Skip to content

Commit e884571

Browse files
weizhouapachedhslove
authored andcommitted
kvm: replace ISO path in vm XML configuration during vm migration (apache#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
1 parent e95ce54 commit e884571

3 files changed

Lines changed: 99 additions & 1 deletion

File tree

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public List<ImageStoreVO> findByZone(ZoneScope scope, Boolean readonly) {
130130
}
131131
if (scope.getScopeId() != null) {
132132
SearchCriteria<ImageStoreVO> scc = createSearchCriteria();
133-
scc.addOr("scope", SearchCriteria.Op.EQ, ScopeType.REGION);
133+
scc.addOr("scope", SearchCriteria.Op.EQ, ScopeType.ZONE);
134134
scc.addOr("dcId", SearchCriteria.Op.EQ, scope.getScopeId());
135135
sc.addAnd("scope", SearchCriteria.Op.SC, scc);
136136
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import com.cloud.agent.api.MigrateAnswer;
6868
import com.cloud.agent.api.MigrateCommand;
6969
import com.cloud.agent.api.MigrateCommand.MigrateDiskInfo;
70+
import com.cloud.agent.api.to.DataTO;
7071
import com.cloud.agent.api.to.DiskTO;
7172
import com.cloud.agent.api.to.DpdkTO;
7273
import 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) {

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ public class LibvirtMigrateCommandWrapperTest {
132132
" </disk>\n" +
133133
" <disk type='file' device='cdrom'>\n" +
134134
" <driver name='qemu' type='raw' cache='none'/>\n" +
135+
" <source file='/mnt/ec8dfdd8-f341-3b0a-988f-cfbc93e46fc4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso'/>\n" +
135136
" <backingStore/>\n" +
136137
" <target dev='hdc' bus='ide'/>\n" +
137138
" <readonly/>\n" +
@@ -249,6 +250,7 @@ public class LibvirtMigrateCommandWrapperTest {
249250
" </disk>\n" +
250251
" <disk type='file' device='cdrom'>\n" +
251252
" <driver name='qemu' type='raw' cache='none'/>\n" +
253+
" <source file='/mnt/ec8dfdd8-f341-3b0a-988f-cfbc93e46fc4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso'/>\n" +
252254
" <backingStore/>\n" +
253255
" <target dev='hdc' bus='ide'/>\n" +
254256
" <readonly/>\n" +
@@ -1007,4 +1009,14 @@ public void getMigrateStorageDeviceLabelsTestFindPathAndLabels() {
10071009
assertTrue(result.containsAll(Arrays.asList("vda", "vdb")));
10081010
}
10091011

1012+
@Test
1013+
public void replaceCdromIsoPathTest() throws ParserConfigurationException, IOException, TransformerException,
1014+
SAXException {
1015+
String oldIsoVolumePath = "/mnt/ec8dfdd8-f341-3b0a-988f-cfbc93e46fc4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso";
1016+
String newIsoVolumePath = "/mnt/50bf9d15-1b0f-3cc1-9e8a-55df3e17e0c4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso";
1017+
1018+
String finalXml = libvirtMigrateCmdWrapper.replaceCdromIsoPath(fullfile, null, oldIsoVolumePath, newIsoVolumePath);
1019+
1020+
Assert.assertTrue(finalXml.contains(newIsoVolumePath));
1021+
}
10101022
}

0 commit comments

Comments
 (0)