1717
1818package org .apache .cloudstack .dns ;
1919
20+ import static com .cloud .event .EventTypes .EVENT_DNS_RECORD_CREATE ;
21+ import static com .cloud .event .EventTypes .EVENT_DNS_RECORD_DELETE ;
2022import static com .cloud .event .EventTypes .EVENT_NIC_CREATE ;
2123import static com .cloud .event .EventTypes .EVENT_NIC_DELETE ;
2224
2325import java .util .ArrayList ;
2426import java .util .Collections ;
27+ import java .util .HashMap ;
2528import java .util .List ;
2629import java .util .Map ;
2730import java .util .Objects ;
2831import java .util .Set ;
32+ import java .util .UUID ;
2933import java .util .stream .Collectors ;
3034
3135import javax .inject .Inject ;
6973import org .apache .cloudstack .framework .messagebus .MessageSubscriber ;
7074import org .apache .cloudstack .framework .messagebus .PublishScope ;
7175import org .apache .commons .collections .CollectionUtils ;
76+ import org .apache .commons .lang3 .RandomStringUtils ;
7277import org .apache .logging .log4j .util .Strings ;
7378import org .springframework .stereotype .Component ;
7479
@@ -457,6 +462,7 @@ public DnsRecordResponse createDnsRecord(CreateDnsRecordCmd cmd) {
457462 DnsProvider provider = getProviderByType (server .getProviderType ());
458463 String normalizedRecordName = provider .addRecord (server , dnsZone , record );
459464 record .setName (normalizedRecordName );
465+ publishDnsRecordEventMessageBus (recordName , type , caller .getAccountId (), EVENT_DNS_RECORD_CREATE , normalizedContents );
460466 return createDnsRecordResponse (record );
461467 } catch (Exception ex ) {
462468 logger .error ("Failed to add DNS record via provider" , ex );
@@ -474,15 +480,14 @@ public boolean deleteDnsRecord(DeleteDnsRecordCmd cmd) {
474480 Account caller = CallContext .current ().getCallingAccount ();
475481 accountMgr .checkAccess (caller , null , true , zone );
476482 DnsServerVO server = dnsServerDao .findById (zone .getDnsServerId ());
483+ DnsRecord .RecordType recordType = cmd .getType ();
477484 try {
478485 DnsRecord record = new DnsRecord ();
479486 record .setName (cmd .getName ());
480- record .setType (cmd . getType () );
487+ record .setType (recordType );
481488 DnsProvider provider = getProviderByType (server .getProviderType ());
482489 String deletedDnsRecord = provider .deleteRecord (server , zone , record );
483- if (deletedDnsRecord != null ) {
484- messageBus .publish (_name , DnsProvider .Topics .DNS_RECORD_DELETE , PublishScope .GLOBAL , deletedDnsRecord );
485- }
490+ publishDnsRecordEventMessageBus (deletedDnsRecord , recordType , caller .getAccountId (), EVENT_DNS_RECORD_DELETE , null );
486491 return deletedDnsRecord != null ;
487492 } catch (Exception ex ) {
488493 logger .error ("Failed to delete DNS record via provider" , ex );
@@ -713,11 +718,7 @@ public void addDnsRecordForVM(VirtualMachine instance, Network network, Nic nic)
713718 logger .warn ("DNS server is not found to process DNS record for Instance: {}" , instance .getInstanceName ());
714719 return ;
715720 }
716- // Construct FQDN Prefix (e.g., "instance-id.dnsZoneName" or "instance-id.subdomain.dnsZoneName")
717- String recordName = String .valueOf (instance .getInstanceName ());
718- if (StringUtils .isNotBlank (dnsZoneNetworkMap .getSubDomain ())) {
719- recordName = String .join ("." , recordName , dnsZoneNetworkMap .getSubDomain (), dnsZone .getName ());
720- }
721+ String recordName = finalizeDnsRecordNameForVm (instance , dnsZoneNetworkMap , server , dnsZone );
721722 String dnsRecordUrl = processDnsRecordInProvider (recordName , instance , server , dnsZone , nic , true );
722723 if (Strings .isBlank (dnsRecordUrl )) {
723724 logger .error ("Failed to add DNS record in provider for Instance: {}" , instance .getInstanceName ());
@@ -726,6 +727,31 @@ public void addDnsRecordForVM(VirtualMachine instance, Network network, Nic nic)
726727 nicDetailsDao .addDetail (nic .getId (), ApiConstants .NIC_DNS_RECORD , dnsRecordUrl , true );
727728 }
728729
730+ private String finalizeDnsRecordNameForVm (VirtualMachine instance , DnsZoneNetworkMapVO dnsZoneNetworkMap , DnsServerVO server , DnsZoneVO dnsZone ) {
731+ String recordName ;
732+ // Construct FQDN Prefix (e.g., "hostname.dnsZoneName" or "hostname.subdomain.dnsZoneName")
733+ try {
734+ List <String > parts = new ArrayList <>();
735+ parts .add (instance .getHostName ());
736+ if (StringUtils .isNotBlank (dnsZoneNetworkMap .getSubDomain ())) {
737+ parts .add (dnsZoneNetworkMap .getSubDomain ());
738+ }
739+ parts .add (dnsZone .getName ());
740+ recordName = String .join ("." , parts );
741+
742+ DnsProvider provider = getProviderByType (server .getProviderType ());
743+ boolean dnsRecordExist = provider .dnsRecordExists (server , dnsZone , recordName , DnsRecord .RecordType .A .toString ());
744+ if (dnsRecordExist ) {
745+ String randomPrefix = RandomStringUtils .randomAlphanumeric (3 ).toLowerCase ();
746+ recordName = randomPrefix + "-" + recordName ;
747+ }
748+ } catch (Exception ex ) {
749+ logger .error ("Failed while constructing DNS record name for Instance: {} " , instance .getInstanceName (), ex );
750+ throw new CloudRuntimeException ("Error occurred during DNS record registration for Instance: " + instance .getInstanceName ());
751+ }
752+ return recordName ;
753+ }
754+
729755 @ Override
730756 public void deleteDnsRecordForVM (VirtualMachine instance , Network network , Nic nic ) {
731757 String instanceName = instance .getInstanceName ();
@@ -836,14 +862,7 @@ public boolean start() {
836862 public boolean configure (String name , Map <String , Object > params ) throws ConfigurationException {
837863 messageBus .subscribe (VirtualMachineManager .Topics .VM_LIFECYCLE , new VmLifecycleSubscriber ());
838864 messageBus .subscribe (Nic .Topics .NIC_LIFECYCLE , new NicLifecycleSubscriber ());
839- messageBus .subscribe (DnsProvider .Topics .DNS_RECORD_DELETE , (senderAddress , subject , args ) -> {
840- try {
841- String deletedDnsRecord = (String ) args ;
842- nicDetailsDao .removeDetailsForValuesIn (ApiConstants .NIC_DNS_RECORD , Collections .singletonList (deletedDnsRecord ));
843- } catch (Exception ex ) {
844- logger .error ("Failed to process DNS record deletion event" , ex );
845- }
846- });
865+ messageBus .subscribe (DnsProvider .Topics .DNS_RECORD_LIFECYCLE , new DnsRecordLifecycleSubscriber ());
847866 return true ;
848867 }
849868
@@ -944,6 +963,36 @@ public void onPublishMessage(String senderAddress, String subject, Object args)
944963 }
945964 }
946965
966+ class DnsRecordLifecycleSubscriber implements MessageSubscriber {
967+ @ Override
968+ public void onPublishMessage (String senderAddress , String subject , Object args ) {
969+ try {
970+ logger .trace ("DNS record lifecycle event: {}, {}, {}" , senderAddress , subject , args );
971+
972+ @ SuppressWarnings ("unchecked" )
973+ Map <String , Object > event = (Map <String , Object >) args ;
974+ String eventType = (String ) event .get (ApiConstants .EVENT_TYPE );
975+ String dnsRecord = (String ) event .get (ApiConstants .DNS_RECORD );
976+ if (EVENT_DNS_RECORD_CREATE .equalsIgnoreCase (eventType )) {
977+ @ SuppressWarnings ("unchecked" )
978+ List <String > contents = (List <String >) event .get (ApiConstants .CONTENTS );
979+ if (CollectionUtils .isNotEmpty (contents )) {
980+ for (String ipAddress : contents ) {
981+ Nic nic = nicDao .findByIpAddressAndVmType (ipAddress , VirtualMachine .Type .User );
982+ if (nic != null ) {
983+ nicDetailsDao .addDetail (nic .getId (), ApiConstants .NIC_DNS_RECORD , dnsRecord , true );
984+ }
985+ }
986+ }
987+ } else if (EVENT_DNS_RECORD_DELETE .equalsIgnoreCase (eventType )) {
988+ nicDetailsDao .removeDetailsForValuesIn (ApiConstants .NIC_DNS_RECORD , Collections .singletonList (dnsRecord ));
989+ }
990+ } catch (Exception ex ) {
991+ logger .error ("Failed to process DNS record lifecycle event" , ex );
992+ }
993+ }
994+ }
995+
947996 private void handleNicEvent (long nicId , long instanceId , boolean isAddDnsRecord ) {
948997 VMInstanceVO vmInstanceVO = vmInstanceDao .findById (instanceId );
949998 if (vmInstanceVO == null ) {
@@ -986,4 +1035,25 @@ void processEventForDnsRecord(VMInstanceVO vmInstanceVO, Network network, Nic ni
9861035 deleteDnsRecordForVM (vmInstanceVO , network , nic );
9871036 }
9881037 }
1038+
1039+ void publishDnsRecordEventMessageBus (String dnsRecord , DnsRecord .RecordType recordType , Long accountId ,
1040+ String eventType , List <String > contents ) {
1041+
1042+ // Only publish for A or AAAA records and non-null record name
1043+ if ((recordType != DnsRecord .RecordType .A && recordType != DnsRecord .RecordType .AAAA ) || dnsRecord == null ) {
1044+ return ;
1045+ }
1046+ try {
1047+ Map <String , Object > event = new HashMap <>();
1048+ event .put (ApiConstants .EVENT_ID , UUID .randomUUID ().toString ());
1049+ event .put (ApiConstants .DNS_RECORD , dnsRecord );
1050+ event .put (ApiConstants .ACCOUNT_ID , accountId );
1051+ event .put (ApiConstants .EVENT_TYPE , eventType );
1052+ event .put (ApiConstants .CONTENTS , contents != null ? contents : Collections .emptyList ());
1053+ event .put (ApiConstants .TIME_STAMP , System .currentTimeMillis ());
1054+ messageBus .publish (_name , DnsProvider .Topics .DNS_RECORD_LIFECYCLE , PublishScope .GLOBAL , event );
1055+ } catch (Exception ex ) {
1056+ logger .error ("Failed to publish {} event for DNS record: {}" , eventType , dnsRecord , ex );
1057+ }
1058+ }
9891059}
0 commit comments