6868import com .cloud .agent .api .MigrateAnswer ;
6969import com .cloud .agent .api .MigrateCommand ;
7070import com .cloud .agent .api .MigrateCommand .MigrateDiskInfo ;
71+ import com .cloud .agent .api .to .DataTO ;
7172import com .cloud .agent .api .to .DiskTO ;
7273import com .cloud .agent .api .to .DpdkTO ;
7374import com .cloud .agent .api .to .VirtualMachineTO ;
@@ -91,6 +92,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
9192 private static final String GRAPHICS_ELEM_END = "/graphics>" ;
9293 private static final String GRAPHICS_ELEM_START = "<graphics" ;
9394 private static final String CONTENTS_WILDCARD = "(?s).*" ;
95+ private static final String CDROM_LABEL = "hdc" ;
9496 private static final Logger s_logger = Logger .getLogger (LibvirtMigrateCommandWrapper .class );
9597
9698 protected String createMigrationURI (final String destinationIp , final LibvirtComputingResource libvirtComputingResource ) {
@@ -166,6 +168,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
166168 String vncPassword = org .apache .commons .lang3 .StringUtils .truncate (to .getVncPassword (), 8 );
167169 xmlDesc = replaceIpForVNCInDescFileAndNormalizePassword (xmlDesc , target , vncPassword , vmName );
168170
171+ // Replace Config Drive ISO path
169172 String oldIsoVolumePath = getOldVolumePath (disks , vmName );
170173 String newIsoVolumePath = getNewVolumePathIfDatastoreHasChanged (libvirtComputingResource , conn , to );
171174 if (newIsoVolumePath != null && !newIsoVolumePath .equals (oldIsoVolumePath )) {
@@ -175,6 +178,14 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
175178 s_logger .debug (String .format ("Replaced disk mount point [%s] with [%s] in VM [%s] XML configuration. New XML configuration is [%s]." , oldIsoVolumePath , newIsoVolumePath , vmName , xmlDesc ));
176179 }
177180 }
181+
182+ // Replace CDROM ISO path
183+ String oldCdromIsoPath = getOldVolumePathForCdrom (disks , vmName );
184+ String newCdromIsoPath = getNewVolumePathForCdrom (libvirtComputingResource , conn , to );
185+ if (newCdromIsoPath != null && !newCdromIsoPath .equals (oldCdromIsoPath )) {
186+ xmlDesc = replaceCdromIsoPath (xmlDesc , vmName , oldCdromIsoPath , newCdromIsoPath );
187+ }
188+
178189 // delete the metadata of vm snapshots before migration
179190 vmsnapshots = libvirtComputingResource .cleanVMSnapshotMetadata (dm );
180191
@@ -702,6 +713,81 @@ private String getNewVolumePathIfDatastoreHasChanged(LibvirtComputingResource li
702713 return newIsoVolumePath ;
703714 }
704715
716+ private String getOldVolumePathForCdrom (List <DiskDef > disks , String vmName ) {
717+ String oldIsoVolumePath = null ;
718+ for (DiskDef disk : disks ) {
719+ if (DiskDef .DeviceType .CDROM .equals (disk .getDeviceType ())
720+ && CDROM_LABEL .equals (disk .getDiskLabel ())
721+ && disk .getDiskPath () != null ) {
722+ oldIsoVolumePath = disk .getDiskPath ();
723+ break ;
724+ }
725+ }
726+ return oldIsoVolumePath ;
727+ }
728+
729+ private String getNewVolumePathForCdrom (LibvirtComputingResource libvirtComputingResource , Connect conn , VirtualMachineTO to ) throws LibvirtException , URISyntaxException {
730+ DiskTO newDisk = null ;
731+ for (DiskTO disk : to .getDisks ()) {
732+ DataTO data = disk .getData ();
733+ if (disk .getDiskSeq () == 3 && data != null && data .getPath () != null ) {
734+ newDisk = disk ;
735+ break ;
736+ }
737+ }
738+
739+ String newIsoVolumePath = null ;
740+ if (newDisk != null ) {
741+ newIsoVolumePath = libvirtComputingResource .getVolumePath (conn , newDisk );
742+ }
743+ return newIsoVolumePath ;
744+ }
745+
746+ protected String replaceCdromIsoPath (String xmlDesc , String vmName , String oldIsoVolumePath , String newIsoVolumePath ) throws IOException , ParserConfigurationException , TransformerException , SAXException {
747+ InputStream in = IOUtils .toInputStream (xmlDesc );
748+
749+ DocumentBuilderFactory docFactory = ParserUtils .getSaferDocumentBuilderFactory ();
750+ DocumentBuilder docBuilder = docFactory .newDocumentBuilder ();
751+ Document doc = docBuilder .parse (in );
752+
753+ // Get the root element
754+ Node domainNode = doc .getFirstChild ();
755+
756+ NodeList domainChildNodes = domainNode .getChildNodes ();
757+
758+ for (int i = 0 ; i < domainChildNodes .getLength (); i ++) {
759+ Node domainChildNode = domainChildNodes .item (i );
760+ if ("devices" .equals (domainChildNode .getNodeName ())) {
761+ NodeList devicesChildNodes = domainChildNode .getChildNodes ();
762+ for (int x = 0 ; x < devicesChildNodes .getLength (); x ++) {
763+ Node deviceChildNode = devicesChildNodes .item (x );
764+ if ("disk" .equals (deviceChildNode .getNodeName ())) {
765+ Node diskNode = deviceChildNode ;
766+ NodeList diskChildNodes = diskNode .getChildNodes ();
767+ for (int z = 0 ; z < diskChildNodes .getLength (); z ++) {
768+ Node diskChildNode = diskChildNodes .item (z );
769+ if ("source" .equals (diskChildNode .getNodeName ())) {
770+ NamedNodeMap sourceNodeAttributes = diskChildNode .getAttributes ();
771+ Node sourceNodeAttribute = sourceNodeAttributes .getNamedItem ("file" );
772+ if (oldIsoVolumePath != null && sourceNodeAttribute != null
773+ && oldIsoVolumePath .equals (sourceNodeAttribute .getNodeValue ())) {
774+ diskNode .removeChild (diskChildNode );
775+ Element newChildSourceNode = doc .createElement ("source" );
776+ newChildSourceNode .setAttribute ("file" , newIsoVolumePath );
777+ diskNode .appendChild (newChildSourceNode );
778+ s_logger .debug (String .format ("Replaced ISO path [%s] with [%s] in VM [%s] XML configuration." , oldIsoVolumePath , newIsoVolumePath , vmName ));
779+ return getXml (doc );
780+ }
781+ }
782+ }
783+ }
784+ }
785+ }
786+ }
787+
788+ return getXml (doc );
789+ }
790+
705791 private String getPathFromSourceText (Set <String > paths , String sourceText ) {
706792 if (paths != null && StringUtils .isNotBlank (sourceText )) {
707793 for (String path : paths ) {
0 commit comments