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