From cbdf98f74fa704f6c80dbf5df57cbc5bb4eb900d Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 14:02:15 -0300 Subject: [PATCH 01/38] Create utility to centralize byte convertions --- .../utils/bytescale/ByteScaleUtils.java | 49 +++++++++++++++++++ .../utils/bytescale/ByteScaleUtilsTest.java | 40 +++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java create mode 100644 utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java diff --git a/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java b/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java new file mode 100644 index 000000000000..aadfe74fef80 --- /dev/null +++ b/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java @@ -0,0 +1,49 @@ +/* + * Copyright 2021 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cloudstack.utils.bytescale; + +/** + * This class provides a facility to convert bytes through his scales (b, Kib, Kb, Mib, Mb...). + * + */ +public class ByteScaleUtils { + + public static final int KiB = 1024; + public static final int MiB = KiB * 1024; + + private ByteScaleUtils() {} + + /** + * Converts mebibytes to bytes. + * + * @param mib The integer value to convert to bytes (eq: 1, 2, 3, ..., 42,...). + * @return The parameter multiplied by 1048576 (1024 * 1024, 1 MiB). + */ + public static long mibToBytes(int mib) { + return mib * MiB; + } + + /** + * Converts bytes to kibibytes. + * + * @param b The value in bytes to convert to kibibytes. + * @return The parameter divided by 1024 (1 KiB). + */ + public static long bytesToKib(long b) { + return b / KiB; + } +} diff --git a/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java b/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java new file mode 100644 index 000000000000..02128b5a3d35 --- /dev/null +++ b/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2021 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cloudstack.utils.bytescale; + +import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class ByteScaleUtilsTest extends TestCase { + + @Test + public void validateMibToBytes() { + int mib = 3; + int b = 1024 * 1024 * mib; + assertEquals(b, ByteScaleUtils.mibToBytes(mib)); + } + + @Test + public void validateBytesToKib() { + int kib = 1024 * 3; + int b = 1024 * kib; + assertEquals(kib, ByteScaleUtils.bytesToKib(b)); + } +} \ No newline at end of file From 425ccde697f4147ab4ff62136d79ee43c16d226d Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 14:09:53 -0300 Subject: [PATCH 02/38] Add/change toString definitions --- .../main/java/com/cloud/agent/api/to/VirtualMachineTO.java | 5 +++++ engine/schema/src/main/java/com/cloud/host/HostVO.java | 2 +- .../src/main/java/com/cloud/service/ServiceOfferingVO.java | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java index c4729383dd4f..5f03b2772fce 100644 --- a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java @@ -413,4 +413,9 @@ public DeployAsIsInfoTO getDeployAsIsInfo() { public void setDeployAsIsInfo(DeployAsIsInfoTO deployAsIsInfo) { this.deployAsIsInfo = deployAsIsInfo; } + + @Override + public String toString() { + return String.format("VM {\"id\": %s, \"name\": \"%s\", \"uuid\": \"%s\", \"type\": \"%s\"}", id, name, uuid, type); + } } diff --git a/engine/schema/src/main/java/com/cloud/host/HostVO.java b/engine/schema/src/main/java/com/cloud/host/HostVO.java index 18dcac9a4a24..7085fdc2a02a 100644 --- a/engine/schema/src/main/java/com/cloud/host/HostVO.java +++ b/engine/schema/src/main/java/com/cloud/host/HostVO.java @@ -677,7 +677,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return String.format("Host [{id: \"%s\", name: \"%s\", uuid: \"%s\", type=\"%s\"}]", id, name, uuid, type); + return String.format("Host {\"id\": \"%s\", \"name\": \"%s\", \"uuid\": \"%s\", \"type\"=\"%s\"}", id, name, uuid, type); } public void setHypervisorType(HypervisorType hypervisorType) { diff --git a/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java b/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java index 3a5f3182b731..1484dbebbeaa 100644 --- a/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java @@ -334,4 +334,9 @@ public void setDynamicFlag(boolean isdynamic) { public boolean isCustomCpuSpeedSupported() { return isCustomized() && getDetail("minCPU") != null; } + + @Override + public String toString() { + return String.format("Service offering {\"id\": %s, \"name\": \"%s\", \"uuid\": \"%s\"}", getId(), getName(), getUuid()); + } } From a6bd180fd3fcca7d3ddca985548e15bbf9c6f86f Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 14:19:47 -0300 Subject: [PATCH 03/38] Create Libvirt handler to ScaleVmCommand --- .../com/cloud/resource/CommandWrapper.java | 2 + .../wrapper/LibvirtScaleVmCommandWrapper.java | 70 +++++++++++ .../LibvirtScaleVmCommandWrapperTest.java | 115 ++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java create mode 100644 plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java diff --git a/core/src/main/java/com/cloud/resource/CommandWrapper.java b/core/src/main/java/com/cloud/resource/CommandWrapper.java index f8596998b18e..21457500808c 100644 --- a/core/src/main/java/com/cloud/resource/CommandWrapper.java +++ b/core/src/main/java/com/cloud/resource/CommandWrapper.java @@ -21,8 +21,10 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import org.apache.log4j.Logger; public abstract class CommandWrapper { + protected Logger logger = Logger.getLogger(getClass()); /** * @param T is the command to be used. diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java new file mode 100644 index 000000000000..d3a1cdb1ee98 --- /dev/null +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java @@ -0,0 +1,70 @@ +/* + * Copyright 2021 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cloud.hypervisor.kvm.resource.wrapper; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ScaleVmAnswer; +import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.resource.CommandWrapper; +import com.cloud.resource.ResourceWrapper; +import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; +import org.libvirt.Connect; +import org.libvirt.Domain; +import org.libvirt.LibvirtException; + +@ResourceWrapper(handles = ScaleVmCommand.class) +public final class LibvirtScaleVmCommandWrapper extends CommandWrapper { + + @Override + public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtComputingResource) { + VirtualMachineTO vmSpec = command.getVirtualMachine(); + String vmName = vmSpec.getName(); + Connect conn = null; + + long memory = ByteScaleUtils.bytesToKib(vmSpec.getMaxRam()); + int vcpus = vmSpec.getCpus(); + String scallingDetails = String.format("%s memory to [%s KiB] and cpu cores to [%s]", vmSpec.toString(), memory, vcpus); + + try { + LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper(); + + conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName); + Domain dm = conn.domainLookupByName(vmName); + + logger.debug(String.format("Scalling %s.", scallingDetails)); + dm.setMemory(memory); + dm.setVcpus(vcpus); + + return new ScaleVmAnswer(command, true, String.format("Successfully scalled %s.", scallingDetails)); + } catch (LibvirtException e) { + String message = String.format("Unable to scale %s due to [%s].", scallingDetails, e.getMessage()); + logger.warn(message, e); + return new ScaleVmAnswer(command, false, message); + } finally { + if (conn != null) { + try { + conn.close(); + } catch (LibvirtException ex) { + logger.warn(String.format("Error trying to close libvirt connection [%s]", ex.getMessage()), ex); + } + } + } + } + +} \ No newline at end of file diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java new file mode 100644 index 000000000000..5384c69b2c75 --- /dev/null +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2021 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cloud.hypervisor.kvm.resource.wrapper; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.template.VirtualMachineTemplate; +import com.cloud.vm.VirtualMachine; +import junit.framework.TestCase; +import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.libvirt.Connect; +import org.libvirt.Domain; +import org.libvirt.LibvirtException; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class LibvirtScaleVmCommandWrapperTest extends TestCase { + + @Mock + LibvirtComputingResource computingResource; + + @Mock + ScaleVmCommand command; + + @Mock + LibvirtUtilitiesHelper libvirtUtilitiesHelper; + + @Mock + Domain domain; + + @Mock + Connect connect; + + @Mock + LibvirtException libvirtException; + + @Mock + Exception exception; + + LibvirtRequestWrapper wrapper; + VirtualMachineTO vmTo; + + String scallingDetails; + + @Before + public void init() { + wrapper = LibvirtRequestWrapper.getInstance(); + assertNotNull(wrapper); + + vmTo = new VirtualMachineTO(1, "Test 1", VirtualMachine.Type.User, 2, 1000, 67108864, 67108864, VirtualMachineTemplate.BootloaderType.External, "Other Linux (64x)", true, true, "test123"); + + long memory = ByteScaleUtils.bytesToKib(vmTo.getMaxRam()); + int vcpus = vmTo.getCpus(); + scallingDetails = String.format("%s memory to [%s KiB] and cpu cores to [%s]", vmTo.toString(), memory, vcpus); + } + + @Test + public void validateExecuteSuccessfully() throws LibvirtException { + Mockito.when(command.getVirtualMachine()).thenReturn(vmTo); + Mockito.when(computingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); + Mockito.when(libvirtUtilitiesHelper.getConnectionByVmName(Mockito.anyString())).thenReturn(connect); + Mockito.when(connect.domainLookupByName(Mockito.anyString())).thenReturn(domain); + Mockito.doNothing().when(domain).setMemory(Mockito.anyLong()); + Mockito.doNothing().when(domain).setVcpus(Mockito.anyInt()); + + Answer answer = wrapper.execute(command, computingResource); + + String details = String.format("Successfully scalled %s.", scallingDetails); + assertTrue(answer.getResult()); + assertEquals(details, answer.getDetails()); + } + + @Test + public void validateExecuteHandleLibvirtException() throws LibvirtException { + Mockito.when(command.getVirtualMachine()).thenReturn(vmTo); + Mockito.when(computingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); + Mockito.doThrow(libvirtException).when(libvirtUtilitiesHelper).getConnectionByVmName(Mockito.anyString()); + String errorMessage = ""; + Mockito.when(libvirtException.getMessage()).thenReturn(errorMessage); + + Answer answer = wrapper.execute(command, computingResource); + + String details = String.format("Unable to scale %s due to [%s].", scallingDetails, errorMessage); + assertFalse(answer.getResult()); + assertEquals(details, answer.getDetails()); + } + + @Test(expected = Exception.class) + public void validateExecuteThrowAnyOtherException() { + Mockito.doThrow(exception).when(computingResource).getLibvirtUtilitiesHelper(); + + wrapper.execute(command, computingResource); + } +} \ No newline at end of file From cc29fd2fef6ffefbd5536f8b5f57fb27b3dcea34 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 14:28:53 -0300 Subject: [PATCH 04/38] Enable dynamic scalling VM with KVM --- .../src/main/java/com/cloud/vm/UserVmManagerImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 579a33d6ee80..bab0e676cc8e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -340,6 +340,7 @@ import com.cloud.vm.snapshot.VMSnapshotManager; import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; +import java.util.HashSet; public class UserVmManagerImpl extends ManagerBase implements UserVmManager, VirtualMachineGuru, UserVmService, Configurable { private static final Logger s_logger = Logger.getLogger(UserVmManagerImpl.class); @@ -1869,7 +1870,14 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI Account caller = CallContext.current().getCallingAccount(); VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); - if (vmInstance.getHypervisorType() != HypervisorType.XenServer && vmInstance.getHypervisorType() != HypervisorType.VMware && vmInstance.getHypervisorType() != HypervisorType.Simulator) { + + Set supportedHypervisorTypes = new HashSet<>(); + supportedHypervisorTypes.add(HypervisorType.XenServer); + supportedHypervisorTypes.add(HypervisorType.VMware); + supportedHypervisorTypes.add(HypervisorType.Simulator); + supportedHypervisorTypes.add(HypervisorType.KVM); + + if (!supportedHypervisorTypes.contains(vmInstance.getHypervisorType())) { s_logger.info("Scaling the VM dynamically is not supported for VMs running on Hypervisor "+vmInstance.getHypervisorType()); throw new InvalidParameterValueException("Scaling the VM dynamically is not supported for VMs running on Hypervisor "+vmInstance.getHypervisorType()); } From 125fbc094762a9f3c373d871018dba2eeca55a3c Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 16:19:32 -0300 Subject: [PATCH 05/38] Move config from interface to class and rename it As every variable declared in interfaces are already final, this moving will be needed to mock tests in nexts commits --- .../java/com/cloud/vm/VirtualMachineManager.java | 16 ---------------- .../com/cloud/vm/VirtualMachineManagerImpl.java | 3 +-- .../configuration/ConfigurationManagerImpl.java | 14 ++++++++++---- .../java/com/cloud/vm/UserVmManagerImpl.java | 9 +++++---- 4 files changed, 16 insertions(+), 26 deletions(-) diff --git a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java index e7828fabef8d..68183ad2add1 100644 --- a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java @@ -76,22 +76,6 @@ public interface VirtualMachineManager extends Manager { ConfigKey AllowExposeHypervisorHostname = new ConfigKey("Advanced", Boolean.class, "global.allow.expose.host.hostname", "false", "If set to true, it allows the hypervisor host name on which the VM is spawned on to be exposed to the VM", true, ConfigKey.Scope.Global); - static final ConfigKey VmServiceOfferingMaxCPUCores = new ConfigKey("Advanced", - Integer.class, - "vm.serviceoffering.cpu.cores.max", - "0", - "Maximum CPU cores for vm service offering. If 0 - no limitation", - true - ); - - static final ConfigKey VmServiceOfferingMaxRAMSize = new ConfigKey("Advanced", - Integer.class, - "vm.serviceoffering.ram.size.max", - "0", - "Maximum RAM size in MB for vm service offering. If 0 - no limitation", - true - ); - interface Topics { String VM_POWER_STATE = "vm.powerstate"; } diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 4e3879f960d5..76e8ef2d08da 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -4769,8 +4769,7 @@ public ConfigKey[] getConfigKeys() { return new ConfigKey[] { ClusterDeltaSyncInterval, StartRetry, VmDestroyForcestop, VmOpCancelInterval, VmOpCleanupInterval, VmOpCleanupWait, VmOpLockStateRetry, VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, VmConfigDriveForceHostCacheUse, VmConfigDriveUseHostCacheOnUnsupportedPool, - HaVmRestartHostUp, ResoureCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel, - VmServiceOfferingMaxCPUCores, VmServiceOfferingMaxRAMSize }; + HaVmRestartHostUp, ResoureCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel }; } public List getStoragePoolAllocators() { diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index f5de35af3ed2..ab55ce9af45a 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -243,7 +243,6 @@ import com.cloud.utils.net.NetUtils; import com.cloud.vm.NicIpAlias; import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicIpAliasDao; import com.cloud.vm.dao.NicIpAliasVO; @@ -423,6 +422,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati "Indicates whether the host in down state can be put into maintenance state so thats its not enabled after it comes back.", true, ConfigKey.Scope.Zone, null); + public static ConfigKey VM_SERVICE_OFFERING_MAX_CPU_CORES = new ConfigKey("Advanced", Integer.class, "vm.serviceoffering.cpu.cores.max", "0", "Maximum CPU cores " + + "for vm service offering. If 0 - no limitation", true); + + public static ConfigKey VM_SERVICE_OFFERING_MAX_RAM_SIZE = new ConfigKey("Advanced", Integer.class, "vm.serviceoffering.ram.size.max", "0", "Maximum RAM size in " + + "MB for vm service offering. If 0 - no limitation", true); + private static final String IOPS_READ_RATE = "IOPS Read"; private static final String IOPS_WRITE_RATE = "IOPS Write"; private static final String BYTES_READ_RATE = "Bytes Read"; @@ -2361,8 +2366,8 @@ public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd) details.put(ApiConstants.MAX_CPU_NUMBER, maxCPU.toString()); } } else { - Integer maxCPUCores = VirtualMachineManager.VmServiceOfferingMaxCPUCores.value() == 0 ? Integer.MAX_VALUE: VirtualMachineManager.VmServiceOfferingMaxCPUCores.value(); - Integer maxRAMSize = VirtualMachineManager.VmServiceOfferingMaxRAMSize.value() == 0 ? Integer.MAX_VALUE: VirtualMachineManager.VmServiceOfferingMaxRAMSize.value(); + Integer maxCPUCores = VM_SERVICE_OFFERING_MAX_CPU_CORES.value() == 0 ? Integer.MAX_VALUE: VM_SERVICE_OFFERING_MAX_CPU_CORES.value(); + Integer maxRAMSize = VM_SERVICE_OFFERING_MAX_RAM_SIZE.value() == 0 ? Integer.MAX_VALUE: VM_SERVICE_OFFERING_MAX_RAM_SIZE.value(); if (cpuNumber != null && (cpuNumber.intValue() <= 0 || cpuNumber.longValue() > maxCPUCores)) { throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the cpu number value between 1 and " + maxCPUCores); } @@ -6485,6 +6490,7 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH, - BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE}; + BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE, VM_SERVICE_OFFERING_MAX_CPU_CORES, + VM_SERVICE_OFFERING_MAX_RAM_SIZE}; } } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index bab0e676cc8e..9b070d82963d 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -155,6 +155,7 @@ import com.cloud.capacity.CapacityManager; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.ConfigurationManagerImpl; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; @@ -1130,11 +1131,11 @@ public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) throws ResourceAllocationE } private void validateOfferingMaxResource(ServiceOfferingVO offering) { - Integer maxCPUCores = VirtualMachineManager.VmServiceOfferingMaxCPUCores.value() == 0 ? Integer.MAX_VALUE: VirtualMachineManager.VmServiceOfferingMaxCPUCores.value(); + Integer maxCPUCores = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES.value() == 0 ? Integer.MAX_VALUE: ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES.value(); if (offering.getCpu() > maxCPUCores) { throw new InvalidParameterValueException("Invalid cpu cores value, please choose another service offering with cpu cores between 1 and " + maxCPUCores); } - Integer maxRAMSize = VirtualMachineManager.VmServiceOfferingMaxRAMSize.value() == 0 ? Integer.MAX_VALUE: VirtualMachineManager.VmServiceOfferingMaxRAMSize.value(); + Integer maxRAMSize = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE.value() == 0 ? Integer.MAX_VALUE: ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE.value(); if (offering.getRamSize() > maxRAMSize) { throw new InvalidParameterValueException("Invalid memory value, please choose another service offering with memory between 32 and " + maxRAMSize + " MB"); } @@ -1149,7 +1150,7 @@ public void validateCustomParameters(ServiceOfferingVO serviceOffering, Map maxCPU || cpuNumber > maxCPUCores) { throw new InvalidParameterValueException(String.format("Invalid cpu cores value, specify a value between %d and %d", minCPU, Math.min(maxCPUCores, maxCPU))); } @@ -1172,7 +1173,7 @@ public void validateCustomParameters(ServiceOfferingVO serviceOffering, Map maxMemory || memory > maxRAMSize) { throw new InvalidParameterValueException(String.format("Invalid memory value, specify a value between %d and %d", minMemory, Math.min(maxRAMSize, maxMemory))); } From 329090585de5c0547185b07643f0c72193ba15ab Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 17:47:41 -0300 Subject: [PATCH 06/38] Configure VM max memory and cpu cores The values are according to service offering or global configs --- .../java/com/cloud/hypervisor/KVMGuru.java | 114 +++++++++++- .../com/cloud/hypervisor/KVMGuruTest.java | 173 ++++++++++++++++++ 2 files changed, 286 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java index cf29a1a55a93..f26a1fab1c24 100644 --- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java +++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java @@ -20,10 +20,13 @@ import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.configuration.ConfigurationManagerImpl; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.kvm.dpdk.DpdkHelper; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DataStoreRole; import com.cloud.storage.GuestOSHypervisorVO; import com.cloud.storage.GuestOSVO; @@ -42,6 +45,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Map; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; +import org.apache.commons.lang3.math.NumberUtils; public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru { @Inject @@ -53,6 +59,9 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru { @Inject DpdkHelper dpdkHelper; + @Inject + ServiceOfferingDao serviceOfferingDao; + public static final Logger s_logger = Logger.getLogger(KVMGuru.class); @Override @@ -126,7 +135,9 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { // Determine the VM's OS description GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId()); to.setOs(guestOS.getDisplayName()); - HostVO host = _hostDao.findById(vm.getVirtualMachine().getHostId()); + VirtualMachine virtualMachine = vm.getVirtualMachine(); + Long hostId = virtualMachine.getHostId(); + HostVO host = hostId == null ? null : _hostDao.findById(hostId); GuestOSHypervisorVO guestOsMapping = null; if (host != null) { guestOsMapping = _guestOsHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), getHypervisorType().toString(), host.getHypervisorVersion()); @@ -137,9 +148,110 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { to.setPlatformEmulator(guestOsMapping.getGuestOsName()); } + configureVmMemoryAndCpuCores(to, host, virtualMachine, vm); return to; } + protected void configureVmMemoryAndCpuCores(VirtualMachineTO virtualMachineTo, HostVO hostVo, VirtualMachine virtualMachine, VirtualMachineProfile virtualMachineProfile) { + String vmDescription = virtualMachineTo.toString(); + + Pair max = getHostMaxMemoryAndCpuCores(hostVo, virtualMachine, vmDescription); + + Long maxHostMemory = max.first(); + Integer maxHostCpuCore = max.second(); + + Long minMemory = virtualMachineTo.getMinRam(); + Long maxMemory = minMemory; + Integer minCpuCores = virtualMachineTo.getCpus(); + Integer maxCpuCores = minCpuCores; + + ServiceOfferingVO serviceOfferingVO = serviceOfferingDao.findById(virtualMachineProfile.getId(), virtualMachineProfile.getServiceOfferingId()); + if (serviceOfferingVO.isDynamic()) { + serviceOfferingDao.loadDetails(serviceOfferingVO); + + maxMemory = getVmMaxMemory(serviceOfferingVO, vmDescription, maxHostMemory); + maxCpuCores = getVmMaxCpuCores(serviceOfferingVO, vmDescription, maxHostCpuCore); + } + + virtualMachineTo.setRam(minMemory, maxMemory); + virtualMachineTo.setCpus(minCpuCores); + virtualMachineTo.setVcpuMaxLimit(maxCpuCores); + } + + protected Pair getHostMaxMemoryAndCpuCores(HostVO host, VirtualMachine virtualMachine, String vmDescription){ + Long maxHostMemory = Long.MAX_VALUE; + Integer maxHostCpuCore = Integer.MAX_VALUE; + + if (host != null) { + return new Pair<>(host.getTotalMemory(), host.getCpus()); + } + + Long lastHostId = virtualMachine.getLastHostId(); + s_logger.info(String.format("%s is not running; therefore, we use the last host [%s] that the VM was running on to derive the unconstrained service offering max CPU and memory.", vmDescription, lastHostId)); + + HostVO lastHost = lastHostId == null ? null : _hostDao.findById(lastHostId); + if (lastHost != null) { + maxHostMemory = lastHost.getTotalMemory(); + maxHostCpuCore = lastHost.getCpus(); + s_logger.debug(String.format("Retrieved memory and cpu max values {\"memory\": %s, \"cpu\": %s} from %s last %s.", maxHostMemory, maxHostCpuCore, vmDescription, lastHost.toString())); + } else { + s_logger.warn(String.format("%s host [%s] and last host [%s] are null. Using 'Long.MAX_VALUE' [%s] and 'Integer.MAX_VALUE' [%s] as max memory and cpu cores.", vmDescription, virtualMachine.getHostId(), lastHostId, maxHostMemory, maxHostCpuCore)); + } + + return new Pair<>(maxHostMemory, maxHostCpuCore); + } + + protected Long getVmMaxMemory(ServiceOfferingVO serviceOfferingVO, String vmDescription, Long maxHostMemory) { + String serviceOfferingDescription = serviceOfferingVO.toString(); + + Long maxMemory; + Integer customOfferingMaxMemory = NumberUtils.createInteger(serviceOfferingVO.getDetail(ApiConstants.MAX_MEMORY)); + Integer maxMemoryConfig = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE.value(); + if (customOfferingMaxMemory != null) { + s_logger.debug(String.format("Using 'Custom unconstrained' %s max memory value [%sMb] as %s memory.", serviceOfferingDescription, customOfferingMaxMemory, vmDescription)); + maxMemory = ByteScaleUtils.mibToBytes(customOfferingMaxMemory); + } else { + String maxMemoryConfigKey = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE.key(); + + s_logger.info(String.format("%s is a 'Custom unconstrained' service offering. Using config [%s] value [%s] as max %s memory.", + serviceOfferingDescription, maxMemoryConfigKey, maxMemoryConfig, vmDescription)); + + if (maxMemoryConfig > 0) { + maxMemory = ByteScaleUtils.mibToBytes(maxMemoryConfig); + } else { + s_logger.info(String.format("Config [%s] has value less or equal '0'. Using %s host or last host max memory [%s] as VM max memory in the hypervisor.", maxMemoryConfigKey, vmDescription, maxHostMemory)); + maxMemory = maxHostMemory; + } + } + return maxMemory; + } + + protected Integer getVmMaxCpuCores(ServiceOfferingVO serviceOfferingVO, String vmDescription, Integer maxHostCpuCore) { + String serviceOfferingDescription = serviceOfferingVO.toString(); + + Integer maxCpuCores; + Integer customOfferingMaxCpuCores = NumberUtils.createInteger(serviceOfferingVO.getDetail(ApiConstants.MAX_CPU_NUMBER)); + Integer maxCpuCoresConfig = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES.value(); + + if (customOfferingMaxCpuCores != null) { + s_logger.debug(String.format("Using 'Custom unconstrained' %s max cpu cores [%s] as %s cpu cores.", serviceOfferingDescription, customOfferingMaxCpuCores, vmDescription)); + maxCpuCores = customOfferingMaxCpuCores; + } else { + String maxCpuCoreConfigKey = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES.key(); + + s_logger.info(String.format("%s is a 'Custom unconstrained' service offering. Using config [%s] value [%s] as max %s cpu cores.", + serviceOfferingDescription, maxCpuCoreConfigKey, maxCpuCoresConfig, vmDescription)); + + if (maxCpuCoresConfig > 0) { + maxCpuCores = maxCpuCoresConfig; + } else { + s_logger.info(String.format("Config [%s] has value less or equal '0'. Using %s host or last host max cpu cores [%s] as VM cpu cores in the hypervisor.", maxCpuCoreConfigKey, vmDescription, maxHostCpuCore)); + maxCpuCores = maxHostCpuCore; + } + } + return maxCpuCores; + } + @Override public Pair getCommandHostDelegation(long hostId, Command cmd) { if (cmd instanceof StorageSubSystemCommand) { diff --git a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java index a10e9379fd85..79a05f2c4dc7 100644 --- a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java +++ b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java @@ -17,11 +17,15 @@ package com.cloud.hypervisor; import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.configuration.ConfigurationManagerImpl; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.offering.ServiceOffering; import com.cloud.service.ServiceOfferingDetailsVO; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDetailsDao; +import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @@ -37,6 +41,9 @@ import java.io.UnsupportedEncodingException; import java.util.Arrays; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; +import org.junit.Assert; @RunWith(MockitoJUnitRunner.class) public class KVMGuruTest { @@ -65,6 +72,15 @@ public class KVMGuruTest { @Mock ServiceOfferingDetailsVO detail2; + @Mock + ServiceOfferingVO serviceOfferingVoMock; + + @Mock + VirtualMachine virtualMachineMock; + + @Mock + ServiceOfferingDao serviceOfferingDaoMock; + private static final long hostId = 1L; private static final Long offeringId = 1L; @@ -129,4 +145,161 @@ public void testSetVmQuotaPercentageOverProvision() { guru.setVmQuotaPercentage(vmTO, vmProfile); Mockito.verify(vmTO).setCpuQuotaPercentage(1d); } + + @Test + public void validateGetVmMaxMemoryReturnCustomOfferingMaxMemory(){ + int maxCustomOfferingMemory = 64; + Mockito.when(serviceOfferingVoMock.getDetail(ApiConstants.MAX_MEMORY)).thenReturn(String.valueOf(maxCustomOfferingMemory)); + + long result = guru.getVmMaxMemory(serviceOfferingVoMock, "Vm description", 1l); + + Assert.assertEquals(ByteScaleUtils.mibToBytes(maxCustomOfferingMemory), result); + } + + @Test + public void validateGetVmMaxMemoryReturnVmServiceOfferingMaxRAMSize(){ + int maxMemoryConfig = 64; + Mockito.when(serviceOfferingVoMock.getDetail(ApiConstants.MAX_MEMORY)).thenReturn(null); + + ConfigKey vmServiceOfferingMaxRAMSize = Mockito.mock(ConfigKey.class); + ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE = vmServiceOfferingMaxRAMSize; + + Mockito.when(vmServiceOfferingMaxRAMSize.value()).thenReturn(maxMemoryConfig); + long result = guru.getVmMaxMemory(serviceOfferingVoMock, "Vm description", 1l); + + Assert.assertEquals(ByteScaleUtils.mibToBytes(maxMemoryConfig), result); + } + + @Test + public void validateGetVmMaxMemoryReturnMaxHostMemory(){ + long maxHostMemory = ByteScaleUtils.mibToBytes(2000); + Mockito.when(serviceOfferingVoMock.getDetail(ApiConstants.MAX_MEMORY)).thenReturn(null); + + ConfigKey vmServiceOfferingMaxRAMSize = Mockito.mock(ConfigKey.class); + ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE = vmServiceOfferingMaxRAMSize; + + Mockito.when(vmServiceOfferingMaxRAMSize.value()).thenReturn(0); + + long result = guru.getVmMaxMemory(serviceOfferingVoMock, "Vm description", maxHostMemory); + + Assert.assertEquals(maxHostMemory, result); + } + + @Test + public void validateGetVmMaxCpuCoresReturnCustomOfferingMaxCpuCores(){ + int maxCustomOfferingCpuCores = 16; + Mockito.when(serviceOfferingVoMock.getDetail(ApiConstants.MAX_CPU_NUMBER)).thenReturn(String.valueOf(maxCustomOfferingCpuCores)); + + long result = guru.getVmMaxCpuCores(serviceOfferingVoMock, "Vm description", 1); + + Assert.assertEquals(maxCustomOfferingCpuCores, result); + } + + @Test + public void validateGetVmMaxCpuCoresVmServiceOfferingMaxCPUCores(){ + int maxCpuCoresConfig = 16; + Mockito.when(serviceOfferingVoMock.getDetail(ApiConstants.MAX_CPU_NUMBER)).thenReturn(null); + + ConfigKey vmServiceOfferingMaxCPUCores = Mockito.mock(ConfigKey.class); + ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES = vmServiceOfferingMaxCPUCores; + + Mockito.when(vmServiceOfferingMaxCPUCores.value()).thenReturn(maxCpuCoresConfig); + long result = guru.getVmMaxCpuCores(serviceOfferingVoMock, "Vm description", 1); + + Assert.assertEquals(maxCpuCoresConfig, result); + } + + @Test + public void validateGetVmMaxCpuCoresReturnMaxHostMemory(){ + int maxHostCpuCores = 64; + Mockito.when(serviceOfferingVoMock.getDetail(ApiConstants.MAX_CPU_NUMBER)).thenReturn(null); + + ConfigKey vmServiceOfferingMaxCPUCores = Mockito.mock(ConfigKey.class); + ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES = vmServiceOfferingMaxCPUCores; + + Mockito.when(vmServiceOfferingMaxCPUCores.value()).thenReturn(0); + + long result = guru.getVmMaxCpuCores(serviceOfferingVoMock, "Vm description", maxHostCpuCores); + + Assert.assertEquals(maxHostCpuCores, result); + } + + @Test + public void validateGetHostMaxMemoryAndCpuCoresHostNotNull(){ + Long maxMemory = 2048l; + Integer maxCpuCores = 16; + + Mockito.when(host.getTotalMemory()).thenReturn(maxMemory); + Mockito.when(host.getCpus()).thenReturn(maxCpuCores); + + Pair result = guru.getHostMaxMemoryAndCpuCores(host, virtualMachineMock, "Vm description"); + + Assert.assertEquals(new Pair<>(maxMemory, maxCpuCores), result); + } + + @Test + public void validateGetHostMaxMemoryAndCpuCoresHostNullAndLastHostIdNull(){ + Long maxMemory = Long.MAX_VALUE; + Integer maxCpuCores = Integer.MAX_VALUE; + + Pair result = guru.getHostMaxMemoryAndCpuCores(null, virtualMachineMock, "Vm description"); + + Assert.assertEquals(new Pair<>(maxMemory, maxCpuCores), result); + } + + @Test + public void validateGetHostMaxMemoryAndCpuCoresHostNullAndLastHostIdNotNullAndLastHostNull(){ + Long maxMemory = Long.MAX_VALUE; + Integer maxCpuCores = Integer.MAX_VALUE; + guru._hostDao = hostDao; + + Mockito.when(virtualMachineMock.getLastHostId()).thenReturn(1l); + Mockito.doReturn(null).when(hostDao).findById(Mockito.any()); + + Pair result = guru.getHostMaxMemoryAndCpuCores(null, virtualMachineMock, "Vm description"); + + Assert.assertEquals(new Pair<>(maxMemory, maxCpuCores), result); + } + + @Test + public void validateGetHostMaxMemoryAndCpuCoresHostNullAndLastHostIdNotNullAndLastHostNotNull(){ + Long maxMemory = 2048l; + Integer maxCpuCores = 16; + guru._hostDao = hostDao; + + Mockito.when(virtualMachineMock.getLastHostId()).thenReturn(1l); + Mockito.doReturn(host).when(hostDao).findById(Mockito.any()); + Mockito.when(host.getTotalMemory()).thenReturn(maxMemory); + Mockito.when(host.getCpus()).thenReturn(maxCpuCores); + + Pair result = guru.getHostMaxMemoryAndCpuCores(null, virtualMachineMock, "Vm description"); + + Assert.assertEquals(new Pair<>(maxMemory, maxCpuCores), result); + } + + @Test + public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsDynamicCallGetMethods(){ + guru.serviceOfferingDao = serviceOfferingDaoMock; + + Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findById(Mockito.anyLong(), Mockito.anyLong()); + Mockito.doReturn(true).when(serviceOfferingVoMock).isDynamic(); + + guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile); + + Mockito.verify(guru).getVmMaxMemory(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyLong()); + Mockito.verify(guru).getVmMaxCpuCores(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyInt()); + } + + @Test + public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsNotDynamicDoNotCallGetMethods(){ + guru.serviceOfferingDao = serviceOfferingDaoMock; + + Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findById(Mockito.anyLong(), Mockito.anyLong()); + Mockito.doReturn(false).when(serviceOfferingVoMock).isDynamic(); + + guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile); + + Mockito.verify(guru, Mockito.never()).getVmMaxMemory(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyLong()); + Mockito.verify(guru, Mockito.never()).getVmMaxCpuCores(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyInt()); + } } \ No newline at end of file From 8e5632d8eacc9b49b6a95d2af412622c01890bc2 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 17:56:55 -0300 Subject: [PATCH 07/38] Extract dpdk configuration to a method and test it --- .../java/com/cloud/hypervisor/KVMGuru.java | 24 +++++----- .../com/cloud/hypervisor/KVMGuruTest.java | 44 +++++++++++++++++++ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java index f26a1fab1c24..ea496a7a4ad7 100644 --- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java +++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java @@ -121,16 +121,7 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { VirtualMachineTO to = toVirtualMachineTO(vm); setVmQuotaPercentage(to, vm); - if (dpdkHelper.isDpdkvHostUserModeSettingOnServiceOffering(vm)) { - dpdkHelper.setDpdkVhostUserMode(to, vm); - } - - if (to.getType() == VirtualMachine.Type.User && MapUtils.isNotEmpty(to.getExtraConfig()) && - to.getExtraConfig().containsKey(DpdkHelper.DPDK_NUMA) && to.getExtraConfig().containsKey(DpdkHelper.DPDK_HUGE_PAGES)) { - for (final NicTO nic : to.getNics()) { - nic.setDpdkEnabled(true); - } - } + enableDpdkIfNeeded(vm, to); // Determine the VM's OS description GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId()); @@ -152,6 +143,19 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { return to; } + protected void enableDpdkIfNeeded(VirtualMachineProfile virtualMachineProfile, VirtualMachineTO virtualMachineTo) { + if (dpdkHelper.isDpdkvHostUserModeSettingOnServiceOffering(virtualMachineProfile)) { + dpdkHelper.setDpdkVhostUserMode(virtualMachineTo, virtualMachineProfile); + } + + if (virtualMachineTo.getType() == VirtualMachine.Type.User && MapUtils.isNotEmpty(virtualMachineTo.getExtraConfig()) && + virtualMachineTo.getExtraConfig().containsKey(DpdkHelper.DPDK_NUMA) && virtualMachineTo.getExtraConfig().containsKey(DpdkHelper.DPDK_HUGE_PAGES)) { + for (final NicTO nic : virtualMachineTo.getNics()) { + nic.setDpdkEnabled(true); + } + } + } + protected void configureVmMemoryAndCpuCores(VirtualMachineTO virtualMachineTo, HostVO hostVo, VirtualMachine virtualMachine, VirtualMachineProfile virtualMachineProfile) { String vmDescription = virtualMachineTo.toString(); diff --git a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java index 79a05f2c4dc7..385834ee549b 100644 --- a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java +++ b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java @@ -16,10 +16,12 @@ // under the License. package com.cloud.hypervisor; +import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.configuration.ConfigurationManagerImpl; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.kvm.dpdk.DpdkHelper; import com.cloud.offering.ServiceOffering; import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.service.ServiceOfferingVO; @@ -41,6 +43,8 @@ import java.io.UnsupportedEncodingException; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; import org.junit.Assert; @@ -81,6 +85,9 @@ public class KVMGuruTest { @Mock ServiceOfferingDao serviceOfferingDaoMock; + @Mock + DpdkHelper dpdkHelperMock; + private static final long hostId = 1L; private static final Long offeringId = 1L; @@ -302,4 +309,41 @@ public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsNotDynamicDoNot Mockito.verify(guru, Mockito.never()).getVmMaxMemory(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyLong()); Mockito.verify(guru, Mockito.never()).getVmMaxCpuCores(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyInt()); } + + @Test + public void validateEnableDpdkIfNeededCallDpdkHelperSetDpdkVhostUserMode() { + Mockito.when(dpdkHelperMock.isDpdkvHostUserModeSettingOnServiceOffering(vmProfile)).thenReturn(Boolean.TRUE); + guru.enableDpdkIfNeeded(vmProfile, vmTO); + Mockito.verify(dpdkHelperMock).setDpdkVhostUserMode(vmTO, vmProfile); + } + + @Test + public void validateEnableDpdkIfNeededDoNotCallDpdkHelperSetDpdkVhostUserMode() { + Mockito.when(dpdkHelperMock.isDpdkvHostUserModeSettingOnServiceOffering(vmProfile)).thenReturn(Boolean.FALSE); + guru.enableDpdkIfNeeded(vmProfile, vmTO); + Mockito.verify(dpdkHelperMock, Mockito.times(0)).setDpdkVhostUserMode(vmTO, vmProfile); + } + + @Test + public void validateEnableDpdkIfNeededNicSetDpdkEnabledTrue() { + Map map = new HashMap<>(); + map.put(DpdkHelper.DPDK_NUMA, "test1"); + map.put(DpdkHelper.DPDK_HUGE_PAGES, "test2"); + + NicTO nicTo1 = Mockito.mock(NicTO.class); + NicTO nicTo2 = Mockito.mock(NicTO.class); + NicTO nicTo3 = Mockito.mock(NicTO.class); + + NicTO[] nics = {nicTo1, nicTo2, nicTo3}; + + Mockito.when(vmTO.getType()).thenReturn(VirtualMachine.Type.User); + Mockito.when(vmTO.getExtraConfig()).thenReturn(map); + Mockito.when(vmTO.getNics()).thenReturn(nics); + + guru.enableDpdkIfNeeded(vmProfile, vmTO); + + for (NicTO nic : nics) { + Mockito.verify(nic).setDpdkEnabled(true); + } + } } \ No newline at end of file From e970e335ce427ffac371fefd82eb0e6aeca00fe9 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 18:54:15 -0300 Subject: [PATCH 08/38] Extract OS desc config to a method and test it --- .../java/com/cloud/hypervisor/KVMGuru.java | 30 +++--- .../com/cloud/hypervisor/KVMGuruTest.java | 92 +++++++++++++++++++ 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java index ea496a7a4ad7..5a6a92e4f89f 100644 --- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java +++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java @@ -123,24 +123,32 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { enableDpdkIfNeeded(vm, to); - // Determine the VM's OS description - GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId()); - to.setOs(guestOS.getDisplayName()); VirtualMachine virtualMachine = vm.getVirtualMachine(); Long hostId = virtualMachine.getHostId(); HostVO host = hostId == null ? null : _hostDao.findById(hostId); + + // Determine the VM's OS description + configureVmOsDescription(virtualMachine, to, host); + + configureVmMemoryAndCpuCores(to, host, virtualMachine, vm); + return to; + } + + protected void configureVmOsDescription(VirtualMachine virtualMachine, VirtualMachineTO virtualMachineTo, HostVO hostVo) { + GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(virtualMachine.getGuestOSId()); + String guestOsDisplayName = guestOS.getDisplayName(); + virtualMachineTo.setOs(guestOsDisplayName); GuestOSHypervisorVO guestOsMapping = null; - if (host != null) { - guestOsMapping = _guestOsHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), getHypervisorType().toString(), host.getHypervisorVersion()); + + if (hostVo != null) { + guestOsMapping = _guestOsHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), getHypervisorType().toString(), hostVo.getHypervisorVersion()); } - if (guestOsMapping == null || host == null) { - to.setPlatformEmulator(guestOS.getDisplayName() == null ? "Other" : guestOS.getDisplayName()); + + if (guestOsMapping == null || hostVo == null) { + virtualMachineTo.setPlatformEmulator(guestOsDisplayName == null ? "Other" : guestOsDisplayName); } else { - to.setPlatformEmulator(guestOsMapping.getGuestOsName()); + virtualMachineTo.setPlatformEmulator(guestOsMapping.getGuestOsName()); } - - configureVmMemoryAndCpuCores(to, host, virtualMachine, vm); - return to; } protected void enableDpdkIfNeeded(VirtualMachineProfile virtualMachineProfile, VirtualMachineTO virtualMachineTo) { diff --git a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java index 385834ee549b..469551a55bfb 100644 --- a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java +++ b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java @@ -27,6 +27,10 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDetailsDao; +import com.cloud.storage.GuestOSHypervisorVO; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.GuestOSHypervisorDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; @@ -88,6 +92,18 @@ public class KVMGuruTest { @Mock DpdkHelper dpdkHelperMock; + @Mock + GuestOSVO guestOsVoMock; + + @Mock + GuestOSHypervisorVO guestOsMappingMock; + + @Mock + GuestOSHypervisorDao guestOSHypervisorDaoMock; + + @Mock + GuestOSDao guestOsDaoMock; + private static final long hostId = 1L; private static final Long offeringId = 1L; @@ -346,4 +362,80 @@ public void validateEnableDpdkIfNeededNicSetDpdkEnabledTrue() { Mockito.verify(nic).setDpdkEnabled(true); } } + + @Test + public void ConfigureVmOsDescription(){ + guru._guestOsDao = guestOsDaoMock; + guru._guestOsHypervisorDao = guestOSHypervisorDaoMock; + + VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {}; + String platformEmulator = "Ubuntu"; + + Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any()); + Mockito.doReturn(guestOsMappingMock).when(guestOSHypervisorDaoMock).findByOsIdAndHypervisor(Mockito.anyLong(), Mockito.anyString(), Mockito.any()); + Mockito.doReturn(platformEmulator).when(guestOsMappingMock).getGuestOsName(); + + guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host); + + Assert.assertEquals(platformEmulator, virtualMachineTo.getPlatformEmulator()); + } + + @Test + public void validateVirtualMachineSetPlatformEmulatorHostNotNullAndGuestOsMappingNullAndGuestOsDisplayNameNull(){ + guru._guestOsDao = guestOsDaoMock; + guru._guestOsHypervisorDao = guestOSHypervisorDaoMock; + + VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {}; + + Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any()); + Mockito.doReturn(null).when(guestOSHypervisorDaoMock).findByOsIdAndHypervisor(Mockito.anyLong(), Mockito.anyString(), Mockito.any()); + + guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host); + + Assert.assertEquals("Other", virtualMachineTo.getPlatformEmulator()); + } + + @Test + public void validateVirtualMachineSetPlatformEmulatorHostNotNullAndGuestOsMappingNullAndGuestOsDisplayNameNotNull(){ + guru._guestOsDao = guestOsDaoMock; + guru._guestOsHypervisorDao = guestOSHypervisorDaoMock; + + VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {}; + String platformEmulator = "Ubuntu"; + + Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any()); + Mockito.doReturn(null).when(guestOSHypervisorDaoMock).findByOsIdAndHypervisor(Mockito.anyLong(), Mockito.anyString(), Mockito.any()); + Mockito.doReturn(platformEmulator).when(guestOsVoMock).getDisplayName(); + + guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host); + + Assert.assertEquals(platformEmulator, virtualMachineTo.getPlatformEmulator()); + } + + @Test + public void validateVirtualMachineSetPlatformEmulatorHostNullAndGuestOsMappingNullAndGuestOsDisplayNameNull(){ + guru._guestOsDao = guestOsDaoMock; + VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {}; + + Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any()); + guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host); + + Assert.assertEquals("Other", virtualMachineTo.getPlatformEmulator()); + } + + @Test + public void validateVirtualMachineSetPlatformEmulatorHostNullAndGuestOsMappingNullAndGuestOsDisplayNameNotNull(){ + guru._guestOsDao = guestOsDaoMock; + + VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {}; + String platformEmulator = "Ubuntu"; + + Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any()); + Mockito.doReturn(platformEmulator).when(guestOsVoMock).getDisplayName(); + + guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host); + + Assert.assertEquals(platformEmulator, virtualMachineTo.getPlatformEmulator()); + } + } \ No newline at end of file From 95d7e91d97ba05c955f1010a26450326c84659e2 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 24 Mar 2021 19:12:01 -0300 Subject: [PATCH 09/38] Extract guest resource def to a method and test it Improve libvirt def --- .../resource/LibvirtComputingResource.java | 43 +++++++++++---- .../hypervisor/kvm/resource/LibvirtVMDef.java | 36 +++++++------ .../LibvirtComputingResourceTest.java | 54 +++++++++++++++++++ 3 files changed, 105 insertions(+), 28 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 00f705195bbc..500a3929f78c 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -183,6 +183,7 @@ import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VmDetailConstants; import com.google.common.base.Strings; +import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; /** * LibvirtComputingResource execute requests on the computing/routing host using @@ -2306,19 +2307,11 @@ public LibvirtVMDef createVMFromSpec(final VirtualMachineTO vmTO) { vm.addComp(guest); - final GuestResourceDef grd = new GuestResourceDef(); - - if (vmTO.getMinRam() != vmTO.getMaxRam() && !_noMemBalloon) { - grd.setMemBalloning(true); - grd.setCurrentMem(vmTO.getMinRam() / 1024); - grd.setMemorySize(vmTO.getMaxRam() / 1024); - } else { - grd.setMemorySize(vmTO.getMaxRam() / 1024); - } - final int vcpus = vmTO.getCpus(); - grd.setVcpuNum(vcpus); + GuestResourceDef grd = createGuestResourceDef(vmTO); vm.addComp(grd); + int vcpus = grd.getVcpu(); + if (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA)) { final CpuModeDef cmd = new CpuModeDef(); cmd.setMode(_guestCpuMode); @@ -2446,6 +2439,34 @@ So if getMinSpeed() returns null we fall back to getSpeed(). return vm; } + protected GuestResourceDef createGuestResourceDef(VirtualMachineTO vmTO){ + GuestResourceDef grd = new GuestResourceDef(); + + grd.setMemBalloning(!_noMemBalloon); + + Long maxRam = ByteScaleUtils.bytesToKib(vmTO.getMaxRam()); + + grd.setMemorySize(maxRam); + grd.setCurrentMem(getCurrentMemAccordingToMemBallooning(vmTO, maxRam)); + + int vcpus = vmTO.getCpus(); + Integer maxVcpus = vmTO.getVcpuMaxLimit(); + + grd.setVcpuNum(vcpus); + grd.setMaxVcpuNum(maxVcpus == null ? vcpus : maxVcpus); + + return grd; + } + + protected long getCurrentMemAccordingToMemBallooning(VirtualMachineTO vmTO, long maxRam) { + if (_noMemBalloon) { + s_logger.warn(String.format("Setting VM's [%s] current memory as max memory [%s] due to memory ballooning is disabled. If you are using a custom service offering, verify if memory ballooning really should be disabled.", vmTO.toString(), maxRam)); + return maxRam; + } else { + return ByteScaleUtils.bytesToKib(vmTO.getMinRam()); + } + } + /** * Add extra configurations (if any) as a String component to the domain XML */ diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 1927ddd3569f..0930c665fcd1 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -234,6 +234,7 @@ public static class GuestResourceDef { private long _currentMem = -1; private String _memBacking; private int _vcpu = -1; + private int maxVcpu = -1; private boolean _memBalloning = false; public void setMemorySize(long mem) { @@ -252,29 +253,30 @@ public void setVcpuNum(int vcpu) { _vcpu = vcpu; } + public void setMaxVcpuNum(int maxVcpu) { + this.maxVcpu = maxVcpu; + } + + public int getVcpu() { + return _vcpu; + } + + public int getMaxVcpu() { + return maxVcpu; + } + public void setMemBalloning(boolean turnon) { _memBalloning = turnon; } @Override public String toString() { - StringBuilder resBuidler = new StringBuilder(); - resBuidler.append("" + _mem + "\n"); - if (_currentMem != -1) { - resBuidler.append("" + _currentMem + "\n"); - } - if (_memBacking != null) { - resBuidler.append("" + "<" + _memBacking + "/>" + "\n"); - } - if (_memBalloning) { - resBuidler.append("\n" + "\n" + "\n"); - } else { - resBuidler.append("\n" + "\n" + "\n"); - } - if (_vcpu != -1) { - resBuidler.append("" + _vcpu + "\n"); - } - return resBuidler.toString(); + StringBuilder response = new StringBuilder(); + response.append(String.format("%s\n", this._mem)); + response.append(String.format("%s\n", this._currentMem)); + response.append(String.format("\n\n\n", this._memBalloning ? "virtio" : "none")); + response.append(String.format("%s\n", this._vcpu, this.maxVcpu)); + return response.toString(); } } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 84d08531c2bf..6ad530c2386b 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -189,6 +189,7 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.Type; +import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; @RunWith(PowerMockRunner.class) @PrepareForTest(value = {MemStat.class}) @@ -5209,4 +5210,57 @@ public void testAddExtraConfigComponentNotEmptyExtraConfig() { libvirtComputingResource.addExtraConfigComponent(extraConfig, vmDef); Mockito.verify(vmDef, times(1)).addComp(any()); } + + @Test + public void validateGetCurrentMemAccordingToMemBallooningWithoutMemBalooning(){ + VirtualMachineTO vmTo = Mockito.mock(VirtualMachineTO.class); + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + libvirtComputingResource._noMemBalloon = true; + long maxMemory = 2048; + + long currentMemory = libvirtComputingResource.getCurrentMemAccordingToMemBallooning(vmTo, maxMemory); + Assert.assertEquals(maxMemory, currentMemory); + Mockito.verify(vmTo, Mockito.times(0)).getMinRam(); + } + + @Test + public void validateGetCurrentMemAccordingToMemBallooningWithtMemBalooning(){ + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + libvirtComputingResource._noMemBalloon = false; + + long maxMemory = 2048; + long minMemory = ByteScaleUtils.mibToBytes(64); + + VirtualMachineTO vmTo = Mockito.mock(VirtualMachineTO.class); + Mockito.when(vmTo.getMinRam()).thenReturn(minMemory); + + long currentMemory = libvirtComputingResource.getCurrentMemAccordingToMemBallooning(vmTo, maxMemory); + Assert.assertEquals(ByteScaleUtils.bytesToKib(minMemory), currentMemory); + Mockito.verify(vmTo).getMinRam(); + } + + @Test + public void validateCreateGuestResourceDefWithVcpuMaxLimit(){ + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + VirtualMachineTO vmTo = Mockito.mock(VirtualMachineTO.class); + int maxCpu = 16; + + Mockito.when(vmTo.getVcpuMaxLimit()).thenReturn(maxCpu); + + LibvirtVMDef.GuestResourceDef grd = libvirtComputingResource.createGuestResourceDef(vmTo); + Assert.assertEquals(maxCpu, grd.getMaxVcpu()); + } + + @Test + public void validateCreateGuestResourceDefWithVcpuMaxLimitAsNull(){ + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + VirtualMachineTO vmTo = Mockito.mock(VirtualMachineTO.class); + int min = 1; + + Mockito.when(vmTo.getCpus()).thenReturn(min); + Mockito.when(vmTo.getVcpuMaxLimit()).thenReturn(null); + + LibvirtVMDef.GuestResourceDef grd = libvirtComputingResource.createGuestResourceDef(vmTo); + Assert.assertEquals(min, grd.getMaxVcpu()); + } } From b4587c9267bc5987166f2daf3b231bc025e3ccec Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Fri, 26 Mar 2021 14:33:49 -0300 Subject: [PATCH 10/38] Refactor LibvirtVMDef.GuestResourceDef --- .../hypervisor/kvm/resource/LibvirtVMDef.java | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 0930c665fcd1..bbab5c05ba0f 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -230,27 +230,22 @@ public String toString() { } public static class GuestResourceDef { - private long _mem; - private long _currentMem = -1; - private String _memBacking; - private int _vcpu = -1; + private long memory; + private long currentMemory = -1; + private int vcpu = -1; private int maxVcpu = -1; - private boolean _memBalloning = false; + private boolean memoryBalloning = false; public void setMemorySize(long mem) { - _mem = mem; + this.memory = mem; } public void setCurrentMem(long currMem) { - _currentMem = currMem; - } - - public void setMemBacking(String memBacking) { - _memBacking = memBacking; + this.currentMemory = currMem; } public void setVcpuNum(int vcpu) { - _vcpu = vcpu; + this.vcpu = vcpu; } public void setMaxVcpuNum(int maxVcpu) { @@ -258,24 +253,24 @@ public void setMaxVcpuNum(int maxVcpu) { } public int getVcpu() { - return _vcpu; + return vcpu; } public int getMaxVcpu() { return maxVcpu; } - public void setMemBalloning(boolean turnon) { - _memBalloning = turnon; + public void setMemBalloning(boolean memoryBalloning) { + this.memoryBalloning = memoryBalloning; } @Override public String toString() { StringBuilder response = new StringBuilder(); - response.append(String.format("%s\n", this._mem)); - response.append(String.format("%s\n", this._currentMem)); - response.append(String.format("\n\n\n", this._memBalloning ? "virtio" : "none")); - response.append(String.format("%s\n", this._vcpu, this.maxVcpu)); + response.append(String.format("%s\n", this.memory)); + response.append(String.format("%s\n", this.currentMemory)); + response.append(String.format("\n\n\n", this.memoryBalloning ? "virtio" : "none")); + response.append(String.format("%s\n", this.vcpu, this.maxVcpu)); return response.toString(); } } From e9e2149dbbcc577af443e99fcb7bf5f5e1266536 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Fri, 26 Mar 2021 14:34:04 -0300 Subject: [PATCH 11/38] Refactor ScaleVmCommand --- core/src/main/java/com/cloud/agent/api/ScaleVmCommand.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/main/java/com/cloud/agent/api/ScaleVmCommand.java b/core/src/main/java/com/cloud/agent/api/ScaleVmCommand.java index 1c763dd05dd9..dc63b1ee746d 100644 --- a/core/src/main/java/com/cloud/agent/api/ScaleVmCommand.java +++ b/core/src/main/java/com/cloud/agent/api/ScaleVmCommand.java @@ -52,9 +52,6 @@ public ScaleVmCommand(String vmName, int cpus, Integer minSpeed, Integer maxSpee this.minRam = minRam; this.maxRam = maxRam; this.vm = new VirtualMachineTO(1L, vmName, null, cpus, minSpeed, maxSpeed, minRam, maxRam, null, null, false, limitCpuUse, null); - /*vm.setName(vmName); - vm.setCpus(cpus); - vm.setRam(minRam, maxRam);*/ } public void setCpus(int cpus) { From 52c6a4bf534b707895ca595d648b986d7e1f4432 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Fri, 26 Mar 2021 15:03:45 -0300 Subject: [PATCH 12/38] Improve VMInstaVO toString() --- engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java b/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java index 0e8dd4ee44a5..809f656f3825 100644 --- a/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java +++ b/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java @@ -506,7 +506,7 @@ public void setRemoved(Date removed) { @Override public String toString() { - return String.format("VM instance {\"id\": \"%s\", \"name\": \"%s\", \"uuid\": \"%s\", \"type\"=\"%s\"}", id, getInstanceName(), uuid, type); + return String.format("VM {\"id\": %s, \"name\": \"%s\", \"uuid\": \"%s\", \"type\": \"%s\"}", getId(), getInstanceName(), getUuid(), getType()); } @Override From 0c61e01bece58dfc21127ee767032bf2378ae484 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Fri, 26 Mar 2021 15:04:04 -0300 Subject: [PATCH 13/38] Refactor upgradeRunningVirtualMachine method --- .../java/com/cloud/vm/UserVmManagerImpl.java | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 9b070d82963d..a721de1a03e6 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -342,6 +342,7 @@ import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; import java.util.HashSet; +import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; public class UserVmManagerImpl extends ManagerBase implements UserVmManager, VirtualMachineGuru, UserVmService, Configurable { private static final Logger s_logger = Logger.getLogger(UserVmManagerImpl.class); @@ -1879,8 +1880,9 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI supportedHypervisorTypes.add(HypervisorType.KVM); if (!supportedHypervisorTypes.contains(vmInstance.getHypervisorType())) { - s_logger.info("Scaling the VM dynamically is not supported for VMs running on Hypervisor "+vmInstance.getHypervisorType()); - throw new InvalidParameterValueException("Scaling the VM dynamically is not supported for VMs running on Hypervisor "+vmInstance.getHypervisorType()); + String message = String.format("Scaling the VM dynamically is not supported for VMs running on Hypervisor [%s].", vmInstance.getHypervisorType()); + s_logger.info(message); + throw new InvalidParameterValueException(message); } _accountMgr.checkAccess(caller, null, true, vmInstance); @@ -1908,9 +1910,11 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI // Don't allow to scale when (Any of the new values less than current values) OR (All current and new values are same) if ((newSpeed < currentSpeed || newMemory < currentMemory || newCpu < currentCpu) || (newSpeed == currentSpeed && newMemory == currentMemory && newCpu == currentCpu)) { - throw new InvalidParameterValueException("Only scaling up the vm is supported, new service offering(speed=" + newSpeed + ",cpu=" + newCpu + ",memory=," + newMemory - + ")" + " should have at least one value(cpu/ram) greater than old value and no resource value less than older(speed=" + currentSpeed + ",cpu=" + currentCpu - + ",memory=," + currentMemory + ")"); + String message = String.format("While the VM is running, only scalling up it is supported. New service offering {\"memory\": %s, \"speed\": %s, \"cpu\": %s} should" + + " have at least one value (ram, speed or cpu) greater than the current values {\"memory\": %s, \"speed\": %s, \"cpu\": %s}.", newMemory, newSpeed, newCpu, + currentMemory, currentSpeed, currentCpu); + + throw new InvalidParameterValueException(message); } _offeringDao.loadDetails(currentServiceOffering); @@ -1920,18 +1924,18 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI Map newDetails = newServiceOffering.getDetails(); String currentVgpuType = currentDetails.get("vgpuType"); String newVgpuType = newDetails.get("vgpuType"); - if(currentVgpuType != null) { - if(newVgpuType == null || !newVgpuType.equalsIgnoreCase(currentVgpuType)) { - throw new InvalidParameterValueException("Dynamic scaling of vGPU type is not supported. VM has vGPU Type: " + currentVgpuType); - } + + if (currentVgpuType != null && (newVgpuType == null || !newVgpuType.equalsIgnoreCase(currentVgpuType))) { + throw new InvalidParameterValueException(String.format("Dynamic scaling of vGPU type is not supported. VM has vGPU Type: [%s].", currentVgpuType)); } // Check resource limits if (newCpu > currentCpu) { _resourceLimitMgr.checkResourceLimit(caller, ResourceType.cpu, newCpu - currentCpu); } + if (newMemory > currentMemory) { - _resourceLimitMgr.checkResourceLimit(caller, ResourceType.memory, newMemory - currentMemory); + _resourceLimitMgr.checkResourceLimit(caller, ResourceType.memory, memoryDiff); } // Dynamically upgrade the running vms @@ -1943,18 +1947,18 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI // Check zone wide flag boolean enableDynamicallyScaleVm = EnableDynamicallyScaleVm.valueIn(vmInstance.getDataCenterId()); if (!enableDynamicallyScaleVm) { - throw new PermissionDeniedException("Dynamically scaling virtual machines is disabled for this zone, please contact your admin"); + throw new PermissionDeniedException("Dynamically scaling virtual machines is disabled for this zone, please contact your admin."); } // Check vm flag if (!vmInstance.isDynamicallyScalable()) { - throw new CloudRuntimeException("Unable to Scale the vm: " + vmInstance.getUuid() + " as vm does not have tools to support dynamic scaling"); + throw new CloudRuntimeException(String.format("Unable to scale %s as it does not have tools to support dynamic scaling.", vmInstance.toString())); } // Check disable threshold for cluster is not crossed HostVO host = _hostDao.findById(vmInstance.getHostId()); if (_capacityMgr.checkIfClusterCrossesThreshold(host.getClusterId(), cpuDiff, memoryDiff)) { - throw new CloudRuntimeException("Unable to scale vm: " + vmInstance.getUuid() + " due to insufficient resources"); + throw new CloudRuntimeException(String.format("Unable to scale %s due to insufficient resources.", vmInstance.toString())); } while (retry-- != 0) { // It's != so that it can match -1. @@ -1973,7 +1977,7 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI // #1 Check existing host has capacity if (!excludes.shouldAvoid(ApiDBUtils.findHostById(vmInstance.getHostId()))) { existingHostHasCapacity = _capacityMgr.checkIfHostHasCpuCapability(vmInstance.getHostId(), newCpu, newSpeed) - && _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), cpuDiff, (memoryDiff) * 1024L * 1024L, false, + && _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), cpuDiff, ByteScaleUtils.mibToBytes(memoryDiff), false, _capacityMgr.getClusterOverProvisioningFactor(host.getClusterId(), Capacity.CAPACITY_TYPE_CPU), _capacityMgr.getClusterOverProvisioningFactor(host.getClusterId(), Capacity.CAPACITY_TYPE_MEMORY), false); excludes.addHost(vmInstance.getHostId()); @@ -1990,9 +1994,7 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI success = true; return success; } catch (InsufficientCapacityException | ResourceUnavailableException | ConcurrentOperationException e) { - s_logger.warn("Received exception while scaling ", e); - } catch (Exception e) { - s_logger.warn("Scaling failed with exception: ", e); + s_logger.error(String.format("Unable to scale %s due to [%s].", vmInstance.toString(), e.getMessage()), e); } finally { if (!success) { // Decrement CPU and Memory count accordingly. From 04fc8a4496401de73b7a7dddc62ba646595ce353 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 31 Mar 2021 09:26:47 -0300 Subject: [PATCH 14/38] Turn int variables into long on utility --- .../utils/bytescale/ByteScaleUtils.java | 8 +++---- .../utils/bytescale/ByteScaleUtilsTest.java | 23 +++++++++++++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java b/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java index aadfe74fef80..fed31cad2253 100644 --- a/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java +++ b/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java @@ -22,18 +22,18 @@ */ public class ByteScaleUtils { - public static final int KiB = 1024; - public static final int MiB = KiB * 1024; + public static final long KiB = 1024; + public static final long MiB = KiB * 1024; private ByteScaleUtils() {} /** * Converts mebibytes to bytes. * - * @param mib The integer value to convert to bytes (eq: 1, 2, 3, ..., 42,...). + * @param mib The value to convert to bytes (eq: 1, 2, 3, ..., 42,...). * @return The parameter multiplied by 1048576 (1024 * 1024, 1 MiB). */ - public static long mibToBytes(int mib) { + public static long mibToBytes(long mib) { return mib * MiB; } diff --git a/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java b/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java index 02128b5a3d35..13138dace5d6 100644 --- a/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java +++ b/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java @@ -26,15 +26,28 @@ public class ByteScaleUtilsTest extends TestCase { @Test public void validateMibToBytes() { - int mib = 3; - int b = 1024 * 1024 * mib; + long mib = 3000L; + long b = 1024L * 1024L * mib; assertEquals(b, ByteScaleUtils.mibToBytes(mib)); } @Test public void validateBytesToKib() { - int kib = 1024 * 3; - int b = 1024 * kib; + long kib = 1024L * 3000L; + long b = 1024 * kib; assertEquals(kib, ByteScaleUtils.bytesToKib(b)); } -} \ No newline at end of file + + @Test + public void validateMibToBytesIfIntTimesIntThenMustExtrapolateIntMaxValue() { + int mib = 3000; + long b = 1024L * 1024L * mib; + assertEquals(b, ByteScaleUtils.mibToBytes(mib)); + } + + @Test + public void validateBytesToKibIfIntByIntThenMustExtrapolateIntMaxValue(){ + int b = Integer.MAX_VALUE; + assertEquals(b, ByteScaleUtils.bytesToKib(b * 1024L)); + } +} From 6c157a4c08be4545361a30398581d27ce497e2b3 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 31 Mar 2021 15:54:06 -0300 Subject: [PATCH 15/38] Verify if VM is scalable on KVMGuru --- .../java/com/cloud/hypervisor/KVMGuru.java | 2 +- .../com/cloud/hypervisor/KVMGuruTest.java | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java index 5a6a92e4f89f..45f3ee0ba510 100644 --- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java +++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java @@ -178,7 +178,7 @@ protected void configureVmMemoryAndCpuCores(VirtualMachineTO virtualMachineTo, H Integer maxCpuCores = minCpuCores; ServiceOfferingVO serviceOfferingVO = serviceOfferingDao.findById(virtualMachineProfile.getId(), virtualMachineProfile.getServiceOfferingId()); - if (serviceOfferingVO.isDynamic()) { + if (serviceOfferingVO.isDynamic() && virtualMachineTo.isEnableDynamicallyScaleVm()) { serviceOfferingDao.loadDetails(serviceOfferingVO); maxMemory = getVmMaxMemory(serviceOfferingVO, vmDescription, maxHostMemory); diff --git a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java index 469551a55bfb..d17833aa8128 100644 --- a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java +++ b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java @@ -301,11 +301,12 @@ public void validateGetHostMaxMemoryAndCpuCoresHostNullAndLastHostIdNotNullAndLa } @Test - public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsDynamicCallGetMethods(){ + public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsDynamicAndVmIsDynamicCallGetMethods(){ guru.serviceOfferingDao = serviceOfferingDaoMock; Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findById(Mockito.anyLong(), Mockito.anyLong()); Mockito.doReturn(true).when(serviceOfferingVoMock).isDynamic(); + Mockito.doReturn(true).when(vmTO).isEnableDynamicallyScaleVm(); guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile); @@ -314,11 +315,26 @@ public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsDynamicCallGetM } @Test - public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsNotDynamicDoNotCallGetMethods(){ + public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsNotDynamicAndVmIsDynamicDoNotCallGetMethods(){ guru.serviceOfferingDao = serviceOfferingDaoMock; Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findById(Mockito.anyLong(), Mockito.anyLong()); Mockito.doReturn(false).when(serviceOfferingVoMock).isDynamic(); + Mockito.lenient().doReturn(true).when(vmTO).isEnableDynamicallyScaleVm(); + + guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile); + + Mockito.verify(guru, Mockito.never()).getVmMaxMemory(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyLong()); + Mockito.verify(guru, Mockito.never()).getVmMaxCpuCores(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyInt()); + } + + @Test + public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsDynamicAndVmIsNotDynamicDoNotCallGetMethods(){ + guru.serviceOfferingDao = serviceOfferingDaoMock; + + Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findById(Mockito.anyLong(), Mockito.anyLong()); + Mockito.doReturn(true).when(serviceOfferingVoMock).isDynamic(); + Mockito.doReturn(false).when(vmTO).isEnableDynamicallyScaleVm(); guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile); From 45d5d2d57bc0c5f9b02fed1767662e9e05336475 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 31 Mar 2021 15:57:45 -0300 Subject: [PATCH 16/38] Rename some KVMGuruTest's methods --- .../test/java/com/cloud/hypervisor/KVMGuruTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java index d17833aa8128..16dfcd034382 100644 --- a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java +++ b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java @@ -379,8 +379,8 @@ public void validateEnableDpdkIfNeededNicSetDpdkEnabledTrue() { } } - @Test - public void ConfigureVmOsDescription(){ + @Test + public void validateConfigureVmOsDescriptionHostNotNullAndGuestOsMappingNotNullAndGuestOsDisplayNameNotNull(){ guru._guestOsDao = guestOsDaoMock; guru._guestOsHypervisorDao = guestOSHypervisorDaoMock; @@ -397,7 +397,7 @@ public void ConfigureVmOsDescription(){ } @Test - public void validateVirtualMachineSetPlatformEmulatorHostNotNullAndGuestOsMappingNullAndGuestOsDisplayNameNull(){ + public void validateConfigureVmOsDescriptionHostNotNullAndGuestOsMappingNullAndGuestOsDisplayNameNull(){ guru._guestOsDao = guestOsDaoMock; guru._guestOsHypervisorDao = guestOSHypervisorDaoMock; @@ -412,7 +412,7 @@ public void validateVirtualMachineSetPlatformEmulatorHostNotNullAndGuestOsMappin } @Test - public void validateVirtualMachineSetPlatformEmulatorHostNotNullAndGuestOsMappingNullAndGuestOsDisplayNameNotNull(){ + public void validateConfigureVmOsDescriptionHostNotNullAndGuestOsMappingNullAndGuestOsDisplayNameNotNull(){ guru._guestOsDao = guestOsDaoMock; guru._guestOsHypervisorDao = guestOSHypervisorDaoMock; @@ -429,7 +429,7 @@ public void validateVirtualMachineSetPlatformEmulatorHostNotNullAndGuestOsMappin } @Test - public void validateVirtualMachineSetPlatformEmulatorHostNullAndGuestOsMappingNullAndGuestOsDisplayNameNull(){ + public void validateConfigureVmOsDescriptionHostNullAndGuestOsMappingNullAndGuestOsDisplayNameNull(){ guru._guestOsDao = guestOsDaoMock; VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {}; @@ -440,7 +440,7 @@ public void validateVirtualMachineSetPlatformEmulatorHostNullAndGuestOsMappingNu } @Test - public void validateVirtualMachineSetPlatformEmulatorHostNullAndGuestOsMappingNullAndGuestOsDisplayNameNotNull(){ + public void validateConfigureVmOsDescriptionHostNullAndGuestOsMappingNullAndGuestOsDisplayNameNotNull(){ guru._guestOsDao = guestOsDaoMock; VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {}; From fdafc2eb168286510738cbcb5ea522d6626a9d86 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 7 Apr 2021 11:46:44 -0300 Subject: [PATCH 17/38] Change vm's xml to work with max memory --- .../hypervisor/kvm/resource/LibvirtVMDef.java | 8 +++++++- .../resource/LibvirtComputingResourceTest.java | 16 +++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index bbab5c05ba0f..5b31eb5d696d 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -267,8 +267,14 @@ public void setMemBalloning(boolean memoryBalloning) { @Override public String toString() { StringBuilder response = new StringBuilder(); - response.append(String.format("%s\n", this.memory)); + response.append(String.format("%s\n", this.currentMemory)); response.append(String.format("%s\n", this.currentMemory)); + + if (this.memory > this.currentMemory) { + response.append(String.format("%s\n", this.memory)); + response.append(String.format(" \n", this.maxVcpu - 1, this.currentMemory)); + } + response.append(String.format("\n\n\n", this.memoryBalloning ? "virtio" : "none")); response.append(String.format("%s\n", this.vcpu, this.maxVcpu)); return response.toString(); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 6ad530c2386b..8dfb0c3c4efc 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -248,6 +248,7 @@ public void testCreateVMFromSpecLegacy() { to.setVncAddr(vncAddr); to.setArch("x86_64"); to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); + to.setVcpuMaxLimit(cpus + 1); final LibvirtVMDef vm = lcr.createVMFromSpec(to); vm.setHvsType(hyperVisorType); @@ -281,6 +282,7 @@ public void testCreateVMFromSpecWithTopology6() { to.setVncAddr(vncAddr); to.setArch("x86_64"); to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); + to.setVcpuMaxLimit(cpus + 1); final LibvirtVMDef vm = lcr.createVMFromSpec(to); vm.setHvsType(hyperVisorType); @@ -313,6 +315,7 @@ public void testCreateVMFromSpecWithTopology4() { final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword); to.setVncAddr(vncAddr); to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); + to.setVcpuMaxLimit(cpus + 1); final LibvirtVMDef vm = lcr.createVMFromSpec(to); vm.setHvsType(hyperVisorType); @@ -351,6 +354,7 @@ public void testCreateVMFromSpec() { to.setVncAddr(vncAddr); to.setArch("x86_64"); to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); + to.setVcpuMaxLimit(cpus + 1); final LibvirtVMDef vm = lcr.createVMFromSpec(to); vm.setHvsType(hyperVisorType); @@ -393,11 +397,17 @@ The configure() method of LibvirtComputingResource has not been called, so the d assertXpath(domainDoc, "/domain/devices/channel/source/@path", "/var/run/qemu/" + to.getName() + ".org.qemu.guest_agent.0"); assertXpath(domainDoc, "/domain/devices/channel/target/@name", "org.qemu.guest_agent.0"); - assertXpath(domainDoc, "/domain/memory/text()", String.valueOf( to.getMaxRam() / 1024 )); - assertXpath(domainDoc, "/domain/currentMemory/text()", String.valueOf( to.getMinRam() / 1024 )); + String minRam = String.valueOf( to.getMinRam() / 1024 ); + assertXpath(domainDoc, "/domain/maxMemory/text()", String.valueOf( to.getMaxRam() / 1024 )); + assertXpath(domainDoc, "/domain/cpu/numa/cell/@cpus", String.format("0-%s", to.getVcpuMaxLimit() - 1)); + assertXpath(domainDoc, "/domain/cpu/numa/cell/@memory", minRam); + assertXpath(domainDoc, "/domain/memory/text()",minRam); + assertXpath(domainDoc, "/domain/currentMemory/text()", minRam); assertXpath(domainDoc, "/domain/devices/memballoon/@model", "virtio"); - assertXpath(domainDoc, "/domain/vcpu/text()", String.valueOf(to.getCpus())); + assertXpath(domainDoc, "/domain/vcpu/@current", String.valueOf(to.getCpus())); + assertXpath(domainDoc, "/domain/vcpu/text()", String.valueOf(to.getVcpuMaxLimit())); + assertXpath(domainDoc, "/domain/os/type/@machine", "pc"); assertXpath(domainDoc, "/domain/os/type/text()", "hvm"); From 43b7a7e694afc8936d63efd205b08bd61cee2aa6 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 7 Apr 2021 11:51:09 -0300 Subject: [PATCH 18/38] Verify if service offering is dynamic before scale --- .../src/main/java/com/cloud/vm/UserVmManagerImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index a721de1a03e6..bd9453c4fc78 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -1879,7 +1879,9 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI supportedHypervisorTypes.add(HypervisorType.Simulator); supportedHypervisorTypes.add(HypervisorType.KVM); - if (!supportedHypervisorTypes.contains(vmInstance.getHypervisorType())) { + HypervisorType vmHypervisorType = vmInstance.getHypervisorType(); + + if (!supportedHypervisorTypes.contains(vmHypervisorType)) { String message = String.format("Scaling the VM dynamically is not supported for VMs running on Hypervisor [%s].", vmInstance.getHypervisorType()); s_logger.info(message); throw new InvalidParameterValueException(message); @@ -1917,6 +1919,12 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI throw new InvalidParameterValueException(message); } + if (vmHypervisorType.equals(HypervisorType.KVM) && !currentServiceOffering.isDynamic()) { + String message = String.format("Unable to live scale VM on KVM when current service offering is a \"Fixed Offering\". KVM needs the tag \"maxMemory\" to live scale and it is only configured when VM is deployed with a custom service offering and \"Dynamic Scalable\" is enabled."); + s_logger.info(message); + throw new InvalidParameterValueException(message); + } + _offeringDao.loadDetails(currentServiceOffering); _offeringDao.loadDetails(newServiceOffering); From 0f00590ac22c0233257143ff75fd74e9c6836e7d Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 7 Apr 2021 12:02:03 -0300 Subject: [PATCH 19/38] Create methods to retrieve data from domain --- .../resource/LibvirtComputingResource.java | 22 +++++++++++ .../LibvirtComputingResourceTest.java | 37 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 500a3929f78c..6c50f592bfbe 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -184,6 +184,7 @@ import com.cloud.vm.VmDetailConstants; import com.google.common.base.Strings; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; +import org.libvirt.VcpuInfo; /** * LibvirtComputingResource execute requests on the computing/routing host using @@ -4355,4 +4356,25 @@ public void setBackingFileFormat(String volPath) { } } + /** + * Retrieves the memory of the running VM.
+ * The libvirt (see https://github.com/libvirt/libvirt/blob/master/src/conf/domain_conf.c, function virDomainDefParseMemory) uses total memory as the tag memory, in VM's XML. + * @param dm domain of the VM. + * @return the memory of the VM. + * @throws org.libvirt.LibvirtException + **/ + public static long getDomainMemory(Domain dm) throws LibvirtException { + return dm.getMaxMemory(); + } + + /** + * Retrieves the quantity of running VCPUs of the running VM.
+ * @param dm domain of the VM. + * @return the quantity of running VCPUs of the running VM. + * @throws org.libvirt.LibvirtException + **/ + public long countDomainRunningVcpus(Domain dm) throws LibvirtException { + VcpuInfo vcpus[] = dm.getVcpusInfo(); + return Arrays.stream(vcpus).filter(vcpu -> vcpu.state.equals(VcpuInfo.VcpuState.VIR_VCPU_RUNNING)).count(); + } } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 8dfb0c3c4efc..3b833fa7c689 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -190,6 +190,7 @@ import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.Type; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; +import org.libvirt.VcpuInfo; @RunWith(PowerMockRunner.class) @PrepareForTest(value = {MemStat.class}) @@ -203,6 +204,9 @@ public class LibvirtComputingResourceTest { @Mock LibvirtVMDef vmDef; + @Mock + Domain domainMock; + String hyperVisorType = "kvm"; Random random = new Random(); final String memInfo = "MemTotal: 5830236 kB\n" + @@ -5273,4 +5277,37 @@ public void validateCreateGuestResourceDefWithVcpuMaxLimitAsNull(){ LibvirtVMDef.GuestResourceDef grd = libvirtComputingResource.createGuestResourceDef(vmTo); Assert.assertEquals(min, grd.getMaxVcpu()); } + + @Test + public void validateGetDomainMemory() throws LibvirtException{ + long valueExpected = ByteScaleUtils.KiB; + + Mockito.doReturn(valueExpected).when(domainMock).getMaxMemory(); + Assert.assertEquals(valueExpected, LibvirtComputingResource.getDomainMemory(domainMock)); + } + + private VcpuInfo createVcpuInfoWithState(VcpuInfo.VcpuState state) { + VcpuInfo vcpu = new VcpuInfo(); + vcpu.state = state; + return vcpu; + } + + @Test + public void validateCountDomainRunningVcpus() throws LibvirtException{ + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + VcpuInfo vcpus[] = new VcpuInfo[5]; + long valueExpected = 3; // 3 vcpus with state VIR_VCPU_RUNNING + + vcpus[0] = createVcpuInfoWithState(VcpuInfo.VcpuState.VIR_VCPU_BLOCKED); + vcpus[1] = createVcpuInfoWithState(VcpuInfo.VcpuState.VIR_VCPU_OFFLINE); + vcpus[2] = createVcpuInfoWithState(VcpuInfo.VcpuState.VIR_VCPU_RUNNING); + vcpus[3] = createVcpuInfoWithState(VcpuInfo.VcpuState.VIR_VCPU_RUNNING); + vcpus[4] = createVcpuInfoWithState(VcpuInfo.VcpuState.VIR_VCPU_RUNNING); + + Mockito.doReturn(vcpus).when(domainMock).getVcpusInfo(); + long result = libvirtComputingResource.countDomainRunningVcpus(domainMock); + + Assert.assertEquals(valueExpected, result); + } + } From f727e035ada3da24732ccccb1a9f0ee2b010786c Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 7 Apr 2021 12:03:01 -0300 Subject: [PATCH 20/38] Create def to hotplug memory --- .../resource/LibvirtVmMemoryDeviceDef.java | 45 +++++++++++++++++++ .../LibvirtVmMemoryDeviceDefTest.java | 43 ++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java create mode 100644 plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java new file mode 100644 index 000000000000..4f9b025559f9 --- /dev/null +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java @@ -0,0 +1,45 @@ +/* + * Copyright 2021 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cloud.hypervisor.kvm.resource; + +/** + * Provides the XML definition to a memory device which can be hotpluged to the VM.
+ * Memory is provided in KiB. + * + */ +public class LibvirtVmMemoryDeviceDef { + + private final long memorySize; + + public LibvirtVmMemoryDeviceDef(long memorySize) { + this.memorySize = memorySize; + } + + @Override + public String toString() { + StringBuilder response = new StringBuilder(); + response.append(""); + response.append(""); + response.append(String.format("%s", memorySize)); + response.append("0"); + response.append(""); + response.append(""); + + return response.toString(); + } + +} diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java new file mode 100644 index 000000000000..0320a6274071 --- /dev/null +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2021 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cloud.hypervisor.kvm.resource; + +import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class LibvirtVmMemoryDeviceDefTest { + + @Test + public void validateToString(){ + long memorySize = ByteScaleUtils.KiB; + + StringBuilder expectedToString = new StringBuilder(); + expectedToString.append(""); + expectedToString.append(""); + expectedToString.append(String.format("%s", memorySize)); + expectedToString.append("0"); + expectedToString.append(""); + expectedToString.append(""); + + Assert.assertEquals(expectedToString.toString(), new LibvirtVmMemoryDeviceDef(memorySize).toString()); + } + +} From 984aef3aab0225b38bf66bb1c0da396cf863fb22 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 7 Apr 2021 12:10:40 -0300 Subject: [PATCH 21/38] Adjust the way command was scaling the VM --- .../wrapper/LibvirtScaleVmCommandWrapper.java | 34 ++++++++++++++----- .../LibvirtScaleVmCommandWrapperTest.java | 16 +++++---- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java index d3a1cdb1ee98..3e22801786dc 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java @@ -21,6 +21,7 @@ import com.cloud.agent.api.ScaleVmCommand; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.hypervisor.kvm.resource.LibvirtVmMemoryDeviceDef; import com.cloud.resource.CommandWrapper; import com.cloud.resource.ResourceWrapper; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; @@ -37,9 +38,10 @@ public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtCo String vmName = vmSpec.getName(); Connect conn = null; - long memory = ByteScaleUtils.bytesToKib(vmSpec.getMaxRam()); - int vcpus = vmSpec.getCpus(); - String scallingDetails = String.format("%s memory to [%s KiB] and cpu cores to [%s]", vmSpec.toString(), memory, vcpus); + long newMemory = ByteScaleUtils.bytesToKib(vmSpec.getMaxRam()); + int newVcpus = vmSpec.getCpus(); + String vmDefinition = vmSpec.toString(); + String scalingDetails = String.format("%s memory to [%s KiB] and cpu cores to [%s]", vmDefinition, newMemory, newVcpus); try { LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper(); @@ -47,13 +49,29 @@ public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtCo conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName); Domain dm = conn.domainLookupByName(vmName); - logger.debug(String.format("Scalling %s.", scallingDetails)); - dm.setMemory(memory); - dm.setVcpus(vcpus); + long currentMemory = LibvirtComputingResource.getDomainMemory(dm); + long runningVcpus = libvirtComputingResource.countDomainRunningVcpus(dm); + long memoryToAttach = newMemory - currentMemory; - return new ScaleVmAnswer(command, true, String.format("Successfully scalled %s.", scallingDetails)); + logger.debug(String.format("Scaling %s.", scalingDetails)); + + if (memoryToAttach > 0) { + String memoryDevice = new LibvirtVmMemoryDeviceDef(newMemory - LibvirtComputingResource.getDomainMemory(dm)).toString(); + logger.debug(String.format("Attaching memory device [%s] to %s.", memoryDevice, vmDefinition)); + dm.attachDevice(memoryDevice); + } else { + logger.info(String.format("Not scaling the memory. To scale the memory of the %s, the new memory [%s] must be higher than the current memory [%s]. The current difference is [%s].", vmDefinition, newMemory, currentMemory, memoryToAttach)); + } + + if (runningVcpus < newVcpus) { + dm.setVcpus(newVcpus); + } else { + logger.info(String.format("Not scaling the cpu cores. To scale the cpu cores of the %s, the new cpu count [%s] must be higher than the current cpu count [%s].", vmDefinition, newVcpus, runningVcpus)); + } + + return new ScaleVmAnswer(command, true, String.format("Successfully scaled %s.", scalingDetails)); } catch (LibvirtException e) { - String message = String.format("Unable to scale %s due to [%s].", scallingDetails, e.getMessage()); + String message = String.format("Unable to scale %s due to [%s].", scalingDetails, e.getMessage()); logger.warn(message, e); return new ScaleVmAnswer(command, false, message); } finally { diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java index 5384c69b2c75..917534241eaa 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java @@ -61,18 +61,20 @@ public class LibvirtScaleVmCommandWrapperTest extends TestCase { LibvirtRequestWrapper wrapper; VirtualMachineTO vmTo; - String scallingDetails; + String scalingDetails; + + int countCpus = 2; @Before public void init() { wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); - vmTo = new VirtualMachineTO(1, "Test 1", VirtualMachine.Type.User, 2, 1000, 67108864, 67108864, VirtualMachineTemplate.BootloaderType.External, "Other Linux (64x)", true, true, "test123"); + vmTo = new VirtualMachineTO(1, "Test 1", VirtualMachine.Type.User, countCpus, 1000, 67108864, 67108864, VirtualMachineTemplate.BootloaderType.External, "Other Linux (64x)", true, true, "test123"); long memory = ByteScaleUtils.bytesToKib(vmTo.getMaxRam()); int vcpus = vmTo.getCpus(); - scallingDetails = String.format("%s memory to [%s KiB] and cpu cores to [%s]", vmTo.toString(), memory, vcpus); + scalingDetails = String.format("%s memory to [%s KiB] and cpu cores to [%s]", vmTo.toString(), memory, vcpus); } @Test @@ -81,12 +83,12 @@ public void validateExecuteSuccessfully() throws LibvirtException { Mockito.when(computingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); Mockito.when(libvirtUtilitiesHelper.getConnectionByVmName(Mockito.anyString())).thenReturn(connect); Mockito.when(connect.domainLookupByName(Mockito.anyString())).thenReturn(domain); - Mockito.doNothing().when(domain).setMemory(Mockito.anyLong()); - Mockito.doNothing().when(domain).setVcpus(Mockito.anyInt()); + Mockito.doReturn((long) countCpus).when(computingResource).countDomainRunningVcpus(domain); + Mockito.doNothing().when(domain).attachDevice(Mockito.anyString()); Answer answer = wrapper.execute(command, computingResource); - String details = String.format("Successfully scalled %s.", scallingDetails); + String details = String.format("Successfully scaled %s.", scalingDetails); assertTrue(answer.getResult()); assertEquals(details, answer.getDetails()); } @@ -101,7 +103,7 @@ public void validateExecuteHandleLibvirtException() throws LibvirtException { Answer answer = wrapper.execute(command, computingResource); - String details = String.format("Unable to scale %s due to [%s].", scallingDetails, errorMessage); + String details = String.format("Unable to scale %s due to [%s].", scalingDetails, errorMessage); assertFalse(answer.getResult()); assertEquals(details, answer.getDetails()); } From 8cc3b867ae4d62a91fb417440ab840216c52de4d Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 7 Apr 2021 12:15:49 -0300 Subject: [PATCH 22/38] Fix database persistence before executing command --- .../cloud/vm/VirtualMachineManagerImpl.java | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 76e8ef2d08da..c969b7b38cb2 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -4663,8 +4663,7 @@ public VMInstanceVO reConfigureVm(final String vmUuid, final ServiceOffering old private VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, ServiceOffering newServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException, ConcurrentOperationException { - VMInstanceVO vm = _vmDao.findByUuid(vmUuid); - upgradeVmDb(vm.getId(), newServiceOffering, oldServiceOffering); + final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); HostVO hostVo = _hostDao.findById(vm.getHostId()); @@ -4696,9 +4695,20 @@ private VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering old work.setResourceId(vm.getHostId()); _workDao.persist(work); - boolean success = false; - try { + Answer reconfigureAnswer = _agentMgr.send(vm.getHostId(), reconfigureCmd); + + if (reconfigureAnswer == null || !reconfigureAnswer.getResult()) { + s_logger.error("Unable to scale vm due to " + (reconfigureAnswer == null ? "" : reconfigureAnswer.getDetails())); + throw new CloudRuntimeException("Unable to scale vm due to " + (reconfigureAnswer == null ? "" : reconfigureAnswer.getDetails())); + } + + if (vm.getType().equals(VirtualMachine.Type.User)) { + _userVmMgr.generateUsageEvent(vm, vm.isDisplayVm(), EventTypes.EVENT_VM_DYNAMIC_SCALE); + } + + upgradeVmDb(vm.getId(), newServiceOffering, oldServiceOffering); + if (reconfiguringOnExistingHost) { vm.setServiceOfferingId(oldServiceOffering.getId()); _capacityMgr.releaseVmCapacity(vm, false, false, vm.getHostId()); //release the old capacity @@ -4706,26 +4716,10 @@ private VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering old _capacityMgr.allocateVmCapacity(vm, false); // lock the new capacity } - Answer scaleVmAnswer = _agentMgr.send(vm.getHostId(), scaleVmCommand); - if (scaleVmAnswer == null || !scaleVmAnswer.getResult()) { - String msg = String.format("Unable to scale %s due to [%s].", vm.toString(), (scaleVmAnswer == null ? "" : scaleVmAnswer.getDetails())); - s_logger.error(msg); - throw new CloudRuntimeException(msg); - } - if (vm.getType().equals(VirtualMachine.Type.User)) { - _userVmMgr.generateUsageEvent(vm, vm.isDisplayVm(), EventTypes.EVENT_VM_DYNAMIC_SCALE); - } - success = true; - } catch (OperationTimedoutException e) { - throw new AgentUnavailableException(String.format("Unable to scale %s due to [%s].", vm.toString(), e.getMessage()), dstHostId, e); + } catch (final OperationTimedoutException e) { + throw new AgentUnavailableException("Operation timed out on reconfiguring " + vm, dstHostId); } catch (final AgentUnavailableException e) { throw e; - } finally { - if (!success) { - _capacityMgr.releaseVmCapacity(vm, false, false, vm.getHostId()); // release the new capacity - upgradeVmDb(vm.getId(), oldServiceOffering, newServiceOffering); // rollback - _capacityMgr.allocateVmCapacity(vm, false); // allocate the old capacity - } } return vm; From 4ff96baf71d8356a6c065a6752294e499fd88fc5 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Wed, 7 Apr 2021 12:21:13 -0300 Subject: [PATCH 23/38] Send more info to host to improve log --- .../com/cloud/agent/api/to/VirtualMachineTO.java | 4 ++++ .../com/cloud/vm/VirtualMachineManagerImpl.java | 16 ++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java index 5f03b2772fce..b92dd0b6ed44 100644 --- a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java @@ -146,6 +146,10 @@ public Type getType() { return type; } + public void setType(Type type) { + this.type = type; + } + public BootloaderType getBootloader() { return bootloader; } diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index c969b7b38cb2..ca013cff8282 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -4680,12 +4680,16 @@ private VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering old new ScaleVmCommand(vm.getInstanceName(), newServiceOffering.getCpu(), minSpeed, newServiceOffering.getSpeed(), minMemory * 1024L * 1024L, newServiceOffering.getRamSize() * 1024L * 1024L, newServiceOffering.getLimitCpuUse()); - Long dstHostId = vm.getHostId(); - - if (vm.getHypervisorType().equals(HypervisorType.VMware)) { - HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType()); - Map details = hvGuru.getClusterSettings(vm.getId()); - scaleVmCommand.getVirtualMachine().setDetails(details); + reconfigureCmd.getVirtualMachine().setId(vm.getId()); + reconfigureCmd.getVirtualMachine().setUuid(vm.getUuid()); + reconfigureCmd.getVirtualMachine().setType(vm.getType()); + + final Long dstHostId = vm.getHostId(); + if(vm.getHypervisorType().equals(HypervisorType.VMware)) { + final HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType()); + Map details = null; + details = hvGuru.getClusterSettings(vm.getId()); + reconfigureCmd.getVirtualMachine().setDetails(details); } ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Running, vm.getType(), vm.getId()); From 668a40218565c66a7d22872c690cc931d09c2c0c Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador Date: Mon, 7 Jun 2021 11:16:12 -0300 Subject: [PATCH 24/38] Fix var name --- .../java/com/cloud/vm/VirtualMachineManagerImpl.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index ca013cff8282..46afe451d102 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -4680,16 +4680,16 @@ private VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering old new ScaleVmCommand(vm.getInstanceName(), newServiceOffering.getCpu(), minSpeed, newServiceOffering.getSpeed(), minMemory * 1024L * 1024L, newServiceOffering.getRamSize() * 1024L * 1024L, newServiceOffering.getLimitCpuUse()); - reconfigureCmd.getVirtualMachine().setId(vm.getId()); - reconfigureCmd.getVirtualMachine().setUuid(vm.getUuid()); - reconfigureCmd.getVirtualMachine().setType(vm.getType()); + scaleVmCommand.getVirtualMachine().setId(vm.getId()); + scaleVmCommand.getVirtualMachine().setUuid(vm.getUuid()); + scaleVmCommand.getVirtualMachine().setType(vm.getType()); final Long dstHostId = vm.getHostId(); if(vm.getHypervisorType().equals(HypervisorType.VMware)) { final HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType()); Map details = null; details = hvGuru.getClusterSettings(vm.getId()); - reconfigureCmd.getVirtualMachine().setDetails(details); + scaleVmCommand.getVirtualMachine().setDetails(details); } ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Running, vm.getType(), vm.getId()); @@ -4700,7 +4700,7 @@ private VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering old _workDao.persist(work); try { - Answer reconfigureAnswer = _agentMgr.send(vm.getHostId(), reconfigureCmd); + Answer reconfigureAnswer = _agentMgr.send(vm.getHostId(), scaleVmCommand); if (reconfigureAnswer == null || !reconfigureAnswer.getResult()) { s_logger.error("Unable to scale vm due to " + (reconfigureAnswer == null ? "" : reconfigureAnswer.getDetails())); From acf781ce503a3ebe071be77e652aff9bcaa0fddc Mon Sep 17 00:00:00 2001 From: GutoVeronezi Date: Mon, 14 Jun 2021 16:21:58 -0300 Subject: [PATCH 25/38] Fix missing "}" --- .../src/main/java/com/cloud/service/ServiceOfferingVO.java | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java b/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java index a431e81bed83..a23623164208 100644 --- a/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java @@ -300,6 +300,7 @@ public boolean isCustomCpuSpeedSupported() { @Override public String toString() { return String.format("Service offering {\"id\": %s, \"name\": \"%s\", \"uuid\": \"%s\"}", getId(), getName(), getUuid()); + } public boolean isDynamicScalingEnabled() { return dynamicScalingEnabled; From 607dc234adb16043bd8a2851b56da3e129e90139 Mon Sep 17 00:00:00 2001 From: GutoVeronezi Date: Fri, 18 Jun 2021 11:31:27 -0300 Subject: [PATCH 26/38] Undo unnecessary changes --- .../java/com/cloud/vm/VirtualMachineManagerImpl.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index d17389678c0b..c475a697cf8b 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -4687,11 +4687,11 @@ private VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering old scaleVmCommand.getVirtualMachine().setUuid(vm.getUuid()); scaleVmCommand.getVirtualMachine().setType(vm.getType()); - final Long dstHostId = vm.getHostId(); - if(vm.getHypervisorType().equals(HypervisorType.VMware)) { - final HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType()); - Map details = null; - details = hvGuru.getClusterSettings(vm.getId()); + Long dstHostId = vm.getHostId(); + + if (vm.getHypervisorType().equals(HypervisorType.VMware)) { + HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType()); + Map details = hvGuru.getClusterSettings(vm.getId()); scaleVmCommand.getVirtualMachine().setDetails(details); } From 81176dc428ad6a469a1a81f83fd5249e6bd310ac Mon Sep 17 00:00:00 2001 From: GutoVeronezi Date: Tue, 22 Jun 2021 19:31:40 -0300 Subject: [PATCH 27/38] Address review --- .../kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java index 3e22801786dc..f8ceab058310 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java @@ -56,7 +56,7 @@ public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtCo logger.debug(String.format("Scaling %s.", scalingDetails)); if (memoryToAttach > 0) { - String memoryDevice = new LibvirtVmMemoryDeviceDef(newMemory - LibvirtComputingResource.getDomainMemory(dm)).toString(); + String memoryDevice = new LibvirtVmMemoryDeviceDef(memoryToAttach).toString(); logger.debug(String.format("Attaching memory device [%s] to %s.", memoryDevice, vmDefinition)); dm.attachDevice(memoryDevice); } else { From 7559c12bafa0075fc39732c7b6d2684481eb6e06 Mon Sep 17 00:00:00 2001 From: GutoVeronezi Date: Tue, 22 Jun 2021 19:32:26 -0300 Subject: [PATCH 28/38] Fix scale validation --- server/src/main/java/com/cloud/hypervisor/KVMGuru.java | 7 ++++++- server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java | 6 ++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java index 45f3ee0ba510..c18f39a3a6ba 100644 --- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java +++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java @@ -34,6 +34,7 @@ import com.cloud.storage.dao.GuestOSHypervisorDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.UserVmManager; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import org.apache.cloudstack.storage.command.CopyCommand; @@ -178,7 +179,7 @@ protected void configureVmMemoryAndCpuCores(VirtualMachineTO virtualMachineTo, H Integer maxCpuCores = minCpuCores; ServiceOfferingVO serviceOfferingVO = serviceOfferingDao.findById(virtualMachineProfile.getId(), virtualMachineProfile.getServiceOfferingId()); - if (serviceOfferingVO.isDynamic() && virtualMachineTo.isEnableDynamicallyScaleVm()) { + if (isVmDynamicScalable(serviceOfferingVO, virtualMachineTo, virtualMachine)) { serviceOfferingDao.loadDetails(serviceOfferingVO); maxMemory = getVmMaxMemory(serviceOfferingVO, vmDescription, maxHostMemory); @@ -190,6 +191,10 @@ protected void configureVmMemoryAndCpuCores(VirtualMachineTO virtualMachineTo, H virtualMachineTo.setVcpuMaxLimit(maxCpuCores); } + protected boolean isVmDynamicScalable(ServiceOfferingVO serviceOfferingVO, VirtualMachineTO virtualMachineTo, VirtualMachine virtualMachine) { + return serviceOfferingVO.isDynamic() && virtualMachineTo.isEnableDynamicallyScaleVm() && UserVmManager.EnableDynamicallyScaleVm.valueIn(virtualMachine.getDataCenterId()); + } + protected Pair getHostMaxMemoryAndCpuCores(HostVO host, VirtualMachine virtualMachine, String vmDescription){ Long maxHostMemory = Long.MAX_VALUE; Integer maxHostCpuCore = Integer.MAX_VALUE; diff --git a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java index 16dfcd034382..22f54d0b13e2 100644 --- a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java +++ b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java @@ -305,8 +305,7 @@ public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsDynamicAndVmIsD guru.serviceOfferingDao = serviceOfferingDaoMock; Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findById(Mockito.anyLong(), Mockito.anyLong()); - Mockito.doReturn(true).when(serviceOfferingVoMock).isDynamic(); - Mockito.doReturn(true).when(vmTO).isEnableDynamicallyScaleVm(); + Mockito.doReturn(true).when(guru).isVmDynamicScalable(Mockito.any(), Mockito.any(), Mockito.any()); guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile); @@ -319,8 +318,7 @@ public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsNotDynamicAndVm guru.serviceOfferingDao = serviceOfferingDaoMock; Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findById(Mockito.anyLong(), Mockito.anyLong()); - Mockito.doReturn(false).when(serviceOfferingVoMock).isDynamic(); - Mockito.lenient().doReturn(true).when(vmTO).isEnableDynamicallyScaleVm(); + Mockito.doReturn(false).when(guru).isVmDynamicScalable(Mockito.any(), Mockito.any(), Mockito.any()); guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile); From 9a7abde542eb076249d39fedb30f6c983200575b Mon Sep 17 00:00:00 2001 From: GutoVeronezi Date: Wed, 23 Jun 2021 11:18:08 -0300 Subject: [PATCH 29/38] Add VM prepared for dynamic scaling validation --- .../wrapper/LibvirtScaleVmCommandWrapper.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java index f8ceab058310..56d9c081a16e 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java @@ -24,6 +24,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVmMemoryDeviceDef; import com.cloud.resource.CommandWrapper; import com.cloud.resource.ResourceWrapper; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; import org.libvirt.Connect; import org.libvirt.Domain; @@ -56,23 +57,31 @@ public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtCo logger.debug(String.format("Scaling %s.", scalingDetails)); if (memoryToAttach > 0) { + if (!dm.getXMLDesc(0).contains("")) { + throw new CloudRuntimeException(String.format("The %s is not prepared for dynamic scaling. To be prepared, the VM must be deployed with a dynamic service offering," + + " VM dynamic scale enabled and global setting \"enable.dynamic.scale.vm\" as \"true\". If you changed one of these settings after deploying the VM," + + " consider stopping and starting it again to prepared it to dynamic scaling.", vmDefinition)); + } + String memoryDevice = new LibvirtVmMemoryDeviceDef(memoryToAttach).toString(); logger.debug(String.format("Attaching memory device [%s] to %s.", memoryDevice, vmDefinition)); dm.attachDevice(memoryDevice); } else { - logger.info(String.format("Not scaling the memory. To scale the memory of the %s, the new memory [%s] must be higher than the current memory [%s]. The current difference is [%s].", vmDefinition, newMemory, currentMemory, memoryToAttach)); + logger.info(String.format("Not scaling the memory. To scale the memory of the %s, the new memory [%s] must be higher than the current memory [%s]. The current " + + "difference is [%s].", vmDefinition, newMemory, currentMemory, memoryToAttach)); } if (runningVcpus < newVcpus) { dm.setVcpus(newVcpus); } else { - logger.info(String.format("Not scaling the cpu cores. To scale the cpu cores of the %s, the new cpu count [%s] must be higher than the current cpu count [%s].", vmDefinition, newVcpus, runningVcpus)); + logger.info(String.format("Not scaling the cpu cores. To scale the cpu cores of the %s, the new cpu count [%s] must be higher than the current cpu count [%s].", + vmDefinition, newVcpus, runningVcpus)); } return new ScaleVmAnswer(command, true, String.format("Successfully scaled %s.", scalingDetails)); - } catch (LibvirtException e) { + } catch (LibvirtException | CloudRuntimeException e) { String message = String.format("Unable to scale %s due to [%s].", scalingDetails, e.getMessage()); - logger.warn(message, e); + logger.error(message, e); return new ScaleVmAnswer(command, false, message); } finally { if (conn != null) { From ad23d397d43b80a3506f46a3c2f92f93d165b767 Mon Sep 17 00:00:00 2001 From: GutoVeronezi Date: Mon, 28 Jun 2021 13:07:11 -0300 Subject: [PATCH 30/38] Refactor LibvirtScaleVmCommandWrapper and improve unit tests --- .../resource/LibvirtComputingResource.java | 2 +- .../wrapper/LibvirtScaleVmCommandWrapper.java | 64 +++--- .../LibvirtComputingResourceTest.java | 3 +- .../LibvirtScaleVmCommandWrapperTest.java | 187 +++++++++++++++--- 4 files changed, 196 insertions(+), 60 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index ad560cccb619..0f4b75d24032 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -4368,7 +4368,7 @@ public static long getDomainMemory(Domain dm) throws LibvirtException { * @return the quantity of running VCPUs of the running VM. * @throws org.libvirt.LibvirtException **/ - public long countDomainRunningVcpus(Domain dm) throws LibvirtException { + public static long countDomainRunningVcpus(Domain dm) throws LibvirtException { VcpuInfo vcpus[] = dm.getVcpusInfo(); return Arrays.stream(vcpus).filter(vcpu -> vcpu.state.equals(VcpuInfo.VcpuState.VIR_VCPU_RUNNING)).count(); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java index 56d9c081a16e..ed2d453bec05 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java @@ -31,7 +31,7 @@ import org.libvirt.LibvirtException; @ResourceWrapper(handles = ScaleVmCommand.class) -public final class LibvirtScaleVmCommandWrapper extends CommandWrapper { +public class LibvirtScaleVmCommandWrapper extends CommandWrapper { @Override public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtComputingResource) { @@ -42,7 +42,7 @@ public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtCo long newMemory = ByteScaleUtils.bytesToKib(vmSpec.getMaxRam()); int newVcpus = vmSpec.getCpus(); String vmDefinition = vmSpec.toString(); - String scalingDetails = String.format("%s memory to [%s KiB] and cpu cores to [%s]", vmDefinition, newMemory, newVcpus); + String scalingDetails = String.format("%s memory to [%s KiB] and CPU cores to [%s]", vmDefinition, newMemory, newVcpus); try { LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper(); @@ -50,33 +50,9 @@ public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtCo conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName); Domain dm = conn.domainLookupByName(vmName); - long currentMemory = LibvirtComputingResource.getDomainMemory(dm); - long runningVcpus = libvirtComputingResource.countDomainRunningVcpus(dm); - long memoryToAttach = newMemory - currentMemory; - logger.debug(String.format("Scaling %s.", scalingDetails)); - - if (memoryToAttach > 0) { - if (!dm.getXMLDesc(0).contains("")) { - throw new CloudRuntimeException(String.format("The %s is not prepared for dynamic scaling. To be prepared, the VM must be deployed with a dynamic service offering," - + " VM dynamic scale enabled and global setting \"enable.dynamic.scale.vm\" as \"true\". If you changed one of these settings after deploying the VM," - + " consider stopping and starting it again to prepared it to dynamic scaling.", vmDefinition)); - } - - String memoryDevice = new LibvirtVmMemoryDeviceDef(memoryToAttach).toString(); - logger.debug(String.format("Attaching memory device [%s] to %s.", memoryDevice, vmDefinition)); - dm.attachDevice(memoryDevice); - } else { - logger.info(String.format("Not scaling the memory. To scale the memory of the %s, the new memory [%s] must be higher than the current memory [%s]. The current " - + "difference is [%s].", vmDefinition, newMemory, currentMemory, memoryToAttach)); - } - - if (runningVcpus < newVcpus) { - dm.setVcpus(newVcpus); - } else { - logger.info(String.format("Not scaling the cpu cores. To scale the cpu cores of the %s, the new cpu count [%s] must be higher than the current cpu count [%s].", - vmDefinition, newVcpus, runningVcpus)); - } + scaleMemory(dm, newMemory, vmDefinition); + scaleVcpus(dm, newVcpus, vmDefinition); return new ScaleVmAnswer(command, true, String.format("Successfully scaled %s.", scalingDetails)); } catch (LibvirtException | CloudRuntimeException e) { @@ -94,4 +70,36 @@ public Answer execute(ScaleVmCommand command, LibvirtComputingResource libvirtCo } } + protected void scaleVcpus(Domain dm, int newVcpus, String vmDefinition) throws LibvirtException { + long runningVcpus = LibvirtComputingResource.countDomainRunningVcpus(dm); + + if (runningVcpus < newVcpus) { + dm.setVcpus(newVcpus); + return; + } + + logger.info(String.format("Not scaling the CPU cores. To scale the CPU cores of the %s, the new CPU count [%s] must be higher than the current CPU count [%s].", + vmDefinition, newVcpus, runningVcpus)); + } + + protected void scaleMemory(Domain dm, long newMemory, String vmDefinition) throws LibvirtException, CloudRuntimeException { + long currentMemory = LibvirtComputingResource.getDomainMemory(dm); + long memoryToAttach = newMemory - currentMemory; + + if (memoryToAttach <= 0) { + logger.info(String.format("Not scaling the memory. To scale the memory of the %s, the new memory [%s] must be higher than the current memory [%s]. The current " + + "difference is [%s].", vmDefinition, newMemory, currentMemory, memoryToAttach)); + return; + } + + if (!dm.getXMLDesc(0).contains("")) { + throw new CloudRuntimeException(String.format("The %s is not prepared for dynamic scaling. To be prepared, the VM must be deployed with a dynamic service offering," + + " VM dynamic scale enabled and global setting \"enable.dynamic.scale.vm\" as \"true\". If you changed one of these settings after deploying the VM," + + " consider stopping and starting it again to prepared it to dynamic scaling.", vmDefinition)); + } + + String memoryDevice = new LibvirtVmMemoryDeviceDef(memoryToAttach).toString(); + logger.debug(String.format("Attaching memory device [%s] to %s.", memoryDevice, vmDefinition)); + dm.attachDevice(memoryDevice); + } } \ No newline at end of file diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 3b833fa7c689..148ed9651e25 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -5294,7 +5294,6 @@ private VcpuInfo createVcpuInfoWithState(VcpuInfo.VcpuState state) { @Test public void validateCountDomainRunningVcpus() throws LibvirtException{ - LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); VcpuInfo vcpus[] = new VcpuInfo[5]; long valueExpected = 3; // 3 vcpus with state VIR_VCPU_RUNNING @@ -5305,7 +5304,7 @@ public void validateCountDomainRunningVcpus() throws LibvirtException{ vcpus[4] = createVcpuInfoWithState(VcpuInfo.VcpuState.VIR_VCPU_RUNNING); Mockito.doReturn(vcpus).when(domainMock).getVcpusInfo(); - long result = libvirtComputingResource.countDomainRunningVcpus(domainMock); + long result = LibvirtComputingResource.countDomainRunningVcpus(domainMock); Assert.assertEquals(valueExpected, result); } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java index 917534241eaa..25cf600ff8a5 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java @@ -21,6 +21,7 @@ import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; import com.cloud.template.VirtualMachineTemplate; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; import junit.framework.TestCase; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; @@ -32,25 +33,32 @@ import org.libvirt.LibvirtException; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.Spy; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; -@RunWith(MockitoJUnitRunner.class) +@RunWith(PowerMockRunner.class) +@PrepareForTest(LibvirtComputingResource.class) public class LibvirtScaleVmCommandWrapperTest extends TestCase { + @Spy + LibvirtScaleVmCommandWrapper libvirtScaleVmCommandWrapperSpy = Mockito.spy(LibvirtScaleVmCommandWrapper.class); + @Mock - LibvirtComputingResource computingResource; + LibvirtComputingResource libvirtComputingResourceMock; @Mock - ScaleVmCommand command; + ScaleVmCommand scaleVmCommandMock; @Mock - LibvirtUtilitiesHelper libvirtUtilitiesHelper; + LibvirtUtilitiesHelper libvirtUtilitiesHelperMock; @Mock - Domain domain; + Domain domainMock; @Mock - Connect connect; + Connect connectMock; @Mock LibvirtException libvirtException; @@ -63,55 +71,176 @@ public class LibvirtScaleVmCommandWrapperTest extends TestCase { String scalingDetails; - int countCpus = 2; - @Before public void init() { wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); - vmTo = new VirtualMachineTO(1, "Test 1", VirtualMachine.Type.User, countCpus, 1000, 67108864, 67108864, VirtualMachineTemplate.BootloaderType.External, "Other Linux (64x)", true, true, "test123"); + vmTo = new VirtualMachineTO(1, "Test 1", VirtualMachine.Type.User, 2, 1000, 67108864, 67108864, VirtualMachineTemplate.BootloaderType.External, "Other Linux (64x)", true, true, "test123"); long memory = ByteScaleUtils.bytesToKib(vmTo.getMaxRam()); int vcpus = vmTo.getCpus(); - scalingDetails = String.format("%s memory to [%s KiB] and cpu cores to [%s]", vmTo.toString(), memory, vcpus); + scalingDetails = String.format("%s memory to [%s KiB] and CPU cores to [%s]", vmTo.toString(), memory, vcpus); + + PowerMockito.mockStatic(LibvirtComputingResource.class); } @Test - public void validateExecuteSuccessfully() throws LibvirtException { - Mockito.when(command.getVirtualMachine()).thenReturn(vmTo); - Mockito.when(computingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); - Mockito.when(libvirtUtilitiesHelper.getConnectionByVmName(Mockito.anyString())).thenReturn(connect); - Mockito.when(connect.domainLookupByName(Mockito.anyString())).thenReturn(domain); - Mockito.doReturn((long) countCpus).when(computingResource).countDomainRunningVcpus(domain); - Mockito.doNothing().when(domain).attachDevice(Mockito.anyString()); + public void validateScaleVcpusRunningVcpusLessThanNewVcpusSetNewVcpu() throws LibvirtException{ + long runningVcpus = 1; + int newVcpus = 2; - Answer answer = wrapper.execute(command, computingResource); + PowerMockito.when(LibvirtComputingResource.countDomainRunningVcpus(Mockito.any())).thenReturn(runningVcpus); + Mockito.doNothing().when(domainMock).setVcpus(Mockito.anyInt()); - String details = String.format("Successfully scaled %s.", scalingDetails); - assertTrue(answer.getResult()); - assertEquals(details, answer.getDetails()); + libvirtScaleVmCommandWrapperSpy.scaleVcpus(domainMock, newVcpus, scalingDetails); + + Mockito.verify(domainMock).setVcpus(Mockito.anyInt()); + } + + @Test + public void validateScaleVcpusRunningVcpusEqualThanNewVcpusDoNothing() throws LibvirtException{ + long runningVcpus = 2; + int newVcpus = 2; + + PowerMockito.when(LibvirtComputingResource.countDomainRunningVcpus(Mockito.any())).thenReturn(runningVcpus); + + libvirtScaleVmCommandWrapperSpy.scaleVcpus(domainMock, newVcpus, scalingDetails); + + Mockito.verify(domainMock, Mockito.never()).setVcpus(Mockito.anyInt()); + } + + @Test + public void validateScaleVcpusRunningVcpusHigherThanNewVcpusDoNothing() throws LibvirtException{ + long runningVcpus = 2; + int newVcpus = 1; + + PowerMockito.when(LibvirtComputingResource.countDomainRunningVcpus(Mockito.any())).thenReturn(runningVcpus); + + libvirtScaleVmCommandWrapperSpy.scaleVcpus(domainMock, newVcpus, scalingDetails); + + Mockito.verify(domainMock, Mockito.never()).setVcpus(Mockito.anyInt()); + } + + @Test (expected = LibvirtException.class) + public void validateScaleVcpusSetVcpusThrowLibvirtException() throws LibvirtException{ + long runningVcpus = 1; + int newVcpus = 2; + + PowerMockito.when(LibvirtComputingResource.countDomainRunningVcpus(Mockito.any())).thenReturn(runningVcpus); + Mockito.doThrow(LibvirtException.class).when(domainMock).setVcpus(Mockito.anyInt()); + + libvirtScaleVmCommandWrapperSpy.scaleVcpus(domainMock, newVcpus, scalingDetails); + + Mockito.verify(domainMock, Mockito.never()).setVcpus(Mockito.anyInt()); + } + + @Test + public void validateScaleMemoryMemoryLessThanZeroDoNothing() throws LibvirtException { + long currentMemory = 1l; + long newMemory = 0l; + + PowerMockito.when(LibvirtComputingResource.getDomainMemory(Mockito.any())).thenReturn(currentMemory); + + libvirtScaleVmCommandWrapperSpy.scaleMemory(domainMock, newMemory, scalingDetails); + + Mockito.verify(domainMock, Mockito.never()).getXMLDesc(Mockito.anyInt()); + Mockito.verify(domainMock, Mockito.never()).attachDevice(Mockito.anyString()); + } + + @Test + public void validateScaleMemoryMemoryEqualToZeroDoNothing() throws LibvirtException { + long currentMemory = 1l; + long newMemory = 1l; + + PowerMockito.when(LibvirtComputingResource.getDomainMemory(Mockito.any())).thenReturn(currentMemory); + + libvirtScaleVmCommandWrapperSpy.scaleMemory(domainMock, newMemory, scalingDetails); + + Mockito.verify(domainMock, Mockito.never()).getXMLDesc(Mockito.anyInt()); + Mockito.verify(domainMock, Mockito.never()).attachDevice(Mockito.anyString()); + } + + @Test (expected = CloudRuntimeException.class) + public void validateScaleMemoryDomainXmlDoesNotContainsMaxMemory() throws LibvirtException { + long currentMemory = 1l; + long newMemory = 2l; + + PowerMockito.when(LibvirtComputingResource.getDomainMemory(Mockito.any())).thenReturn(currentMemory); + Mockito.doReturn("").when(domainMock).getXMLDesc(Mockito.anyInt()); + + libvirtScaleVmCommandWrapperSpy.scaleMemory(domainMock, newMemory, scalingDetails); + + Mockito.verify(domainMock).getXMLDesc(Mockito.anyInt()); + Mockito.verify(domainMock, Mockito.never()).attachDevice(Mockito.anyString()); + } + + @Test (expected = LibvirtException.class) + public void validateScaleMemoryAttachDeviceThrowsLibvirtException() throws LibvirtException { + long currentMemory = 1l; + long newMemory = 2l; + + PowerMockito.when(LibvirtComputingResource.getDomainMemory(Mockito.any())).thenReturn(currentMemory); + Mockito.doReturn("").when(domainMock).getXMLDesc(Mockito.anyInt()); + Mockito.doThrow(LibvirtException.class).when(domainMock).attachDevice(Mockito.anyString()); + + libvirtScaleVmCommandWrapperSpy.scaleMemory(domainMock, newMemory, scalingDetails); + + Mockito.verify(domainMock).getXMLDesc(Mockito.anyInt()); + Mockito.verify(domainMock).attachDevice(Mockito.anyString()); + } + + @Test + public void validateScaleMemory() throws LibvirtException { + long currentMemory = 1l; + long newMemory = 2l; + + PowerMockito.when(LibvirtComputingResource.getDomainMemory(Mockito.any())).thenReturn(currentMemory); + Mockito.doReturn("").when(domainMock).getXMLDesc(Mockito.anyInt()); + Mockito.doNothing().when(domainMock).attachDevice(Mockito.anyString()); + + libvirtScaleVmCommandWrapperSpy.scaleMemory(domainMock, newMemory, scalingDetails); + + Mockito.verify(domainMock).getXMLDesc(Mockito.anyInt()); + Mockito.verify(domainMock).attachDevice(Mockito.anyString()); } @Test public void validateExecuteHandleLibvirtException() throws LibvirtException { - Mockito.when(command.getVirtualMachine()).thenReturn(vmTo); - Mockito.when(computingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); - Mockito.doThrow(libvirtException).when(libvirtUtilitiesHelper).getConnectionByVmName(Mockito.anyString()); String errorMessage = ""; - Mockito.when(libvirtException.getMessage()).thenReturn(errorMessage); - Answer answer = wrapper.execute(command, computingResource); + Mockito.doReturn(vmTo).when(scaleVmCommandMock).getVirtualMachine(); + Mockito.doReturn(libvirtUtilitiesHelperMock).when(libvirtComputingResourceMock).getLibvirtUtilitiesHelper(); + Mockito.doThrow(libvirtException).when(libvirtUtilitiesHelperMock).getConnectionByVmName(Mockito.anyString()); + Mockito.doReturn(errorMessage).when(libvirtException).getMessage(); + + Answer answer = libvirtScaleVmCommandWrapperSpy.execute(scaleVmCommandMock, libvirtComputingResourceMock); String details = String.format("Unable to scale %s due to [%s].", scalingDetails, errorMessage); assertFalse(answer.getResult()); assertEquals(details, answer.getDetails()); } + @Test + public void validateExecuteSuccessfully() throws LibvirtException { + Mockito.doReturn(vmTo).when(scaleVmCommandMock).getVirtualMachine(); + Mockito.doReturn(libvirtUtilitiesHelperMock).when(libvirtComputingResourceMock).getLibvirtUtilitiesHelper(); + Mockito.doReturn(connectMock).when(libvirtUtilitiesHelperMock).getConnectionByVmName(Mockito.anyString()); + Mockito.doReturn(domainMock).when(connectMock).domainLookupByName(Mockito.anyString()); + Mockito.doNothing().when(libvirtScaleVmCommandWrapperSpy).scaleMemory(Mockito.any(), Mockito.anyLong(), Mockito.anyString()); + Mockito.doNothing().when(libvirtScaleVmCommandWrapperSpy).scaleVcpus(Mockito.any(), Mockito.anyInt(), Mockito.anyString()); + + Answer answer = libvirtScaleVmCommandWrapperSpy.execute(scaleVmCommandMock, libvirtComputingResourceMock); + + String details = String.format("Successfully scaled %s.", scalingDetails); + assertTrue(answer.getResult()); + assertEquals(details, answer.getDetails()); + } + @Test(expected = Exception.class) public void validateExecuteThrowAnyOtherException() { - Mockito.doThrow(exception).when(computingResource).getLibvirtUtilitiesHelper(); + Mockito.doThrow(Exception.class).when(libvirtComputingResourceMock).getLibvirtUtilitiesHelper(); - wrapper.execute(command, computingResource); + libvirtScaleVmCommandWrapperSpy.execute(scaleVmCommandMock, libvirtComputingResourceMock); } } \ No newline at end of file From e65db10fb33841f9e40f7077e2510bd14e590f16 Mon Sep 17 00:00:00 2001 From: GutoVeronezi Date: Mon, 26 Jul 2021 08:44:22 -0300 Subject: [PATCH 31/38] Remove duplicated method --- .../kvm/resource/LibvirtComputingResource.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 404231aff720..1488524e8457 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -2532,21 +2532,6 @@ private CpuModeDef createCpuModeDef(VirtualMachineTO vmTO, int vcpus) { return cmd; } - /** - * Creates guest resources based in VM specification. - */ - protected GuestResourceDef createGuestResourceDef(VirtualMachineTO vmTO) { - GuestResourceDef grd = new GuestResourceDef(); - - grd.setMemorySize(vmTO.getMaxRam() / 1024); - if (vmTO.getMinRam() != vmTO.getMaxRam() && !_noMemBalloon) { - grd.setMemBalloning(true); - grd.setCurrentMem(vmTO.getMinRam() / 1024); - } - grd.setVcpuNum(vmTO.getCpus()); - return grd; - } - private void configureGuestIfUefiEnabled(boolean isSecureBoot, String bootMode, GuestDef guest) { setGuestLoader(bootMode, SECURE, guest, GuestDef.GUEST_LOADER_SECURE); setGuestLoader(bootMode, LEGACY, guest, GuestDef.GUEST_LOADER_LEGACY); @@ -2626,6 +2611,9 @@ private void configureGuestAndUserVMToUseLXC(LibvirtVMDef vm, GuestDef guest) { vm.setHvsType(HypervisorType.LXC.toString().toLowerCase()); } + /** + * Creates guest resources based in VM specification. + */ protected GuestResourceDef createGuestResourceDef(VirtualMachineTO vmTO){ GuestResourceDef grd = new GuestResourceDef(); From 4cde5e3f71f36226e5fdd877bc97c151fc282a46 Mon Sep 17 00:00:00 2001 From: GutoVeronezi Date: Fri, 30 Jul 2021 14:33:41 -0300 Subject: [PATCH 32/38] Add RuntimeException check --- .../src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index f7e6b79f1d7b..1c77295a75a7 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -4665,6 +4665,8 @@ public VMInstanceVO reConfigureVm(final String vmUuid, final ServiceOffering old throw (ConcurrentOperationException)jobResult; } else if (jobResult instanceof InsufficientServerCapacityException) { throw (InsufficientServerCapacityException)jobResult; + } else if (jobResult instanceof RuntimeException) { + throw (RuntimeException)jobResult; } else if (jobResult instanceof Throwable) { s_logger.error("Unhandled exception", (Throwable)jobResult); throw new RuntimeException("Unhandled exception", (Throwable)jobResult); From ac1f2f87d6bd87bd38ba1c21e5fae7ddad448f99 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:36:27 -0300 Subject: [PATCH 33/38] Remove copyright from header --- .../cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java index 4f9b025559f9..1865a6d41d5a 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDef.java @@ -1,6 +1,4 @@ /* - * Copyright 2021 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at From 267ebab7af8181520ea38f2e8eabd71b7168bfac Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:36:45 -0300 Subject: [PATCH 34/38] Remove copyright from header --- .../kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java index ed2d453bec05..384d5cc8b151 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java @@ -1,6 +1,4 @@ /* - * Copyright 2021 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -102,4 +100,4 @@ protected void scaleMemory(Domain dm, long newMemory, String vmDefinition) throw logger.debug(String.format("Attaching memory device [%s] to %s.", memoryDevice, vmDefinition)); dm.attachDevice(memoryDevice); } -} \ No newline at end of file +} From 40bb25ae18679ddcc860bbccfde0de96641557ce Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:37:06 -0300 Subject: [PATCH 35/38] Remove copyright from header --- .../hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java index 0320a6274071..aee4f36bda2b 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVmMemoryDeviceDefTest.java @@ -1,6 +1,4 @@ /* - * Copyright 2021 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at From 9ab2036b7c535d4580469565282bb98f0b8ffbb9 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:37:22 -0300 Subject: [PATCH 36/38] Remove copyright from header --- .../resource/wrapper/LibvirtScaleVmCommandWrapperTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java index 25cf600ff8a5..a0851e747f12 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java @@ -1,6 +1,4 @@ /* - * Copyright 2021 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -243,4 +241,4 @@ public void validateExecuteThrowAnyOtherException() { libvirtScaleVmCommandWrapperSpy.execute(scaleVmCommandMock, libvirtComputingResourceMock); } -} \ No newline at end of file +} From b3c65f065ef950aa74f3de69952827532ec31fa5 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:38:14 -0300 Subject: [PATCH 37/38] Remove copyright from header --- .../org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java b/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java index fed31cad2253..95d455f12474 100644 --- a/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java +++ b/utils/src/main/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtils.java @@ -1,6 +1,4 @@ /* - * Copyright 2021 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at From a7ad61b8d0f9c21d748da51f9f1391cdbff5ffe8 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:38:30 -0300 Subject: [PATCH 38/38] Update ByteScaleUtilsTest.java --- .../apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java b/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java index 13138dace5d6..b3487641b42c 100644 --- a/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java +++ b/utils/src/test/java/org/apache/cloudstack/utils/bytescale/ByteScaleUtilsTest.java @@ -1,6 +1,4 @@ /* - * Copyright 2021 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at