From af7ce8ebdd9eb99b191801e700dfdef6caf7923e Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Fri, 20 Mar 2026 13:10:59 +0530 Subject: [PATCH] fix addDnsRecord and deleteDnsRecord flow for automatic registration and ownership issue for associate/disassociate dnsZoneToNetwork --- .../DisassociateDnsZoneFromNetworkCmd.java | 13 ++-- .../cloudstack/dns/DnsProviderManager.java | 3 +- .../dns/DnsProviderManagerImpl.java | 63 +++++++++++++++++-- .../dns/DnsVmLifecycleListener.java | 16 ++--- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DisassociateDnsZoneFromNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DisassociateDnsZoneFromNetworkCmd.java index 51808323b7c..b0aa0902e9e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DisassociateDnsZoneFromNetworkCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/dns/DisassociateDnsZoneFromNetworkCmd.java @@ -26,7 +26,6 @@ import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.DnsZoneResponse; import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.SuccessResponse; @@ -35,6 +34,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; import com.cloud.user.Account; @APICommand(name = "disassociateDnsZoneFromNetwork", @@ -45,9 +45,6 @@ import com.cloud.user.Account; authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class DisassociateDnsZoneFromNetworkCmd extends BaseCmd { - @Parameter(name = ApiConstants.DNS_ZONE_ID, type = CommandType.UUID, entityType = DnsZoneResponse.class, description = "The ID of the DNS zone") - private Long dnsZoneId; - @ACL(accessType = SecurityChecker.AccessType.OperateEntry) @Parameter(name = ApiConstants.NETWORK_ID, type = CommandType.UUID, entityType = NetworkResponse.class, required = true, description = "The ID of the Network") @@ -70,13 +67,13 @@ public class DisassociateDnsZoneFromNetworkCmd extends BaseCmd { @Override public long getEntityOwnerId() { + Network network = _entityMgr.findById(Network.class, networkId); + if (network != null) { + return network.getAccountId(); + } return Account.ACCOUNT_ID_SYSTEM; } - public Long getDnsZoneId() { - return dnsZoneId; - } - public Long getNetworkId() { return networkId; } diff --git a/api/src/main/java/org/apache/cloudstack/dns/DnsProviderManager.java b/api/src/main/java/org/apache/cloudstack/dns/DnsProviderManager.java index e6ce3a49022..284b91e1346 100644 --- a/api/src/main/java/org/apache/cloudstack/dns/DnsProviderManager.java +++ b/api/src/main/java/org/apache/cloudstack/dns/DnsProviderManager.java @@ -75,7 +75,8 @@ public interface DnsProviderManager extends Manager, PluggableService { boolean disassociateZoneFromNetwork(DisassociateDnsZoneFromNetworkCmd cmd); - String processDnsRecordForInstance(VirtualMachine instance, Network network, Nic nic, boolean isAdd); + void addDnsRecordForVM(VirtualMachine instance, Network network, Nic nic); + void deleteDnsRecordForVM(VirtualMachine instance, Network network, Nic nic); void checkDnsServerPermission(Account caller, DnsServer dnsServer); 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 9b3e31d68d9..8374680aeda 100644 --- a/server/src/main/java/org/apache/cloudstack/dns/DnsProviderManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/dns/DnsProviderManagerImpl.java @@ -59,6 +59,7 @@ import org.apache.cloudstack.dns.vo.DnsServerVO; import org.apache.cloudstack.dns.vo.DnsZoneJoinVO; import org.apache.cloudstack.dns.vo.DnsZoneNetworkMapVO; import org.apache.cloudstack.dns.vo.DnsZoneVO; +import org.apache.logging.log4j.util.Strings; import org.springframework.stereotype.Component; import com.cloud.domain.dao.DomainDao; @@ -81,8 +82,10 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.db.TransactionCallback; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.Nic; +import com.cloud.vm.NicDetailVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicDetailsDao; import com.cloud.vm.dao.UserVmDao; @Component @@ -110,6 +113,8 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa DnsServerJoinDao dnsServerJoinDao; @Inject AccountDao accountDao; + @Inject + NicDetailsDao nicDetailsDao; private DnsProvider getProviderByType(DnsProviderType type) { if (type == null) { @@ -649,23 +654,69 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa } @Override - public String processDnsRecordForInstance(VirtualMachine instance, Network network, Nic nic, boolean isAdd) { - long networkId = network.getId(); - DnsZoneNetworkMapVO dnsZoneNetworkMap = dnsZoneNetworkMapDao.findByNetworkId(networkId); + public void addDnsRecordForVM(VirtualMachine instance, Network network, Nic nic) { + DnsZoneNetworkMapVO dnsZoneNetworkMap = dnsZoneNetworkMapDao.findByNetworkId(network.getId()); if (dnsZoneNetworkMap == null) { logger.warn("No DNS zone is mapped to this network. Please associate a zone first."); - return null; + return; } DnsZoneVO dnsZone = dnsZoneDao.findById(dnsZoneNetworkMap.getDnsZoneId()); if (dnsZone == null || dnsZone.getState() != DnsZone.State.Active) { - return null; + logger.warn("DNS zone is not available for DNS record setup"); + return; } DnsServerVO server = dnsServerDao.findById(dnsZone.getDnsServerId()); + if (server == null) { + logger.warn("DNS server is not found to process DNS record for Instance: {}", instance.getInstanceName()); + return; + } // Construct FQDN Prefix (e.g., "instance-id.dnsZoneName" or "instance-id.subdomain.dnsZoneName") String recordName = String.valueOf(instance.getInstanceName()); if (StringUtils.isNotBlank(dnsZoneNetworkMap.getSubDomain())) { recordName = String.join(".", recordName, dnsZoneNetworkMap.getSubDomain(), dnsZone.getName()); } + String dnsRecordUrl = processDnsRecordInProvider(recordName, instance, server, dnsZone, nic, true); + if (Strings.isBlank(dnsRecordUrl)) { + logger.error("Failed to add DNS record in provider for Instance: {}", instance.getInstanceName()); + return; + } + nicDetailsDao.addDetail(nic.getId(), ApiConstants.NIC_DNS_RECORD, dnsRecordUrl, true); + } + + @Override + public void deleteDnsRecordForVM(VirtualMachine instance, Network network, Nic nic) { + String instanceName = instance.getInstanceName(); + NicDetailVO nicDetailVO = nicDetailsDao.findDetail(nic.getId(), ApiConstants.NIC_DNS_RECORD); + if (nicDetailVO == null || Strings.isBlank(nicDetailVO.getValue())) { + logger.debug("No DNS record found for Instance: {}", instance.getInstanceName()); + return; + } + String dnsRecord = nicDetailVO.getValue(); + try { + DnsZoneNetworkMapVO dnsZoneNetworkMap = dnsZoneNetworkMapDao.findByNetworkId(network.getId()); + DnsZoneVO dnsZone = null; + DnsServerVO dnsServer = null; + if (dnsZoneNetworkMap != null) { + dnsZone = dnsZoneDao.findById(dnsZoneNetworkMap.getDnsZoneId()); + } + if (dnsZone != null) { + dnsServer = dnsServerDao.findById(dnsZone.getDnsServerId()); + } + if (dnsServer != null) { + processDnsRecordInProvider(dnsRecord, instance, dnsServer, dnsZone, nic, false); + } else { + logger.warn("Skipping deletion of DNS record: {} from provider for Instance: {}.", dnsRecord, instanceName); + } + } catch (Exception ex) { + logger.error("Failed deleting DNS record: {} for Instance: {}, proceeding with DB cleanup.", dnsRecord, instanceName); + } finally { + nicDetailsDao.removeDetail(nic.getId(), ApiConstants.NIC_DNS_RECORD); + logger.debug("Removed DNS record from DB for Instance: {}, NIC ID: {}", instanceName, nic.getUuid()); + } + } + + private String processDnsRecordInProvider(String recordName, VirtualMachine instance, DnsServer server, DnsZone dnsZone, + Nic nic, boolean isAdd) { try { DnsProvider provider = getProviderByType(server.getProviderType()); @@ -695,7 +746,7 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa logger.error( "Failed to {} DNS record for Instance {} in zone {}", isAdd ? "register" : "remove", - instance.getHostName(), + instance.getInstanceName(), dnsZone.getName(), ex ); diff --git a/server/src/main/java/org/apache/cloudstack/dns/DnsVmLifecycleListener.java b/server/src/main/java/org/apache/cloudstack/dns/DnsVmLifecycleListener.java index 12044f497cf..a235ce75022 100644 --- a/server/src/main/java/org/apache/cloudstack/dns/DnsVmLifecycleListener.java +++ b/server/src/main/java/org/apache/cloudstack/dns/DnsVmLifecycleListener.java @@ -144,12 +144,12 @@ public class DnsVmLifecycleListener extends ManagerBase implements EventSubscrib } private void handleVmEvent(String vmUuid, boolean isAddDnsRecord) { - VMInstanceVO vmInstanceVO = vmInstanceDao.findByUuid(vmUuid); + VMInstanceVO vmInstanceVO = vmInstanceDao.findByUuidIncludingRemoved(vmUuid); if (vmInstanceVO == null) { logger.error("Unable to find Instance with ID: {}", vmUuid); return; } - List vmNics = nicDao.listByVmId(vmInstanceVO.getId()); + List vmNics = nicDao.listByVmIdIncludingRemoved(vmInstanceVO.getId()); for (NicVO nic : vmNics) { Network network = networkDao.findById(nic.getNetworkId()); if (network == null || !Network.GuestType.Shared.equals(network.getGuestType())) { @@ -160,16 +160,10 @@ public class DnsVmLifecycleListener extends ManagerBase implements EventSubscrib } void processEventForDnsRecord(VMInstanceVO vmInstanceVO, Network network, Nic nic, boolean isAddDnsRecord) { - String dnsRecordUrl = providerManager.processDnsRecordForInstance(vmInstanceVO, network, nic, isAddDnsRecord); - if (dnsRecordUrl != null) { - if (isAddDnsRecord) { - nicDetailsDao.addDetail(nic.getId(), ApiConstants.NIC_DNS_RECORD, dnsRecordUrl, true); - } else { - nicDetailsDao.removeDetail(nic.getId(), ApiConstants.NIC_DNS_RECORD); - } + if (isAddDnsRecord) { + providerManager.addDnsRecordForVM(vmInstanceVO, network, nic); } else { - logger.error("Failure {} DNS record for Instance: {} for Network with ID: {}", - isAddDnsRecord ? "adding" : "removing", vmInstanceVO.getUuid(), network.getUuid()); + providerManager.deleteDnsRecordForVM(vmInstanceVO, network, nic); } }