Skip to content

Commit 47a6a81

Browse files
authored
Merge branch '4.20' into delete-storage-pool-fix
2 parents 0a1a90c + 8db7cab commit 47a6a81

File tree

21 files changed

+362
-79
lines changed

21 files changed

+362
-79
lines changed

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,7 @@ public class ApiConstants {
10971097
public static final String DOCKER_REGISTRY_EMAIL = "dockerregistryemail";
10981098
public static final String ISO_NAME = "isoname";
10991099
public static final String ISO_STATE = "isostate";
1100+
public static final String ISO_URL = "isourl";
11001101
public static final String SEMANTIC_VERSION = "semanticversion";
11011102
public static final String KUBERNETES_VERSION_ID = "kubernetesversionid";
11021103
public static final String KUBERNETES_VERSION_NAME = "kubernetesversionname";

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

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
158158
final String target = command.getDestinationIp();
159159
xmlDesc = dm.getXMLDesc(xmlFlag);
160160
if (logger.isDebugEnabled()) {
161-
logger.debug(String.format("VM [%s] with XML configuration [%s] will be migrated to host [%s].", vmName, xmlDesc, target));
161+
logger.debug("VM {} with XML configuration {} will be migrated to host {}.", vmName, maskSensitiveInfoInXML(xmlDesc), target);
162162
}
163163

164164
// Limit the VNC password in case the length is greater than 8 characters
@@ -173,7 +173,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
173173
logger.debug(String.format("Editing mount path of ISO from %s to %s", oldIsoVolumePath, newIsoVolumePath));
174174
xmlDesc = replaceDiskSourceFile(xmlDesc, newIsoVolumePath, vmName);
175175
if (logger.isDebugEnabled()) {
176-
logger.debug(String.format("Replaced disk mount point [%s] with [%s] in Instance [%s] XML configuration. New XML configuration is [%s].", oldIsoVolumePath, newIsoVolumePath, vmName, xmlDesc));
176+
logger.debug("Replaced disk mount point {} with {} in Instance {} XML configuration. New XML configuration is {}.", oldIsoVolumePath, newIsoVolumePath, vmName, maskSensitiveInfoInXML(xmlDesc));
177177
}
178178
}
179179

@@ -204,23 +204,23 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
204204

205205
if (migrateStorage) {
206206
if (logger.isDebugEnabled()) {
207-
logger.debug(String.format("Changing VM [%s] volumes during migration to host: [%s].", vmName, target));
207+
logger.debug("Changing VM {} volumes during migration to host: {}.", vmName, target);
208208
}
209209
xmlDesc = replaceStorage(xmlDesc, mapMigrateStorage, migrateStorageManaged);
210210
if (logger.isDebugEnabled()) {
211-
logger.debug(String.format("Changed VM [%s] XML configuration of used storage. New XML configuration is [%s].", vmName, xmlDesc));
211+
logger.debug("Changed VM {} XML configuration of used storage. New XML configuration is {}.", vmName, maskSensitiveInfoInXML(xmlDesc));
212212
}
213213
migrateDiskLabels = getMigrateStorageDeviceLabels(disks, mapMigrateStorage);
214214
}
215215

216216
Map<String, DpdkTO> dpdkPortsMapping = command.getDpdkInterfaceMapping();
217217
if (MapUtils.isNotEmpty(dpdkPortsMapping)) {
218218
if (logger.isTraceEnabled()) {
219-
logger.trace(String.format("Changing VM [%s] DPDK interfaces during migration to host: [%s].", vmName, target));
219+
logger.trace("Changing VM {} DPDK interfaces during migration to host: {}.", vmName, target);
220220
}
221221
xmlDesc = replaceDpdkInterfaces(xmlDesc, dpdkPortsMapping);
222222
if (logger.isDebugEnabled()) {
223-
logger.debug(String.format("Changed VM [%s] XML configuration of DPDK interfaces. New XML configuration is [%s].", vmName, xmlDesc));
223+
logger.debug("Changed VM {} XML configuration of DPDK interfaces. New XML configuration is {}.", vmName, maskSensitiveInfoInXML(xmlDesc));
224224
}
225225
}
226226

@@ -233,7 +233,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
233233
}
234234

235235
//run migration in thread so we can monitor it
236-
logger.info(String.format("Starting live migration of instance [%s] to destination host [%s] having the final XML configuration: [%s].", vmName, dconn.getURI(), xmlDesc));
236+
logger.info("Starting live migration of instance {} to destination host {} having the final XML configuration: {}.", vmName, dconn.getURI(), maskSensitiveInfoInXML(xmlDesc));
237237
final ExecutorService executor = Executors.newFixedThreadPool(1);
238238
boolean migrateNonSharedInc = command.isMigrateNonSharedInc() && !migrateStorageManaged;
239239

@@ -243,20 +243,21 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
243243
final Future<Domain> migrateThread = executor.submit(worker);
244244
executor.shutdown();
245245
long sleeptime = 0;
246+
final int migrateDowntime = libvirtComputingResource.getMigrateDowntime();
247+
boolean isMigrateDowntimeSet = false;
248+
246249
while (!executor.isTerminated()) {
247250
Thread.sleep(100);
248251
sleeptime += 100;
249-
if (sleeptime == 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state
250-
final int migrateDowntime = libvirtComputingResource.getMigrateDowntime();
251-
if (migrateDowntime > 0 ) {
252-
try {
253-
final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime);
254-
if (setDowntime == 0 ) {
255-
logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms");
256-
}
257-
} catch (final LibvirtException e) {
258-
logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
252+
if (!isMigrateDowntimeSet && migrateDowntime > 0 && sleeptime >= 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state
253+
try {
254+
final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime);
255+
if (setDowntime == 0 ) {
256+
isMigrateDowntimeSet = true;
257+
logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms");
259258
}
259+
} catch (final LibvirtException e) {
260+
logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
260261
}
261262
}
262263
if (sleeptime % 1000 == 0) {
@@ -272,7 +273,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
272273
} catch (final LibvirtException e) {
273274
logger.info("Couldn't get VM domain state after " + sleeptime + "ms: " + e.getMessage());
274275
}
275-
if (state != null && state == DomainState.VIR_DOMAIN_RUNNING) {
276+
if (state != null && (state == DomainState.VIR_DOMAIN_RUNNING || state == DomainState.VIR_DOMAIN_PAUSED)) {
276277
try {
277278
DomainJobInfo job = dm.getJobInfo();
278279
logger.info(String.format("Aborting migration of VM [%s] with domain job [%s] due to time out after %d seconds.", vmName, job, migrateWait));
@@ -314,6 +315,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
314315
if (logger.isDebugEnabled()) {
315316
logger.debug(String.format("Cleaning the disks of VM [%s] in the source pool after VM migration finished.", vmName));
316317
}
318+
resumeDomainIfPaused(destDomain, vmName);
317319
deleteOrDisconnectDisksOnSourcePool(libvirtComputingResource, migrateDiskInfoList, disks);
318320
libvirtComputingResource.cleanOldSecretsByDiskDef(conn, disks);
319321
}
@@ -378,6 +380,28 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
378380
return new MigrateAnswer(command, result == null, result, null);
379381
}
380382

383+
private DomainState getDestDomainState(Domain destDomain, String vmName) {
384+
DomainState dmState = null;
385+
try {
386+
dmState = destDomain.getInfo().state;
387+
} catch (final LibvirtException e) {
388+
logger.info("Failed to get domain state for VM: " + vmName + " due to: " + e.getMessage());
389+
}
390+
return dmState;
391+
}
392+
393+
private void resumeDomainIfPaused(Domain destDomain, String vmName) {
394+
DomainState dmState = getDestDomainState(destDomain, vmName);
395+
if (dmState == DomainState.VIR_DOMAIN_PAUSED) {
396+
logger.info("Resuming VM " + vmName + " on destination after migration");
397+
try {
398+
destDomain.resume();
399+
} catch (final Exception e) {
400+
logger.error("Failed to resume vm " + vmName + " on destination after migration due to : " + e.getMessage());
401+
}
402+
}
403+
}
404+
381405
/**
382406
* Gets the disk labels (vda, vdb...) of the disks mapped for migration on mapMigrateStorage.
383407
* @param diskDefinitions list of all the disksDefinitions of the VM.
@@ -575,9 +599,7 @@ String replaceIpForVNCInDescFileAndNormalizePassword(String xmlDesc, final Strin
575599
graphElem = graphElem.replaceAll("passwd='([^\\s]+)'", "passwd='" + vncPassword + "'");
576600
}
577601
xmlDesc = xmlDesc.replaceAll(GRAPHICS_ELEM_START + CONTENTS_WILDCARD + GRAPHICS_ELEM_END, graphElem);
578-
if (logger.isDebugEnabled()) {
579-
logger.debug(String.format("Replaced the VNC IP address [%s] with [%s] in VM [%s].", originalGraphElem, graphElem, vmName));
580-
}
602+
logger.debug("Replaced the VNC IP address {} with {} in VM {}.", maskSensitiveInfoInXML(originalGraphElem), maskSensitiveInfoInXML(graphElem), vmName);
581603
}
582604
}
583605
return xmlDesc;
@@ -910,4 +932,10 @@ private boolean findSourceNode(Document doc, Node diskNode, String vmName, Strin
910932
}
911933
return false;
912934
}
935+
936+
public static String maskSensitiveInfoInXML(String xmlDesc) {
937+
if (xmlDesc == null) return null;
938+
return xmlDesc.replaceAll("(graphics\\s+[^>]*type=['\"]vnc['\"][^>]*passwd=['\"])([^'\"]*)(['\"])",
939+
"$1*****$3");
940+
}
913941
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ public Answer execute(final StartCommand command, final LibvirtComputingResource
8080
}
8181

8282
libvirtComputingResource.createVifs(vmSpec, vm);
83-
84-
logger.debug("starting " + vmName + ": " + vm.toString());
83+
if (logger.isDebugEnabled()) {
84+
logger.debug("Starting {} : {}", vmName, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(vm.toString()));
85+
}
8586
String vmInitialSpecification = vm.toString();
8687
String vmFinalSpecification = performXmlTransformHook(vmInitialSpecification, libvirtComputingResource);
8788
libvirtComputingResource.startVM(conn, vmName, vmFinalSpecification);

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ private Map<String, MigrateDiskInfo> createMapMigrateStorage(String sourceText,
589589
@Test
590590
public void testReplaceIpForVNCInDescFile() {
591591
final String targetIp = "192.168.22.21";
592-
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(fullfile, targetIp, null, "");
592+
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(fullfile, targetIp, "vncSecretPwd", "");
593593
assertEquals("transformation does not live up to expectation:\n" + result, targetfile, result);
594594
}
595595

@@ -1019,4 +1019,28 @@ public void replaceCdromIsoPathTest() throws ParserConfigurationException, IOExc
10191019

10201020
Assert.assertTrue(finalXml.contains(newIsoVolumePath));
10211021
}
1022+
1023+
@Test
1024+
public void testMaskVncPwdDomain() {
1025+
// Test case 1: Single quotes
1026+
String xml1 = "<graphics type='vnc' port='5900' passwd='secret123'/>";
1027+
String expected1 = "<graphics type='vnc' port='5900' passwd='*****'/>";
1028+
assertEquals(expected1, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml1));
1029+
1030+
// Test case 2: Double quotes
1031+
String xml2 = "<graphics type=\"vnc\" port=\"5901\" passwd=\"mypassword\"/>";
1032+
String expected2 = "<graphics type=\"vnc\" port=\"5901\" passwd=\"*****\"/>";
1033+
assertEquals(expected2, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml2));
1034+
1035+
// Test case 3: Non-VNC graphics (should remain unchanged)
1036+
String xml3 = "<graphics type='spice' port='5902' passwd='notvnc'/>";
1037+
assertEquals(xml3, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml3));
1038+
1039+
// Test case 4: Multiple VNC entries in one string
1040+
String xml4 = "<graphics type='vnc' port='5900' passwd='a'/>\n" +
1041+
"<graphics type='vnc' port='5901' passwd='b'/>";
1042+
String expected4 = "<graphics type='vnc' port='5900' passwd='*****'/>\n" +
1043+
"<graphics type='vnc' port='5901' passwd='*****'/>";
1044+
assertEquals(expected4, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml4));
1045+
}
10221046
}

0 commit comments

Comments
 (0)