From 8f71ce6f409bfbc288b995cc17527e0d39e66769 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Fri, 1 May 2026 17:42:40 +0530 Subject: [PATCH] introduce 'unmanage' param in deleteDnsServerCmd to prevent deletion of zones from dns provider --- .../command/user/dns/CreateDnsZoneCmd.java | 2 +- .../command/user/dns/DeleteDnsServerCmd.java | 12 ++++++- .../command/user/dns/DeleteDnsZoneCmd.java | 6 ++-- .../java/com/cloud/vm/dao/NicDetailsDao.java | 4 +-- .../com/cloud/vm/dao/NicDetailsDaoImpl.java | 23 ++++++------ .../META-INF/db/views/nic_dns_view.sql | 2 +- .../dns/DnsProviderManagerImpl.java | 32 ++++++++--------- .../cloudstack/dns/dao/DnsServerDaoImpl.java | 3 ++ .../cloudstack/dns/dao/NicDnsJoinDao.java | 17 ++++++--- .../cloudstack/dns/dao/NicDnsJoinDaoImpl.java | 28 +++++++++++---- .../dns/DnsProviderManagerImplTest.java | 14 ++++---- ui/src/views/network/dns/DeleteDnsServer.vue | 36 +++++++++++++++++-- 12 files changed, 124 insertions(+), 55 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/dns/CreateDnsZoneCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/dns/CreateDnsZoneCmd.java index 76bd8bdc493..25c4b007cc8 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/dns/CreateDnsZoneCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/dns/CreateDnsZoneCmd.java @@ -68,7 +68,7 @@ public class CreateDnsZoneCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.EXISTING, type = CommandType.BOOLEAN, entityType = DnsZoneResponse.class, description = "If true, imports an existing DNS zone from the DNS provider into CloudStack. " + - "If false, creates the zone in the DNS provider and registers it in CloudStack.") + "If false, creates the zone in the DNS provider and registers it in CloudStack. Default is false") private Boolean existing = false; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsServerCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsServerCmd.java index 5444e769da5..099fc62f354 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsServerCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsServerCmd.java @@ -53,9 +53,15 @@ public class DeleteDnsServerCmd extends BaseAsyncCmd { private Long id; @Parameter(name = ApiConstants.CLEANUP, type = CommandType.BOOLEAN, - entityType = DnsZoneResponse.class, description = "True if all associated DNS zones have to be cleaned up with this server") + entityType = DnsZoneResponse.class, description = "If true, all associated DNS zones will be cleaned up " + + "when the server is removed. Default: true") private Boolean cleanup = true; + @Parameter(name = ApiConstants.UNMANAGE, type = CommandType.BOOLEAN, entityType = DnsZoneResponse.class, + description = "If true, the DNS zone is only removed from CloudStack (unmanaged); if false, it is removed " + + "from both CloudStack and the DNS provider. Default: false") + private Boolean unmanage = false; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -102,4 +108,8 @@ public class DeleteDnsServerCmd extends BaseAsyncCmd { public Boolean getCleanup() { return Boolean.TRUE.equals(cleanup); } + + public Boolean isUnmanage() { + return Boolean.TRUE.equals(unmanage); + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsZoneCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsZoneCmd.java index f5b1f1d2255..dee8bc770a8 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsZoneCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsZoneCmd.java @@ -52,8 +52,8 @@ public class DeleteDnsZoneCmd extends BaseAsyncCmd { private Long id; @Parameter(name = ApiConstants.UNMANAGE, type = CommandType.BOOLEAN, entityType = DnsZoneResponse.class, - description = "If true, removes the DNS zone from CloudStack; if false, " + - "removes it from both CloudStack and the DNS provider.") + description = "If true, imports an existing DNS zone from the DNS provider into CloudStack; " + + "if false, creates the DNS zone in the provider and registers it with CloudStack. Default: false") private Boolean unmanage = false; ///////////////////////////////////////////////////// @@ -79,7 +79,7 @@ public class DeleteDnsZoneCmd extends BaseAsyncCmd { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete DNS Zone"); } } catch (Exception e) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete DNS Zone: " + e.getMessage()); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); } } diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDetailsDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDetailsDao.java index 1d32ea20f1e..403727ed9c6 100644 --- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDetailsDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDetailsDao.java @@ -16,7 +16,7 @@ // under the License. package com.cloud.vm.dao; -import java.util.List; +import java.util.Set; import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; @@ -25,5 +25,5 @@ import com.cloud.vm.NicDetailVO; public interface NicDetailsDao extends GenericDao, ResourceDetailsDao { - void removeDetailsForValuesIn(String resourceName, List values); + void removeDetailsForNicIds(String resourceName, Set nicIds); } diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDetailsDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDetailsDaoImpl.java index 3b391a50350..1011f0588bb 100644 --- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDetailsDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDetailsDaoImpl.java @@ -17,28 +17,27 @@ package com.cloud.vm.dao; -import java.util.List; +import java.util.Set; import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; -import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; - import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.vm.NicDetailVO; @Component public class NicDetailsDaoImpl extends ResourceDetailsDaoBase implements NicDetailsDao { - private final SearchBuilder NameValuesSearch; + private final SearchBuilder ResourceIdNameSearch; public NicDetailsDaoImpl() { super(); - NameValuesSearch = createSearchBuilder(); - NameValuesSearch.and(ApiConstants.NAME, NameValuesSearch.entity().getName(), SearchCriteria.Op.EQ); - NameValuesSearch.and(ApiConstants.VALUE, NameValuesSearch.entity().getValue(), SearchCriteria.Op.IN); - NameValuesSearch.done(); + ResourceIdNameSearch = createSearchBuilder(); + ResourceIdNameSearch.and(ApiConstants.NAME, ResourceIdNameSearch.entity().getName(), SearchCriteria.Op.EQ); + ResourceIdNameSearch.and(ApiConstants.RESOURCE_ID, ResourceIdNameSearch.entity().getResourceId(), SearchCriteria.Op.IN); + ResourceIdNameSearch.done(); } @@ -48,13 +47,13 @@ public class NicDetailsDaoImpl extends ResourceDetailsDaoBase imple } @Override - public void removeDetailsForValuesIn(String resourceName, List values) { - if (CollectionUtils.isEmpty(values)) { + public void removeDetailsForNicIds(String resourceName, Set nicIds) { + if (CollectionUtils.isEmpty(nicIds)) { return; } - SearchCriteria sc = NameValuesSearch.create(); + SearchCriteria sc = ResourceIdNameSearch.create(); sc.setParameters(ApiConstants.NAME, resourceName); - sc.setParameters(ApiConstants.VALUE, values.toArray()); + sc.setParameters(ApiConstants.RESOURCE_ID, nicIds.toArray()); remove(sc); } } diff --git a/engine/schema/src/main/resources/META-INF/db/views/nic_dns_view.sql b/engine/schema/src/main/resources/META-INF/db/views/nic_dns_view.sql index 3ae24098871..8c7737db088 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/nic_dns_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/nic_dns_view.sql @@ -37,4 +37,4 @@ FROM LEFT JOIN `cloud`.`nic_details` nd ON n.id = nd.nic_id AND nd.name = 'nicdnsname' WHERE - map.removed IS NULL; + n.instance_id IS NOT NULL AND map.removed IS NULL; diff --git a/server/src/main/java/org/apache/cloudstack/dns/DnsProviderManagerImpl.java b/server/src/main/java/org/apache/cloudstack/dns/DnsProviderManagerImpl.java index 93a3d93f87f..27c971e7e44 100644 --- a/server/src/main/java/org/apache/cloudstack/dns/DnsProviderManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/dns/DnsProviderManagerImpl.java @@ -28,7 +28,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -316,7 +315,7 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa List dnsZones = dnsZoneDao.findDnsZonesByServerId(dnsServerId); for (DnsZoneVO dnsZone : dnsZones) { try { - deleteDnsZone(dnsZone.getId(), false); + deleteDnsZone(dnsZone.getId(), cmd.isUnmanage()); } catch (Exception ex) { logger.error("Error cleaning up DNS zone: {} during DNS server: {} deletion", dnsZone.getName(), dnsServer.getName()); } @@ -328,7 +327,7 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa @Override @ActionEvent(eventType = EventTypes.EVENT_DNS_ZONE_DELETE, eventDescription = "Deleting DNS Zone") - public boolean deleteDnsZone(Long zoneId, boolean isUnmanage) { + public boolean deleteDnsZone(Long zoneId, boolean retainInProvider) { DnsZoneVO dnsZone = dnsZoneDao.findById(zoneId); if (dnsZone == null) { throw new InvalidParameterValueException("DNS zone not found for the given ID."); @@ -336,23 +335,16 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa String dnsZoneName = dnsZone.getName(); Account caller = CallContext.current().getCallingAccount(); accountMgr.checkAccess(caller, null, true, dnsZone); - DnsServerVO server = dnsServerDao.findById(dnsZone.getDnsServerId()); - if (server == null) { - throw new CloudRuntimeException(String.format("The DNS server not found for DNS zone: %s", dnsZoneName)); - } boolean dbResult = Transaction.execute((TransactionCallback) status -> { DnsZoneNetworkMapVO networkMapVO = dnsZoneNetworkMapDao.findByZoneId(zoneId); - DnsProvider provider = getProviderByType(server.getProviderType()); // Remove DNS records from nic_details if there are any if (networkMapVO != null) { try { - List records = provider.listRecords(server, dnsZone); - if (CollectionUtils.isNotEmpty(records)) { - List dnsRecordNames = records.stream().map(DnsRecord::getName).filter(Objects::nonNull) - .map(name -> name.replaceAll("\\.+$", "")) - .collect(Collectors.toList()); - nicDetailsDao.removeDetailsForValuesIn(ApiConstants.NIC_DNS_NAME, dnsRecordNames); + List nicDnsJoinVOS = nicDnsJoinDao.listByZoneId(zoneId); + if (CollectionUtils.isNotEmpty(nicDnsJoinVOS)) { + Set nicIds = nicDnsJoinVOS.stream().map(NicDnsJoinVO::getId).collect(Collectors.toSet()); + nicDetailsDao.removeDetailsForNicIds(ApiConstants.NIC_DNS_NAME, nicIds); } } catch (Exception ex) { logger.warn("Failed to fetch DNS records for dnsZone: {}, perform manual cleanup.", dnsZoneName, ex); @@ -361,14 +353,22 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa } // Remove DNS zone from provider and cleanup DB - if (!isUnmanage) { + if (!retainInProvider) { try { + DnsServerVO server = dnsServerDao.findById(dnsZone.getDnsServerId()); + if (server == null) { + throw new CloudRuntimeException(String.format("The DNS server not found for DNS zone: %s", dnsZoneName)); + } + DnsProvider provider = getProviderByType(server.getProviderType()); provider.deleteZone(server, dnsZone); logger.debug("Deleted DNS zone: {} from provider", dnsZoneName); } catch (DnsNotFoundException ex) { logger.warn("DNS zone: {} is not present in the provider, proceeding with cleanup", dnsZoneName); } catch (Exception ex) { logger.error("Failed to delete DNS zone from provider", ex); + if (ex instanceof CloudRuntimeException) { + throw new CloudRuntimeException(ex.getMessage()); + } throw new CloudRuntimeException(String.format("Failed to delete DNS zone: %s.", dnsZoneName)); } } @@ -1151,7 +1151,7 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa } private boolean isDnsCollision(String dnsRecordUrl, long targetZoneId, long instanceId) { - NicDnsJoinVO existing = nicDnsJoinDao.findActiveByDnsRecordAndZone(dnsRecordUrl, targetZoneId); + NicDnsJoinVO existing = nicDnsJoinDao.findActiveByDnsRecordAndZone(targetZoneId, dnsRecordUrl); if (existing != null && existing.getInstanceId() != instanceId) { logger.error("DNS collision: cannot register DNS record: {}. Already owned by Instance: {}.", dnsRecordUrl, existing.getInstanceId()); diff --git a/server/src/main/java/org/apache/cloudstack/dns/dao/DnsServerDaoImpl.java b/server/src/main/java/org/apache/cloudstack/dns/dao/DnsServerDaoImpl.java index 2447a30d2b5..e21602356ee 100644 --- a/server/src/main/java/org/apache/cloudstack/dns/dao/DnsServerDaoImpl.java +++ b/server/src/main/java/org/apache/cloudstack/dns/dao/DnsServerDaoImpl.java @@ -173,6 +173,9 @@ public class DnsServerDaoImpl extends GenericDaoBase implemen @Override public void loadDetails(DnsServer dnsServer) { + if (dnsServer == null) { + return; + } Map details = dnsServerDetailsDao.listDetailsKeyPairs(dnsServer.getId()); dnsServer.setDetails(details); } diff --git a/server/src/main/java/org/apache/cloudstack/dns/dao/NicDnsJoinDao.java b/server/src/main/java/org/apache/cloudstack/dns/dao/NicDnsJoinDao.java index 71b1487fba6..682f1811812 100644 --- a/server/src/main/java/org/apache/cloudstack/dns/dao/NicDnsJoinDao.java +++ b/server/src/main/java/org/apache/cloudstack/dns/dao/NicDnsJoinDao.java @@ -27,20 +27,22 @@ public interface NicDnsJoinDao extends GenericDao { /** * Used for Collision Checks. - * @param dnsRecordUrl + * * @param dnsZoneId + * @param nicDnsName * @return active records to see who currently owns the dnsRecordUrl. */ - NicDnsJoinVO findActiveByDnsRecordAndZone(String dnsRecordUrl, long dnsZoneId); + NicDnsJoinVO findActiveByDnsRecordAndZone(long dnsZoneId, String nicDnsName); /** * Used to sync DNS record url based on available ips for vmId in the dnsZone + * * @param vmId * @param dnsZoneId - * @param dnsRecordUrl + * @param nicDnsName * @return list of active nics using the dnsRecordUrl, supports null vmId for dnsZone wide query */ - List listActiveByVmIdZoneAndDnsRecord(Long vmId, long dnsZoneId, String dnsRecordUrl); + List listActiveByVmIdZoneAndDnsRecord(Long vmId, long dnsZoneId, String nicDnsName); /** * Used for VM Start/Running @@ -55,4 +57,11 @@ public interface NicDnsJoinDao extends GenericDao { * @return records with soft-delete */ List listIncludingRemovedByVmId(long vmId); + + /** + * Find all records for dnsZoneId with valid nicDnsName + * @param dnsZoneId + * @return + */ + List listByZoneId(long dnsZoneId); } diff --git a/server/src/main/java/org/apache/cloudstack/dns/dao/NicDnsJoinDaoImpl.java b/server/src/main/java/org/apache/cloudstack/dns/dao/NicDnsJoinDaoImpl.java index 60bffd25fc4..9e7652ef0d4 100644 --- a/server/src/main/java/org/apache/cloudstack/dns/dao/NicDnsJoinDaoImpl.java +++ b/server/src/main/java/org/apache/cloudstack/dns/dao/NicDnsJoinDaoImpl.java @@ -30,6 +30,7 @@ public class NicDnsJoinDaoImpl extends GenericDaoBase implem private final SearchBuilder activeDnsRecordZoneSearch; private final SearchBuilder activeVmZoneDnsRecordSearch; // Route for null vmId private final SearchBuilder activeVmSearch; + private final SearchBuilder activeDnsRecordsByZoneIdSearch; public NicDnsJoinDaoImpl() { @@ -49,28 +50,36 @@ public class NicDnsJoinDaoImpl extends GenericDaoBase implem activeVmSearch = createSearchBuilder(); activeVmSearch.and(ApiConstants.INSTANCE_ID, activeVmSearch.entity().getInstanceId(), SearchCriteria.Op.EQ); activeVmSearch.done(); + + activeDnsRecordsByZoneIdSearch = createSearchBuilder(); + activeDnsRecordsByZoneIdSearch.selectFields(activeDnsRecordsByZoneIdSearch.entity().getId()); + activeDnsRecordsByZoneIdSearch.and(ApiConstants.DNS_ZONE_ID, activeDnsRecordsByZoneIdSearch.entity().getDnsZoneId(), SearchCriteria.Op.EQ); + activeDnsRecordsByZoneIdSearch.and(ApiConstants.NIC_DNS_NAME, activeDnsRecordsByZoneIdSearch.entity().getNicDnsName(), SearchCriteria.Op.NNULL); + activeDnsRecordsByZoneIdSearch.and(ApiConstants.REMOVED, activeDnsRecordsByZoneIdSearch.entity().getRemoved(), SearchCriteria.Op.NULL); + activeDnsRecordsByZoneIdSearch.done(); + } @Override - public NicDnsJoinVO findActiveByDnsRecordAndZone(String dnsRecordUrl, long dnsZoneId) { + public NicDnsJoinVO findActiveByDnsRecordAndZone(long dnsZoneId, String nicDnsName) { SearchCriteria sc = activeDnsRecordZoneSearch.create(); - sc.setParameters(ApiConstants.NIC_DNS_NAME, dnsRecordUrl); + sc.setParameters(ApiConstants.NIC_DNS_NAME, nicDnsName); sc.setParameters(ApiConstants.DNS_ZONE_ID, dnsZoneId); return findOneBy(sc); } @Override - public List listActiveByVmIdZoneAndDnsRecord(Long vmId, long dnsZoneId, String dnsRecordUrl) { + public List listActiveByVmIdZoneAndDnsRecord(Long vmId, long dnsZoneId, String nicDnsName) { if (vmId != null) { - SearchCriteria sc = activeDnsRecordZoneSearch.create(); + SearchCriteria sc = activeVmZoneDnsRecordSearch.create(); sc.setParameters(ApiConstants.INSTANCE_ID, vmId); sc.setParameters(ApiConstants.DNS_ZONE_ID, dnsZoneId); - sc.setParameters(ApiConstants.NIC_DNS_NAME, dnsRecordUrl); + sc.setParameters(ApiConstants.NIC_DNS_NAME, nicDnsName); return listBy(sc); } else { SearchCriteria sc = activeDnsRecordZoneSearch.create(); - sc.setParameters(ApiConstants.NIC_DNS_NAME, dnsRecordUrl); sc.setParameters(ApiConstants.DNS_ZONE_ID, dnsZoneId); + sc.setParameters(ApiConstants.NIC_DNS_NAME, nicDnsName); return listBy(sc); } } @@ -88,4 +97,11 @@ public class NicDnsJoinDaoImpl extends GenericDaoBase implem sc.setParameters(ApiConstants.INSTANCE_ID, vmId); return listIncludingRemovedBy(sc); } + + @Override + public List listByZoneId(long dnsZoneId) { + SearchCriteria sc = activeDnsRecordsByZoneIdSearch.create(); + sc.setParameters(ApiConstants.DNS_ZONE_ID, dnsZoneId); + return listBy(sc); + } } diff --git a/server/src/test/java/org/apache/cloudstack/dns/DnsProviderManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/dns/DnsProviderManagerImplTest.java index 3d7a0778d5b..e508d55ace4 100644 --- a/server/src/test/java/org/apache/cloudstack/dns/DnsProviderManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/dns/DnsProviderManagerImplTest.java @@ -1194,7 +1194,7 @@ public class DnsProviderManagerImplTest { NicDnsJoinVO existing = mock(NicDnsJoinVO.class); when(existing.getInstanceId()).thenReturn(99L); - when(nicDnsJoinDao.findActiveByDnsRecordAndZone("vm.example.com", ZONE_ID)).thenReturn(existing); + when(nicDnsJoinDao.findActiveByDnsRecordAndZone(ZONE_ID, "vm.example.com")).thenReturn(existing); try (MockedStatic aeMock = Mockito.mockStatic(com.cloud.event.ActionEventUtils.class)) { @@ -1209,7 +1209,7 @@ public class DnsProviderManagerImplTest { @Test public void testIsDnsCollisionReturnsFalseWhenNoExistingRecord() { - when(nicDnsJoinDao.findActiveByDnsRecordAndZone("vm.example.com", ZONE_ID)).thenReturn(null); + when(nicDnsJoinDao.findActiveByDnsRecordAndZone(ZONE_ID, "vm.example.com")).thenReturn(null); boolean result = (boolean) ReflectionTestUtils.invokeMethod( manager, "isDnsCollision", "vm.example.com", ZONE_ID, 42L); assertFalse(result); @@ -1220,7 +1220,7 @@ public class DnsProviderManagerImplTest { NicDnsJoinVO existing = mock(NicDnsJoinVO.class); when(existing.getInstanceId()).thenReturn(42L); - when(nicDnsJoinDao.findActiveByDnsRecordAndZone("vm.example.com", ZONE_ID)).thenReturn(existing); + when(nicDnsJoinDao.findActiveByDnsRecordAndZone(ZONE_ID, "vm.example.com")).thenReturn(existing); boolean result = (boolean) ReflectionTestUtils.invokeMethod( manager, "isDnsCollision", "vm.example.com", ZONE_ID, 42L); assertFalse(result); @@ -1325,7 +1325,7 @@ public class DnsProviderManagerImplTest { when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO); // no collision - when(nicDnsJoinDao.findActiveByDnsRecordAndZone(anyString(), eq(ZONE_ID))).thenReturn(null); + when(nicDnsJoinDao.findActiveByDnsRecordAndZone(eq(ZONE_ID), anyString())).thenReturn(null); // sync: no IPs → delete both when(nicDnsJoinDao.listActiveByVmIdZoneAndDnsRecord(eq(51L), eq(ZONE_ID), anyString())) .thenReturn(Collections.emptyList()); @@ -1367,7 +1367,7 @@ public class DnsProviderManagerImplTest { NicDnsJoinVO colliding = mock(NicDnsJoinVO.class); when(colliding.getInstanceId()).thenReturn(999L); - when(nicDnsJoinDao.findActiveByDnsRecordAndZone(anyString(), eq(ZONE_ID))).thenReturn(colliding); + when(nicDnsJoinDao.findActiveByDnsRecordAndZone(eq(ZONE_ID), anyString())).thenReturn(colliding); try (MockedStatic txMock = Mockito.mockStatic(com.cloud.utils.db.Transaction.class); @@ -1438,7 +1438,7 @@ public class DnsProviderManagerImplTest { when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO); // no collision for new record - when(nicDnsJoinDao.findActiveByDnsRecordAndZone(anyString(), eq(ZONE_ID))).thenReturn(null); + when(nicDnsJoinDao.findActiveByDnsRecordAndZone(eq(ZONE_ID), anyString())).thenReturn(null); // sync always returns empty → deleteRecord called when(nicDnsJoinDao.listActiveByVmIdZoneAndDnsRecord(eq(62L), eq(ZONE_ID), anyString())) .thenReturn(Collections.emptyList()); @@ -1486,7 +1486,7 @@ public class DnsProviderManagerImplTest { NicDnsJoinVO colliding = mock(NicDnsJoinVO.class); when(colliding.getInstanceId()).thenReturn(999L); - when(nicDnsJoinDao.findActiveByDnsRecordAndZone(anyString(), eq(ZONE_ID))).thenReturn(colliding); + when(nicDnsJoinDao.findActiveByDnsRecordAndZone(eq(ZONE_ID), anyString())).thenReturn(colliding); when(nicDnsJoinDao.listActiveByVmIdZoneAndDnsRecord(eq(63L), eq(ZONE_ID), anyString())) .thenReturn(Collections.emptyList()); diff --git a/ui/src/views/network/dns/DeleteDnsServer.vue b/ui/src/views/network/dns/DeleteDnsServer.vue index 3f42c784b7f..460aa7b603b 100644 --- a/ui/src/views/network/dns/DeleteDnsServer.vue +++ b/ui/src/views/network/dns/DeleteDnsServer.vue @@ -59,6 +59,20 @@ v-focus="true" /> + + + + + + + + + +
{{ $t('label.cancel') }} @@ -79,9 +93,13 @@