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
This commit is contained in:
Wei Zhou 2024-06-12 16:01:23 +02:00 committed by GitHub
parent 5c749eced2
commit b2ef53b8a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 99 additions and 1 deletions

View File

@ -130,7 +130,7 @@ public class ImageStoreDaoImpl extends GenericDaoBase<ImageStoreVO, Long> implem
}
if (scope.getScopeId() != null) {
SearchCriteria<ImageStoreVO> 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);
}

View File

@ -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<MigrateCo
private static final String GRAPHICS_ELEM_END = "/graphics>";
private static final String GRAPHICS_ELEM_START = "<graphics";
private static final String CONTENTS_WILDCARD = "(?s).*";
private static final String CDROM_LABEL = "hdc";
private static final Logger s_logger = Logger.getLogger(LibvirtMigrateCommandWrapper.class);
protected String createMigrationURI(final String destinationIp, final LibvirtComputingResource libvirtComputingResource) {
@ -166,6 +168,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
String vncPassword = org.apache.commons.lang3.StringUtils.truncate(to.getVncPassword(), 8);
xmlDesc = replaceIpForVNCInDescFileAndNormalizePassword(xmlDesc, target, vncPassword, vmName);
// Replace Config Drive ISO path
String oldIsoVolumePath = getOldVolumePath(disks, vmName);
String newIsoVolumePath = getNewVolumePathIfDatastoreHasChanged(libvirtComputingResource, conn, to);
if (newIsoVolumePath != null && !newIsoVolumePath.equals(oldIsoVolumePath)) {
@ -175,6 +178,14 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
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));
}
}
// Replace CDROM ISO path
String oldCdromIsoPath = getOldVolumePathForCdrom(disks, vmName);
String newCdromIsoPath = getNewVolumePathForCdrom(libvirtComputingResource, conn, to);
if (newCdromIsoPath != null && !newCdromIsoPath.equals(oldCdromIsoPath)) {
xmlDesc = replaceCdromIsoPath(xmlDesc, vmName, oldCdromIsoPath, newCdromIsoPath);
}
// delete the metadata of vm snapshots before migration
vmsnapshots = libvirtComputingResource.cleanVMSnapshotMetadata(dm);
@ -702,6 +713,81 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
return newIsoVolumePath;
}
private String getOldVolumePathForCdrom(List<DiskDef> 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<String> paths, String sourceText) {
if (paths != null && StringUtils.isNotBlank(sourceText)) {
for (String path : paths) {

View File

@ -132,6 +132,7 @@ public class LibvirtMigrateCommandWrapperTest {
" </disk>\n" +
" <disk type='file' device='cdrom'>\n" +
" <driver name='qemu' type='raw' cache='none'/>\n" +
" <source file='/mnt/ec8dfdd8-f341-3b0a-988f-cfbc93e46fc4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso'/>\n" +
" <backingStore/>\n" +
" <target dev='hdc' bus='ide'/>\n" +
" <readonly/>\n" +
@ -249,6 +250,7 @@ public class LibvirtMigrateCommandWrapperTest {
" </disk>\n" +
" <disk type='file' device='cdrom'>\n" +
" <driver name='qemu' type='raw' cache='none'/>\n" +
" <source file='/mnt/ec8dfdd8-f341-3b0a-988f-cfbc93e46fc4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso'/>\n" +
" <backingStore/>\n" +
" <target dev='hdc' bus='ide'/>\n" +
" <readonly/>\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));
}
}