Skip to content

Commit 420bf6d

Browse files
Merge branch '4.22'
2 parents 1b0a036 + b1f870a commit 420bf6d

File tree

16 files changed

+330
-68
lines changed

16 files changed

+330
-68
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
@@ -1216,6 +1216,7 @@ public class ApiConstants {
12161216
public static final String DOCKER_REGISTRY_EMAIL = "dockerregistryemail";
12171217
public static final String ISO_NAME = "isoname";
12181218
public static final String ISO_STATE = "isostate";
1219+
public static final String ISO_URL = "isourl";
12191220
public static final String SEMANTIC_VERSION = "semanticversion";
12201221
public static final String KUBERNETES_VERSION_ID = "kubernetesversionid";
12211222
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
@@ -163,7 +163,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
163163
final String target = command.getDestinationIp();
164164
xmlDesc = dm.getXMLDesc(xmlFlag);
165165
if (logger.isDebugEnabled()) {
166-
logger.debug(String.format("VM [%s] with XML configuration [%s] will be migrated to host [%s].", vmName, xmlDesc, target));
166+
logger.debug("VM {} with XML configuration {} will be migrated to host {}.", vmName, maskSensitiveInfoInXML(xmlDesc), target);
167167
}
168168

169169
// Limit the VNC password in case the length is greater than 8 characters
@@ -178,7 +178,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
178178
logger.debug(String.format("Editing mount path of ISO from %s to %s", oldIsoVolumePath, newIsoVolumePath));
179179
xmlDesc = replaceDiskSourceFile(xmlDesc, newIsoVolumePath, vmName);
180180
if (logger.isDebugEnabled()) {
181-
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));
181+
logger.debug("Replaced disk mount point {} with {} in Instance {} XML configuration. New XML configuration is {}.", oldIsoVolumePath, newIsoVolumePath, vmName, maskSensitiveInfoInXML(xmlDesc));
182182
}
183183
}
184184

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

210210
if (migrateStorage) {
211211
if (logger.isDebugEnabled()) {
212-
logger.debug(String.format("Changing VM [%s] volumes during migration to host: [%s].", vmName, target));
212+
logger.debug("Changing VM {} volumes during migration to host: {}.", vmName, target);
213213
}
214214
xmlDesc = replaceStorage(xmlDesc, mapMigrateStorage, migrateStorageManaged);
215215
if (logger.isDebugEnabled()) {
216-
logger.debug(String.format("Changed VM [%s] XML configuration of used storage. New XML configuration is [%s].", vmName, xmlDesc));
216+
logger.debug("Changed VM {} XML configuration of used storage. New XML configuration is {}.", vmName, maskSensitiveInfoInXML(xmlDesc));
217217
}
218218
migrateDiskLabels = getMigrateStorageDeviceLabels(disks, mapMigrateStorage);
219219
}
220220

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

@@ -240,7 +240,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
240240
}
241241

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

@@ -256,20 +256,21 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
256256
final Future<Domain> migrateThread = executor.submit(worker);
257257
executor.shutdown();
258258
long sleeptime = 0;
259+
final int migrateDowntime = libvirtComputingResource.getMigrateDowntime();
260+
boolean isMigrateDowntimeSet = false;
261+
259262
while (!executor.isTerminated()) {
260263
Thread.sleep(100);
261264
sleeptime += 100;
262-
if (sleeptime == 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state
263-
final int migrateDowntime = libvirtComputingResource.getMigrateDowntime();
264-
if (migrateDowntime > 0 ) {
265-
try {
266-
final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime);
267-
if (setDowntime == 0 ) {
268-
logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms");
269-
}
270-
} catch (final LibvirtException e) {
271-
logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
265+
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
266+
try {
267+
final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime);
268+
if (setDowntime == 0 ) {
269+
isMigrateDowntimeSet = true;
270+
logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms");
272271
}
272+
} catch (final LibvirtException e) {
273+
logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
273274
}
274275
}
275276
if (sleeptime % 1000 == 0) {
@@ -287,7 +288,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
287288
} catch (final LibvirtException e) {
288289
logger.info("Couldn't get VM domain state after " + sleeptime + "ms: " + e.getMessage());
289290
}
290-
if (state != null && state == DomainState.VIR_DOMAIN_RUNNING) {
291+
if (state != null && (state == DomainState.VIR_DOMAIN_RUNNING || state == DomainState.VIR_DOMAIN_PAUSED)) {
291292
try {
292293
DomainJobInfo job = dm.getJobInfo();
293294
logger.warn("Aborting migration of VM {} with domain job [{}] due to timeout after {} seconds. " +
@@ -334,6 +335,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
334335
if (logger.isDebugEnabled()) {
335336
logger.debug(String.format("Cleaning the disks of VM [%s] in the source pool after VM migration finished.", vmName));
336337
}
338+
resumeDomainIfPaused(destDomain, vmName);
337339
deleteOrDisconnectDisksOnSourcePool(libvirtComputingResource, migrateDiskInfoList, disks);
338340
libvirtComputingResource.cleanOldSecretsByDiskDef(conn, disks);
339341
}
@@ -408,6 +410,28 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
408410
return new MigrateAnswer(command, result == null, result, null);
409411
}
410412

413+
private DomainState getDestDomainState(Domain destDomain, String vmName) {
414+
DomainState dmState = null;
415+
try {
416+
dmState = destDomain.getInfo().state;
417+
} catch (final LibvirtException e) {
418+
logger.info("Failed to get domain state for VM: " + vmName + " due to: " + e.getMessage());
419+
}
420+
return dmState;
421+
}
422+
423+
private void resumeDomainIfPaused(Domain destDomain, String vmName) {
424+
DomainState dmState = getDestDomainState(destDomain, vmName);
425+
if (dmState == DomainState.VIR_DOMAIN_PAUSED) {
426+
logger.info("Resuming VM " + vmName + " on destination after migration");
427+
try {
428+
destDomain.resume();
429+
} catch (final Exception e) {
430+
logger.error("Failed to resume vm " + vmName + " on destination after migration due to : " + e.getMessage());
431+
}
432+
}
433+
}
434+
411435
/**
412436
* Gets the disk labels (vda, vdb...) of the disks mapped for migration on mapMigrateStorage.
413437
* @param diskDefinitions list of all the disksDefinitions of the VM.
@@ -715,9 +739,7 @@ String replaceIpForVNCInDescFileAndNormalizePassword(String xmlDesc, final Strin
715739
graphElem = graphElem.replaceAll("passwd='([^\\s]+)'", "passwd='" + vncPassword + "'");
716740
}
717741
xmlDesc = xmlDesc.replaceAll(GRAPHICS_ELEM_START + CONTENTS_WILDCARD + GRAPHICS_ELEM_END, graphElem);
718-
if (logger.isDebugEnabled()) {
719-
logger.debug(String.format("Replaced the VNC IP address [%s] with [%s] in VM [%s].", originalGraphElem, graphElem, vmName));
720-
}
742+
logger.debug("Replaced the VNC IP address {} with {} in VM {}.", maskSensitiveInfoInXML(originalGraphElem), maskSensitiveInfoInXML(graphElem), vmName);
721743
}
722744
}
723745
return xmlDesc;
@@ -1036,4 +1058,10 @@ private boolean findSourceNode(Document doc, Node diskNode, String vmName, Strin
10361058
}
10371059
return false;
10381060
}
1061+
1062+
public static String maskSensitiveInfoInXML(String xmlDesc) {
1063+
if (xmlDesc == null) return null;
1064+
return xmlDesc.replaceAll("(graphics\\s+[^>]*type=['\"]vnc['\"][^>]*passwd=['\"])([^'\"]*)(['\"])",
1065+
"$1*****$3");
1066+
}
10391067
}

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
@@ -84,8 +84,9 @@ public Answer execute(final StartCommand command, final LibvirtComputingResource
8484
}
8585

8686
libvirtComputingResource.createVifs(vmSpec, vm);
87-
88-
logger.debug("starting " + vmName + ": " + vm.toString());
87+
if (logger.isDebugEnabled()) {
88+
logger.debug("Starting {} : {}", vmName, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(vm.toString()));
89+
}
8990
String vmInitialSpecification = vm.toString();
9091
String vmFinalSpecification = performXmlTransformHook(vmInitialSpecification, libvirtComputingResource);
9192
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
@@ -658,7 +658,7 @@ private Map<String, MigrateDiskInfo> createMapMigrateStorage(String sourceText,
658658
@Test
659659
public void testReplaceIpForVNCInDescFile() {
660660
final String targetIp = "192.168.22.21";
661-
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(fullfile, targetIp, null, "");
661+
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(fullfile, targetIp, "vncSecretPwd", "");
662662
assertEquals("transformation does not live up to expectation:\n" + result, targetfile, result);
663663
}
664664

@@ -1089,6 +1089,30 @@ public void replaceCdromIsoPathTest() throws ParserConfigurationException, IOExc
10891089
Assert.assertTrue(finalXml.contains(newIsoVolumePath));
10901090
}
10911091

1092+
@Test
1093+
public void testMaskVncPwdDomain() {
1094+
// Test case 1: Single quotes
1095+
String xml1 = "<graphics type='vnc' port='5900' passwd='secret123'/>";
1096+
String expected1 = "<graphics type='vnc' port='5900' passwd='*****'/>";
1097+
assertEquals(expected1, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml1));
1098+
1099+
// Test case 2: Double quotes
1100+
String xml2 = "<graphics type=\"vnc\" port=\"5901\" passwd=\"mypassword\"/>";
1101+
String expected2 = "<graphics type=\"vnc\" port=\"5901\" passwd=\"*****\"/>";
1102+
assertEquals(expected2, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml2));
1103+
1104+
// Test case 3: Non-VNC graphics (should remain unchanged)
1105+
String xml3 = "<graphics type='spice' port='5902' passwd='notvnc'/>";
1106+
assertEquals(xml3, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml3));
1107+
1108+
// Test case 4: Multiple VNC entries in one string
1109+
String xml4 = "<graphics type='vnc' port='5900' passwd='a'/>\n" +
1110+
"<graphics type='vnc' port='5901' passwd='b'/>";
1111+
String expected4 = "<graphics type='vnc' port='5900' passwd='*****'/>\n" +
1112+
"<graphics type='vnc' port='5901' passwd='*****'/>";
1113+
assertEquals(expected4, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml4));
1114+
}
1115+
10921116
@Test
10931117
public void updateGpuDevicesIfNeededTestNoGpuDevice() throws Exception {
10941118
Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,8 +1383,7 @@ protected void ensureResourceLimitsForScale(final KubernetesClusterVO cluster,
13831383
}
13841384

13851385
totalAdditionalVms += additional;
1386-
long effectiveCpu = (long) so.getCpu() * so.getSpeed();
1387-
totalAdditionalCpuUnits += effectiveCpu * additional;
1386+
totalAdditionalCpuUnits += so.getCpu() * additional;
13881387
totalAdditionalRamMb += so.getRamSize() * additional;
13891388

13901389
try {

0 commit comments

Comments
 (0)