Skip to content

Commit 3bb318b

Browse files
authored
kvm: Add support for cgroupv2 (#8252)
1. Problem description In Apache CloudStack (ACS), when a VM is deployed in a host with the KVM hypervisor, an XML file is created in the assigned host, which has a property shares that defines the weight of the VM to access the host CPU. The value of this property has no unit, and it is a relative measure to calculate how much CPU a given VM will have in the host. However, this value has a limit, which depends on the version of cgroup utilized by the host's kernel. The problem lies at the range value of shares that varies between both versions: [2, 264144] for cgroups version 1; and [1, 10000] for cgroups version 2. Currently, ACS calculates the value of shares using Equation 1, presented below, where CPU is the number of cores and speed is the CPU frequency; both specified in the VM's compute offering. Therefore, if a compute offering has, for example, 6 cores at 2 GHz, the shares value will be 12000 and an exception will be thrown by libvirt if the host utilizes cgroup v2. The second version is becoming the default one in current Linux distributions; thus, it is necessary to address this limitation. Equation 1 shares = CPU * speed Fixes: #6744 2. Proposed changes To address the problem described, we propose to apply a scale conversion considering the max shares of the host. Using the same formula currently utilized by ACS, it is possible to calculate the maximum shares of a VM for a given host. In other words, using the number of cores and the nominal speed of the host's CPU as the upper limit of shares allowed to a VM. Then, this value will be scaled to the allowed interval of [1, 10000] of cgroup v2 by using a linear scale conversion. The VM shares would be calculated as Equation 2, presented below, where VM requested shares is the requested shares value calculated using Equation 1, cgroup upper limit is fixed with a value of 10000 (cgroups v2 upper limit), and host max shares is the maximum shares value of the host, calculated using Equation 1. Using Equation 2, the only case where a VM passes the cgroup v2 limit is when the user requests more resources than the host has, which is not possible with the current implementation of ACS. Equation 2 shares = (VM requested shares * cgroup upper limit)/host max shares To implement the proposal, the following APIs will be updated: deployVirtualMachine, migrateVirtualMachine and scaleVirtualMachine. When a VM is being deployed, a new verification will be added to find a suitable host. The max shares of each host will be calculated, and the VM calculated shares will be verified if it does not surpass the host's value. Likewise, the migration of VMs will have a similar new verification. Lastly, the scale of VMs will also have the same verification for the VM's host. To determine the max shares of a given host, we will use the same equation currently used in ACS for calculating the shares of VMs, presented in Section 1. When Equation 1 is used to determine the maximum shares of a host, CPU is the number of cores of the host, and speed is the nominal CPU speed, i.e., considering the CPU's base frequency. It is important to note that these changes are only for hosts with the KVM hypervisor using cgroup v2 for now.
1 parent 3ce7c39 commit 3bb318b

File tree

12 files changed

+463
-39
lines changed

12 files changed

+463
-39
lines changed

core/src/main/java/com/cloud/agent/api/MigrateCommand.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public class MigrateCommand extends Command {
4040
private boolean executeInSequence = false;
4141
private List<MigrateDiskInfo> migrateDiskInfoList = new ArrayList<>();
4242
private Map<String, DpdkTO> dpdkInterfaceMapping = new HashMap<>();
43+
44+
private int newVmCpuShares;
45+
4346
Map<String, Boolean> vlanToPersistenceMap = new HashMap<>();
4447

4548
public Map<String, DpdkTO> getDpdkInterfaceMapping() {
@@ -138,6 +141,14 @@ public void setMigrateDiskInfoList(List<MigrateDiskInfo> migrateDiskInfoList) {
138141
this.migrateDiskInfoList = migrateDiskInfoList;
139142
}
140143

144+
public int getNewVmCpuShares() {
145+
return newVmCpuShares;
146+
}
147+
148+
public void setNewVmCpuShares(int newVmCpuShares) {
149+
this.newVmCpuShares = newVmCpuShares;
150+
}
151+
141152
public static class MigrateDiskInfo {
142153
public enum DiskType {
143154
FILE, BLOCK;

core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public class PrepareForMigrationAnswer extends Answer {
2828

2929
private Map<String, DpdkTO> dpdkInterfaceMapping = new HashMap<>();
3030

31+
private Integer newVmCpuShares = null;
32+
3133
protected PrepareForMigrationAnswer() {
3234
}
3335

@@ -50,4 +52,12 @@ public void setDpdkInterfaceMapping(Map<String, DpdkTO> mapping) {
5052
public Map<String, DpdkTO> getDpdkInterfaceMapping() {
5153
return this.dpdkInterfaceMapping;
5254
}
55+
56+
public Integer getNewVmCpuShares() {
57+
return newVmCpuShares;
58+
}
59+
60+
public void setNewVmCpuShares(Integer newVmCpuShares) {
61+
this.newVmCpuShares = newVmCpuShares;
62+
}
5363
}

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import javax.persistence.EntityExistsException;
4949

5050
import com.cloud.event.ActionEventUtils;
51+
import com.google.gson.Gson;
5152
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
5253
import org.apache.cloudstack.annotation.AnnotationService;
5354
import org.apache.cloudstack.annotation.dao.AnnotationDao;
@@ -2790,23 +2791,9 @@ protected void migrate(final VMInstanceVO vm, final long srcHostId, final Deploy
27902791
}
27912792

27922793
boolean migrated = false;
2793-
Map<String, DpdkTO> dpdkInterfaceMapping = null;
2794+
Map<String, DpdkTO> dpdkInterfaceMapping = new HashMap<>();
27942795
try {
2795-
final boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
2796-
Map<String, Boolean> vlanToPersistenceMap = getVlanToPersistenceMapForVM(vm.getId());
2797-
final MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows, to, getExecuteInSequence(vm.getHypervisorType()));
2798-
if (MapUtils.isNotEmpty(vlanToPersistenceMap)) {
2799-
mc.setVlanToPersistenceMap(vlanToPersistenceMap);
2800-
}
2801-
2802-
boolean kvmAutoConvergence = StorageManager.KvmAutoConvergence.value();
2803-
mc.setAutoConvergence(kvmAutoConvergence);
2804-
mc.setHostGuid(dest.getHost().getGuid());
2805-
2806-
dpdkInterfaceMapping = ((PrepareForMigrationAnswer) pfma).getDpdkInterfaceMapping();
2807-
if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) {
2808-
mc.setDpdkInterfaceMapping(dpdkInterfaceMapping);
2809-
}
2796+
final MigrateCommand mc = buildMigrateCommand(vm, to, dest, pfma, dpdkInterfaceMapping);
28102797

28112798
try {
28122799
final Answer ma = _agentMgr.send(vm.getLastHostId(), mc);
@@ -2878,6 +2865,43 @@ protected void migrate(final VMInstanceVO vm, final long srcHostId, final Deploy
28782865
}
28792866
}
28802867

2868+
/**
2869+
* Create and set parameters for the {@link MigrateCommand} used in the migration and scaling of VMs.
2870+
*/
2871+
protected MigrateCommand buildMigrateCommand(VMInstanceVO vmInstance, VirtualMachineTO virtualMachineTO, DeployDestination destination, Answer answer,
2872+
Map<String, DpdkTO> dpdkInterfaceMapping) {
2873+
final boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vmInstance.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
2874+
final MigrateCommand migrateCommand = new MigrateCommand(vmInstance.getInstanceName(), destination.getHost().getPrivateIpAddress(), isWindows, virtualMachineTO,
2875+
getExecuteInSequence(vmInstance.getHypervisorType()));
2876+
2877+
Map<String, Boolean> vlanToPersistenceMap = getVlanToPersistenceMapForVM(vmInstance.getId());
2878+
if (MapUtils.isNotEmpty(vlanToPersistenceMap)) {
2879+
s_logger.debug(String.format("Setting VLAN persistence to [%s] as part of migrate command for VM [%s].", new Gson().toJson(vlanToPersistenceMap), virtualMachineTO));
2880+
migrateCommand.setVlanToPersistenceMap(vlanToPersistenceMap);
2881+
}
2882+
2883+
migrateCommand.setAutoConvergence(StorageManager.KvmAutoConvergence.value());
2884+
migrateCommand.setHostGuid(destination.getHost().getGuid());
2885+
2886+
PrepareForMigrationAnswer prepareForMigrationAnswer = (PrepareForMigrationAnswer) answer;
2887+
2888+
Map<String, DpdkTO> answerDpdkInterfaceMapping = prepareForMigrationAnswer.getDpdkInterfaceMapping();
2889+
if (MapUtils.isNotEmpty(answerDpdkInterfaceMapping) && dpdkInterfaceMapping != null) {
2890+
s_logger.debug(String.format("Setting DPDK interface mapping to [%s] as part of migrate command for VM [%s].", new Gson().toJson(vlanToPersistenceMap),
2891+
virtualMachineTO));
2892+
dpdkInterfaceMapping.putAll(answerDpdkInterfaceMapping);
2893+
migrateCommand.setDpdkInterfaceMapping(dpdkInterfaceMapping);
2894+
}
2895+
2896+
Integer newVmCpuShares = prepareForMigrationAnswer.getNewVmCpuShares();
2897+
if (newVmCpuShares != null) {
2898+
s_logger.debug(String.format("Setting CPU shares to [%d] as part of migrate command for VM [%s].", newVmCpuShares, virtualMachineTO));
2899+
migrateCommand.setNewVmCpuShares(newVmCpuShares);
2900+
}
2901+
2902+
return migrateCommand;
2903+
}
2904+
28812905
private void updateVmPod(VMInstanceVO vm, long dstHostId) {
28822906
// update the VMs pod
28832907
HostVO host = _hostDao.findById(dstHostId);
@@ -4395,16 +4419,7 @@ private void orchestrateMigrateForScale(final String vmUuid, final long srcHostI
43954419

43964420
boolean migrated = false;
43974421
try {
4398-
Map<String, Boolean> vlanToPersistenceMap = getVlanToPersistenceMapForVM(vm.getId());
4399-
final boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
4400-
final MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows, to, getExecuteInSequence(vm.getHypervisorType()));
4401-
if (MapUtils.isNotEmpty(vlanToPersistenceMap)) {
4402-
mc.setVlanToPersistenceMap(vlanToPersistenceMap);
4403-
}
4404-
4405-
boolean kvmAutoConvergence = StorageManager.KvmAutoConvergence.value();
4406-
mc.setAutoConvergence(kvmAutoConvergence);
4407-
mc.setHostGuid(dest.getHost().getGuid());
4422+
final MigrateCommand mc = buildMigrateCommand(vm, to, dest, pfma, null);
44084423

44094424
try {
44104425
final Answer ma = _agentMgr.send(vm.getLastHostId(), mc);

engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import javax.inject.Inject;
3333

34+
import com.cloud.agent.api.PrepareForMigrationAnswer;
3435
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
3536
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
3637
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
@@ -1884,18 +1885,18 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
18841885
}
18851886

18861887
PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(vmTO);
1888+
Answer pfma;
18871889

18881890
try {
1889-
Answer pfma = agentManager.send(destHost.getId(), pfmc);
1891+
pfma = agentManager.send(destHost.getId(), pfmc);
18901892

18911893
if (pfma == null || !pfma.getResult()) {
18921894
String details = pfma != null ? pfma.getDetails() : "null answer returned";
18931895
String msg = "Unable to prepare for migration due to the following: " + details;
18941896

18951897
throw new AgentUnavailableException(msg, destHost.getId());
18961898
}
1897-
}
1898-
catch (final OperationTimedoutException e) {
1899+
} catch (final OperationTimedoutException e) {
18991900
throw new AgentUnavailableException("Operation timed out", destHost.getId());
19001901
}
19011902

@@ -1911,6 +1912,12 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
19111912
migrateCommand.setMigrateStorageManaged(managedStorageDestination);
19121913
migrateCommand.setMigrateNonSharedInc(migrateNonSharedInc);
19131914

1915+
Integer newVmCpuShares = ((PrepareForMigrationAnswer) pfma).getNewVmCpuShares();
1916+
if (newVmCpuShares != null) {
1917+
LOGGER.debug(String.format("Setting CPU shares to [%d] as part of migrate VM with volumes command for VM [%s].", newVmCpuShares, vmTO));
1918+
migrateCommand.setNewVmCpuShares(newVmCpuShares);
1919+
}
1920+
19141921
boolean kvmAutoConvergence = StorageManager.KvmAutoConvergence.value();
19151922
migrateCommand.setAutoConvergence(kvmAutoConvergence);
19161923

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

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import org.apache.commons.lang.ArrayUtils;
7373
import org.apache.commons.lang.BooleanUtils;
7474
import org.apache.commons.lang.math.NumberUtils;
75+
import org.apache.commons.lang3.ObjectUtils;
7576
import org.apache.commons.lang3.StringUtils;
7677
import org.apache.log4j.Logger;
7778
import org.apache.xerces.impl.xpath.regex.Match;
@@ -472,6 +473,14 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
472473
*/
473474
private static final String COMMAND_SET_MEM_BALLOON_STATS_PERIOD = "virsh dommemstat %s --period %s --live";
474475

476+
private static int hostCpuMaxCapacity = 0;
477+
478+
private static final int CGROUP_V2_UPPER_LIMIT = 10000;
479+
480+
private static final String COMMAND_GET_CGROUP_HOST_VERSION = "stat -fc %T /sys/fs/cgroup/";
481+
482+
public static final String CGROUP_V2 = "cgroup2fs";
483+
475484
protected long getHypervisorLibvirtVersion() {
476485
return _hypervisorLibvirtVersion;
477486
}
@@ -547,6 +556,18 @@ public ExecutionResult cleanupCommand(final NetworkElementCommand cmd) {
547556
return new ExecutionResult(true, null);
548557
}
549558

559+
/**
560+
* @return the host CPU max capacity according to the method {@link LibvirtComputingResource#calculateHostCpuMaxCapacity(int, Long)}; if the host utilizes cgroup v1, this
561+
* value is 0.
562+
*/
563+
public int getHostCpuMaxCapacity() {
564+
return hostCpuMaxCapacity;
565+
}
566+
567+
public void setHostCpuMaxCapacity(int hostCpuMaxCapacity) {
568+
LibvirtComputingResource.hostCpuMaxCapacity = hostCpuMaxCapacity;
569+
}
570+
550571
public LibvirtKvmAgentHook getTransformer() throws IOException {
551572
return new LibvirtKvmAgentHook(_agentHooksBasedir, _agentHooksLibvirtXmlScript, _agentHooksLibvirtXmlMethod);
552573
}
@@ -2673,12 +2694,41 @@ protected FeaturesDef createFeaturesDef(Map<String, String> customParams, boolea
26732694
*/
26742695
protected CpuTuneDef createCpuTuneDef(VirtualMachineTO vmTO) {
26752696
CpuTuneDef ctd = new CpuTuneDef();
2676-
int shares = vmTO.getCpus() * (vmTO.getMinSpeed() != null ? vmTO.getMinSpeed() : vmTO.getSpeed());
2677-
ctd.setShares(shares);
2697+
ctd.setShares(calculateCpuShares(vmTO));
26782698
setQuotaAndPeriod(vmTO, ctd);
26792699
return ctd;
26802700
}
26812701

2702+
/**
2703+
* Calculates the VM CPU shares considering the cgroup version of the host.
2704+
* <ul>
2705+
* <li>
2706+
* If the host utilize cgroup v1, then, the CPU shares is calculated as <b>VM CPU shares = CPU cores * CPU frequency</b>.
2707+
* </li>
2708+
* <li>
2709+
* If the host utilize cgroup v2, the CPU shares calculation considers the cgroup v2 upper limit of <b>10,000</b>, and a linear scale conversion is applied
2710+
* considering the maximum host CPU shares (i.e. using the number of CPU cores and CPU nominal frequency of the host). Therefore, the VM CPU shares is calculated as
2711+
* <b>VM CPU shares = (VM requested shares * cgroup upper limit) / host max shares</b>.
2712+
* </li>
2713+
* </ul>
2714+
*/
2715+
public int calculateCpuShares(VirtualMachineTO vmTO) {
2716+
int vCpus = vmTO.getCpus();
2717+
int cpuSpeed = ObjectUtils.defaultIfNull(vmTO.getMinSpeed(), vmTO.getSpeed());
2718+
int requestedCpuShares = vCpus * cpuSpeed;
2719+
int hostCpuMaxCapacity = getHostCpuMaxCapacity();
2720+
2721+
if (hostCpuMaxCapacity > 0) {
2722+
int updatedCpuShares = (int) Math.ceil((requestedCpuShares * CGROUP_V2_UPPER_LIMIT) / (double) hostCpuMaxCapacity);
2723+
s_logger.debug(String.format("This host utilizes cgroupv2 (as the max shares value is [%s]), thus, the VM requested shares of [%s] will be converted to " +
2724+
"consider the host limits; the new CPU shares value is [%s].", hostCpuMaxCapacity, requestedCpuShares, updatedCpuShares));
2725+
return updatedCpuShares;
2726+
}
2727+
s_logger.debug(String.format("This host does not have a maximum CPU shares set; therefore, this host utilizes cgroupv1 and the VM requested CPU shares [%s] will not be " +
2728+
"converted.", requestedCpuShares));
2729+
return requestedCpuShares;
2730+
}
2731+
26822732
private CpuModeDef createCpuModeDef(VirtualMachineTO vmTO, int vcpus) {
26832733
final CpuModeDef cmd = new CpuModeDef();
26842734
cmd.setMode(_guestCpuMode);
@@ -3469,8 +3519,8 @@ private Map<String, String> getVersionStrings() {
34693519

34703520
@Override
34713521
public StartupCommand[] initialize() {
3472-
34733522
final KVMHostInfo info = new KVMHostInfo(_dom0MinMem, _dom0OvercommitMem, _manualCpuSpeed);
3523+
calculateHostCpuMaxCapacity(info.getCpus(), info.getCpuSpeed());
34743524

34753525
String capabilities = String.join(",", info.getCapabilities());
34763526
if (dpdkSupport) {
@@ -3514,6 +3564,32 @@ public StartupCommand[] initialize() {
35143564
return startupCommandsArray;
35153565
}
35163566

3567+
/**
3568+
* Calculates and sets the host CPU max capacity according to the cgroup version of the host.
3569+
* <ul>
3570+
* <li>
3571+
* <b>cgroup v1</b>: the max CPU capacity for the host is set to <b>0</b>.
3572+
* </li>
3573+
* <li>
3574+
* <b>cgroup v2</b>: the max CPU capacity for the host is the value of <b>cpuCores * cpuSpeed</b>.
3575+
* </li>
3576+
* </ul>
3577+
*/
3578+
protected void calculateHostCpuMaxCapacity(int cpuCores, Long cpuSpeed) {
3579+
String output = Script.runSimpleBashScript(COMMAND_GET_CGROUP_HOST_VERSION);
3580+
s_logger.info(String.format("Host uses control group [%s].", output));
3581+
3582+
if (!CGROUP_V2.equals(output)) {
3583+
s_logger.info(String.format("Setting host CPU max capacity to 0, as it uses cgroup v1.", getHostCpuMaxCapacity()));
3584+
setHostCpuMaxCapacity(0);
3585+
return;
3586+
}
3587+
3588+
s_logger.info(String.format("Calculating the max shares of the host."));
3589+
setHostCpuMaxCapacity(cpuCores * cpuSpeed.intValue());
3590+
s_logger.info(String.format("The max shares of the host is [%d].", getHostCpuMaxCapacity()));
3591+
}
3592+
35173593
private StartupStorageCommand createLocalStoragePool(String localStoragePath, String localStorageUUID, StartupRoutingCommand cmd) {
35183594
StartupStorageCommand sscmd = null;
35193595
try {

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.io.IOException;
2424
import java.io.InputStream;
2525
import java.net.URISyntaxException;
26+
import java.nio.charset.StandardCharsets;
2627
import java.util.List;
2728
import java.util.Map;
2829
import java.util.Set;
@@ -211,6 +212,8 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
211212
}
212213
}
213214

215+
xmlDesc = updateVmSharesIfNeeded(command, xmlDesc, libvirtComputingResource);
216+
214217
dconn = libvirtUtilitiesHelper.retrieveQemuConnection(destinationUri);
215218

216219
if (to.getType() == VirtualMachine.Type.User) {
@@ -362,6 +365,44 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
362365
return new MigrateAnswer(command, result == null, result, null);
363366
}
364367

368+
/**
369+
* Checks if the CPU shares are equal in the source host and destination host.
370+
* <ul>
371+
* <li>
372+
* If both hosts utilize cgroup v1; then, the shares value of the VM is equal in both hosts, and there is no need to update the VM CPU shares value for the
373+
* migration.</li>
374+
* <li>
375+
* If, at least, one of the hosts utilize cgroup v2, the VM CPU shares must be recalculated for the migration, accordingly to
376+
* method {@link LibvirtComputingResource#calculateCpuShares(VirtualMachineTO)}.
377+
* </li>
378+
* </ul>
379+
*/
380+
protected String updateVmSharesIfNeeded(MigrateCommand migrateCommand, String xmlDesc, LibvirtComputingResource libvirtComputingResource)
381+
throws ParserConfigurationException, IOException, SAXException, TransformerException {
382+
Integer newVmCpuShares = migrateCommand.getNewVmCpuShares();
383+
int currentCpuShares = libvirtComputingResource.calculateCpuShares(migrateCommand.getVirtualMachine());
384+
385+
if (newVmCpuShares == currentCpuShares) {
386+
s_logger.info(String.format("Current CPU shares [%s] is equal in both hosts; therefore, there is no need to update the CPU shares for the new host.",
387+
currentCpuShares));
388+
return xmlDesc;
389+
}
390+
391+
InputStream inputStream = IOUtils.toInputStream(xmlDesc, StandardCharsets.UTF_8);
392+
DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory();
393+
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
394+
Document document = docBuilder.parse(inputStream);
395+
396+
Element root = document.getDocumentElement();
397+
Node sharesNode = root.getElementsByTagName("shares").item(0);
398+
String currentShares = sharesNode.getTextContent();
399+
400+
s_logger.info(String.format("VM [%s] will have CPU shares altered from [%s] to [%s] as part of migration because the cgroups version differs between hosts.",
401+
migrateCommand.getVmName(), currentShares, newVmCpuShares));
402+
sharesNode.setTextContent(String.valueOf(newVmCpuShares));
403+
return getXml(document);
404+
}
405+
365406
/**
366407
* Replace DPDK source path and target before migrations
367408
*/

0 commit comments

Comments
 (0)