From b2ef53b8a2d95c0ab59abd7e8e2ec5b7343a8615 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 12 Jun 2024 16:01:23 +0200 Subject: [PATCH] kvm: replace ISO path in vm XML configuration during vm migration (#9212) * kvm: replace ISO path in vm XML configuration during vm migration * Update 9212: address comments * kvm: fix vm migration if there are multiple image stores --- .../datastore/db/ImageStoreDaoImpl.java | 2 +- .../wrapper/LibvirtMigrateCommandWrapper.java | 86 +++++++++++++++++++ .../LibvirtMigrateCommandWrapperTest.java | 12 +++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java index 84b88c215ca..21c5dc76d96 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java @@ -130,7 +130,7 @@ public class ImageStoreDaoImpl extends GenericDaoBase implem } if (scope.getScopeId() != null) { SearchCriteria scc = createSearchCriteria(); - scc.addOr("scope", SearchCriteria.Op.EQ, ScopeType.REGION); + scc.addOr("scope", SearchCriteria.Op.EQ, ScopeType.ZONE); scc.addOr("dcId", SearchCriteria.Op.EQ, scope.getScopeId()); sc.addAnd("scope", SearchCriteria.Op.SC, scc); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java index aebbaa4119d..5ba174acd39 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java @@ -68,6 +68,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.MigrateAnswer; import com.cloud.agent.api.MigrateCommand; import com.cloud.agent.api.MigrateCommand.MigrateDiskInfo; +import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.DpdkTO; import com.cloud.agent.api.to.VirtualMachineTO; @@ -91,6 +92,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper disks, String vmName) { + String oldIsoVolumePath = null; + for (DiskDef disk : disks) { + if (DiskDef.DeviceType.CDROM.equals(disk.getDeviceType()) + && CDROM_LABEL.equals(disk.getDiskLabel()) + && disk.getDiskPath() != null) { + oldIsoVolumePath = disk.getDiskPath(); + break; + } + } + return oldIsoVolumePath; + } + + private String getNewVolumePathForCdrom(LibvirtComputingResource libvirtComputingResource, Connect conn, VirtualMachineTO to) throws LibvirtException, URISyntaxException { + DiskTO newDisk = null; + for (DiskTO disk : to.getDisks()) { + DataTO data = disk.getData(); + if (disk.getDiskSeq() == 3 && data != null && data.getPath() != null) { + newDisk = disk; + break; + } + } + + String newIsoVolumePath = null; + if (newDisk != null) { + newIsoVolumePath = libvirtComputingResource.getVolumePath(conn, newDisk); + } + return newIsoVolumePath; + } + + protected String replaceCdromIsoPath(String xmlDesc, String vmName, String oldIsoVolumePath, String newIsoVolumePath) throws IOException, ParserConfigurationException, TransformerException, SAXException { + InputStream in = IOUtils.toInputStream(xmlDesc); + + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + Document doc = docBuilder.parse(in); + + // Get the root element + Node domainNode = doc.getFirstChild(); + + NodeList domainChildNodes = domainNode.getChildNodes(); + + for (int i = 0; i < domainChildNodes.getLength(); i++) { + Node domainChildNode = domainChildNodes.item(i); + if ("devices".equals(domainChildNode.getNodeName())) { + NodeList devicesChildNodes = domainChildNode.getChildNodes(); + for (int x = 0; x < devicesChildNodes.getLength(); x++) { + Node deviceChildNode = devicesChildNodes.item(x); + if ("disk".equals(deviceChildNode.getNodeName())) { + Node diskNode = deviceChildNode; + NodeList diskChildNodes = diskNode.getChildNodes(); + for (int z = 0; z < diskChildNodes.getLength(); z++) { + Node diskChildNode = diskChildNodes.item(z); + if ("source".equals(diskChildNode.getNodeName())) { + NamedNodeMap sourceNodeAttributes = diskChildNode.getAttributes(); + Node sourceNodeAttribute = sourceNodeAttributes.getNamedItem("file"); + if (oldIsoVolumePath != null && sourceNodeAttribute != null + && oldIsoVolumePath.equals(sourceNodeAttribute.getNodeValue())) { + diskNode.removeChild(diskChildNode); + Element newChildSourceNode = doc.createElement("source"); + newChildSourceNode.setAttribute("file", newIsoVolumePath); + diskNode.appendChild(newChildSourceNode); + s_logger.debug(String.format("Replaced ISO path [%s] with [%s] in VM [%s] XML configuration.", oldIsoVolumePath, newIsoVolumePath, vmName)); + return getXml(doc); + } + } + } + } + } + } + } + + return getXml(doc); + } + private String getPathFromSourceText(Set paths, String sourceText) { if (paths != null && StringUtils.isNotBlank(sourceText)) { for (String path : paths) { diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java index 29a5e1f934b..3c5e54e2ba8 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java @@ -132,6 +132,7 @@ public class LibvirtMigrateCommandWrapperTest { " \n" + " \n" + " \n" + +" \n" + " \n" + " \n" + " \n" + @@ -249,6 +250,7 @@ public class LibvirtMigrateCommandWrapperTest { " \n" + " \n" + " \n" + +" \n" + " \n" + " \n" + " \n" + @@ -1007,4 +1009,14 @@ public class LibvirtMigrateCommandWrapperTest { assertTrue(result.containsAll(Arrays.asList("vda", "vdb"))); } + @Test + public void replaceCdromIsoPathTest() throws ParserConfigurationException, IOException, TransformerException, + SAXException { + String oldIsoVolumePath = "/mnt/ec8dfdd8-f341-3b0a-988f-cfbc93e46fc4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso"; + String newIsoVolumePath = "/mnt/50bf9d15-1b0f-3cc1-9e8a-55df3e17e0c4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso"; + + String finalXml = libvirtMigrateCmdWrapper.replaceCdromIsoPath(fullfile, null, oldIsoVolumePath, newIsoVolumePath); + + Assert.assertTrue(finalXml.contains(newIsoVolumePath)); + } }