diff --git a/api/src/main/java/com/cloud/offering/ServiceOffering.java b/api/src/main/java/com/cloud/offering/ServiceOffering.java index 2a80ba5bd61..163762202b0 100644 --- a/api/src/main/java/com/cloud/offering/ServiceOffering.java +++ b/api/src/main/java/com/cloud/offering/ServiceOffering.java @@ -116,4 +116,6 @@ public interface ServiceOffering extends DiskOffering, InfrastructureEntity, Int String getDeploymentPlanner(); boolean isDynamic(); + + boolean isDynamicallyScalable(); } diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index eab9c736a37..da2591ecac8 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -218,7 +218,7 @@ public interface UserVmService { String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard, List affinityGroupIdList, Map customParameter, String customId, Map> dhcpOptionMap, Map dataDiskTemplateToDiskOfferingMap, - Map userVmOVFProperties) throws InsufficientCapacityException, + Map userVmOVFProperties, Boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -300,7 +300,7 @@ public interface UserVmService { HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList, Map customParameters, String customId, Map> dhcpOptionMap, Map dataDiskTemplateToDiskOfferingMap, - Map userVmOVFProperties) throws InsufficientCapacityException, + Map userVmOVFProperties, Boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -379,7 +379,7 @@ public interface UserVmService { String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList, Map customParameters, String customId, Map> dhcpOptionMap, Map dataDiskTemplateToDiskOfferingMap, - Map templateOvfPropertiesMap) + Map templateOvfPropertiesMap, Boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; diff --git a/api/src/main/java/com/cloud/vm/VirtualMachine.java b/api/src/main/java/com/cloud/vm/VirtualMachine.java index 829e743df73..02f55377845 100644 --- a/api/src/main/java/com/cloud/vm/VirtualMachine.java +++ b/api/src/main/java/com/cloud/vm/VirtualMachine.java @@ -342,4 +342,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Partition, @Override boolean isDisplay(); + Boolean isDynamicallyScalable(); + } diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 605a6c006eb..006f58a2833 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -837,6 +837,7 @@ public class ApiConstants { public static final String CROSS_ZONES = "crossZones"; public static final String TEMPLATETYPE = "templatetype"; public static final String SOURCETEMPLATEID = "sourcetemplateid"; + public static final String DynamicScalingEnabled = "dynamicscalingenabled"; public static final String POOL_TYPE ="pooltype"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index d2d6f387744..428309a3278 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -223,6 +223,11 @@ public class CreateServiceOfferingCmd extends BaseCmd { @Parameter(name = ApiConstants.STORAGE_POLICY, type = CommandType.UUID, entityType = VsphereStoragePoliciesResponse.class,required = false, description = "Name of the storage policy defined at vCenter, this is applicable only for VMware", since = "4.15") private Long storagePolicy; + @Parameter(name = ApiConstants.DynamicScalingEnabled, + type = CommandType.BOOLEAN, + description = "true if virtual machine needs to be dynamically scalable of cpu or memory") + protected Boolean isDynamicScalingEnabled; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -441,6 +446,10 @@ public class CreateServiceOfferingCmd extends BaseCmd { return storagePolicy; } + public Boolean getDynamicScalingEnabled() { + return isDynamicScalingEnabled == null ? Boolean.TRUE : isDynamicScalingEnabled; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 6d7cc9c81c2..d6f3727128c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -235,6 +235,11 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG @LogLevel(LogLevel.Log4jLevel.Off) private Map vAppNetworks; + @Parameter(name = ApiConstants.DynamicScalingEnabled, + type = CommandType.BOOLEAN, + description = "true if virtual machine needs to be dynamically scalable") + protected Boolean isDynamicScalingEnabled; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -623,6 +628,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG return bootIntoSetup; } + public Boolean getDynamicScalingEnabled() { + return isDynamicScalingEnabled == null ? Boolean.TRUE : isDynamicScalingEnabled; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java index 05fcfbdc7b2..40be57c3975 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java @@ -204,6 +204,10 @@ public class ServiceOfferingResponse extends BaseResponse { @Param(description = "Root disk size in GB", since = "4.15") private Long rootDiskSize; + @SerializedName("dynamicscalingenabled") + @Param(description = "true if virtual machine needs to be dynamically scalable of cpu or memory") + private Boolean dynamicscalingenabled; + public ServiceOfferingResponse() { } @@ -457,7 +461,6 @@ public class ServiceOfferingResponse extends BaseResponse { public void setIscutomized(boolean iscutomized) { this.isCustomized = iscutomized; - } public void setCacheMode(String cacheMode) { @@ -475,4 +478,12 @@ public class ServiceOfferingResponse extends BaseResponse { public void setRootDiskSize(Long rootDiskSize) { this.rootDiskSize = rootDiskSize; } + + public Boolean getDynamicscalingenabled() { + return dynamicscalingenabled; + } + + public void setDynamicscalingenabled(Boolean dynamicscalingenabled) { + this.dynamicscalingenabled = dynamicscalingenabled; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java index 934e84fe9d0..bfc9f9aad86 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java @@ -170,6 +170,10 @@ public class SystemVmResponse extends BaseResponse { @Param(description = "the systemvm agent version", since = "4.13.1") private String version; + @SerializedName(ApiConstants.IS_DYNAMICALLY_SCALABLE) + @Param(description = "true if vm contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory.") + private Boolean isDynamicallyScalable; + @Override public String getObjectId() { return this.getId(); @@ -442,4 +446,12 @@ public class SystemVmResponse extends BaseResponse { public void setVersion(String version) { this.version = version; } + + public Boolean getDynamicallyScalable() { + return isDynamicallyScalable; + } + + public void setDynamicallyScalable(Boolean dynamicallyScalable) { + isDynamicallyScalable = dynamicallyScalable; + } } 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 3e5ddbfcbc8..4c1ce803dca 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3916,6 +3916,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac if (currentServiceOffering.isDynamic() && !newServiceOffering.isDynamic()) { removeCustomOfferingDetails(vmId); } + Boolean dynamicScalingEnabled = vmForUpdate.isDynamicallyScalable() && newServiceOffering.isDynamicallyScalable() && UserVmManager.EnableDynamicallyScaleVm.valueIn(vmForUpdate.getDataCenterId()); + vmForUpdate.setDynamicallyScalable(dynamicScalingEnabled); return _vmDao.update(vmId, vmForUpdate); } 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 3a5f3182b73..c265bcd290d 100644 --- a/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java @@ -75,6 +75,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering @Column(name = "deployment_planner") private String deploymentPlanner = null; + @Column(name = "dynamically_scalable") + private boolean dynamicallyScalable; + // This is a delayed load value. If the value is null, // then this field has not been loaded yet. // Call service offering dao to load it. @@ -91,7 +94,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering } public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, String displayText, - ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) { + ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) { super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true); this.cpu = cpu; this.ramSize = ramSize; @@ -105,8 +108,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.vmType = vmType == null ? null : vmType.toString().toLowerCase(); } - public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, - boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType) { + public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, + boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, String hostTag, String deploymentPlanner, Boolean dynamicScalingEnabled) { super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true); this.cpu = cpu; this.ramSize = ramSize; @@ -114,55 +118,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.rateMbps = rateMbps; this.multicastRateMbps = multicastRateMbps; this.offerHA = offerHA; - this.limitCpuUse = limitCpuUse; + this.limitCpuUse = limitResourceUse; this.volatileVm = volatileVm; this.vmType = vmType == null ? null : vmType.toString().toLowerCase(); - } - - public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, - VirtualMachine.Type vmType, String hostTag) { - this(name, - cpu, - ramSize, - speed, - rateMbps, - multicastRateMbps, - offerHA, - limitResourceUse, - volatileVm, - displayText, - provisioningType, - useLocalStorage, - recreatable, - tags, - systemUse, - vmType - ); this.hostTag = hostTag; - } - - public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, - VirtualMachine.Type vmType, String hostTag, String deploymentPlanner) { - this(name, - cpu, - ramSize, - speed, - rateMbps, - multicastRateMbps, - offerHA, - limitResourceUse, - volatileVm, - displayText, - provisioningType, - useLocalStorage, - recreatable, - tags, - systemUse, - vmType, - hostTag); this.deploymentPlanner = deploymentPlanner; + this.dynamicallyScalable = dynamicScalingEnabled; } public ServiceOfferingVO(ServiceOfferingVO offering) { @@ -189,6 +150,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering volatileVm = offering.isVolatileVm(); hostTag = offering.getHostTag(); vmType = offering.getSystemVmType(); + dynamicallyScalable = offering.isDynamicallyScalable(); } @Override @@ -334,4 +296,13 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public boolean isCustomCpuSpeedSupported() { return isCustomized() && getDetail("minCPU") != null; } + + @Override + public boolean isDynamicallyScalable() { + return dynamicallyScalable; + } + + public void setDynamicallyScalable(boolean dynamicallyScalable) { + this.dynamicallyScalable = dynamicallyScalable; + } } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/db/VMEntityVO.java b/engine/schema/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/db/VMEntityVO.java index 4ab5f427591..494ffc6be23 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/db/VMEntityVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/db/VMEntityVO.java @@ -189,6 +189,9 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject details = new HashMap(); @@ -284,4 +287,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public void setDynamicFlag(boolean isdynamic) { isDynamic = isdynamic; } + + @Override + public boolean isDynamicallyScalable() { + return dynamicallyScalable; + } } diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java index 17def806c33..28f925915c9 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java @@ -374,7 +374,7 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu nodeVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner, hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, kubernetesCluster.getKeyPair(), - null, addrs, null, null, null, customParameterMap, null, null, null, null); + null, addrs, null, null, null, customParameterMap, null, null, null, null, true); if (LOGGER.isInfoEnabled()) { LOGGER.info(String.format("Created node VM : %s, %s in the Kubernetes cluster : %s", hostName, nodeVm.getUuid(), kubernetesCluster.getName())); } diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java index 4a96b9ed2ba..a67375eb4c2 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java @@ -72,6 +72,7 @@ import com.cloud.vm.Nic; import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContextImpl; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.UserVmManager; import com.google.common.base.Strings; public class KubernetesClusterStartWorker extends KubernetesClusterResourceModifierActionWorker { @@ -208,10 +209,11 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif logAndThrow(Level.ERROR, "Failed to read Kubernetes master configuration file", e); } String base64UserData = Base64.encodeBase64String(k8sMasterConfig.getBytes(StringUtils.getPreferredCharset())); + Boolean dynamicScalingEnabled = serviceOffering.isDynamicallyScalable() && clusterTemplate.isDynamicallyScalable() && UserVmManager.EnableDynamicallyScaleVm.valueIn(zone.getId()); masterVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner, hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, kubernetesCluster.getKeyPair(), - requestedIps, addrs, null, null, null, customParameterMap, null, null, null, null); + requestedIps, addrs, null, null, null, customParameterMap, null, null, null, null, dynamicScalingEnabled); if (LOGGER.isInfoEnabled()) { LOGGER.info(String.format("Created master VM ID: %s, %s in the Kubernetes cluster : %s", masterVm.getUuid(), hostName, kubernetesCluster.getName())); } @@ -262,10 +264,11 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif logAndThrow(Level.ERROR, "Failed to read Kubernetes master configuration file", e); } String base64UserData = Base64.encodeBase64String(k8sMasterConfig.getBytes(StringUtils.getPreferredCharset())); + Boolean dynamicScalingEnabled = serviceOffering.isDynamicallyScalable() && clusterTemplate.isDynamicallyScalable() && UserVmManager.EnableDynamicallyScaleVm.valueIn(zone.getId()); additionalMasterVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner, hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, kubernetesCluster.getKeyPair(), - null, addrs, null, null, null, customParameterMap, null, null, null, null); + null, addrs, null, null, null, customParameterMap, null, null, null, null, dynamicScalingEnabled); if (LOGGER.isInfoEnabled()) { LOGGER.info(String.format("Created master VM ID : %s, %s in the Kubernetes cluster : %s", additionalMasterVm.getUuid(), hostName, kubernetesCluster.getName())); } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 5c5ba55f197..1f28deae78b 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -1470,6 +1470,7 @@ public class ApiResponseHelper implements ResponseGenerator { vmResponse.setState(vm.getState().toString()); } + vmResponse.setDynamicallyScalable(vm.isDynamicallyScalable()); // for console proxies, add the active sessions if (vm.getType() == Type.ConsoleProxy) { ConsoleProxyVO proxy = ApiDBUtils.findConsoleProxy(vm.getId()); diff --git a/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java index 87b03748dbc..7692f544837 100644 --- a/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java @@ -113,6 +113,7 @@ public class ServiceOfferingJoinDaoImpl extends GenericDaoBase filteredDomainIds = filterChildSubDomains(domainIds); @@ -2524,7 +2524,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, typedProvisioningType, localStorageRequired, false, tags, isSystem, vmType, - hostTag, deploymentPlanner); + hostTag, deploymentPlanner, dynamicScalingEnabled); if (Boolean.TRUE.equals(isCustomizedIops) || isCustomizedIops == null) { minIops = null; diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java index 7d6c88870c0..8e982f0cc19 100644 --- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java @@ -54,7 +54,6 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; -import com.cloud.vm.UserVmManager; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @@ -258,7 +257,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis // Workaround to make sure the TO has the UUID we need for Niciri integration VMInstanceVO vmInstance = _virtualMachineDao.findById(to.getId()); // check if XStools/VMWare tools are present in the VM and dynamic scaling feature is enabled (per zone/global) - Boolean isDynamicallyScalable = vmInstance.isDynamicallyScalable() && UserVmManager.EnableDynamicallyScaleVm.valueIn(vm.getDataCenterId()); + Boolean isDynamicallyScalable = vmInstance.isDynamicallyScalable(); to.setEnableDynamicallyScaleVm(isDynamicallyScalable); to.setUuid(vmInstance.getUuid()); diff --git a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java index c7105495161..5e7f0a95264 100644 --- a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java +++ b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java @@ -1325,18 +1325,18 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScale vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, - null, true, null, null, null, null, null, null, null); + null, true, null, null, null, null, null, null, null, true); } else { if (zone.isSecurityGroupEnabled()) { vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, null, null, owner, "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, - null, null, true, null, null, null, null, null, null, null); + null, null, true, null, null, null, null, null, null, null, true); } else { vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), - null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, addrs, true, null, null, null, null, null, null, null); + null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, addrs, true, null, null, null, null, null, null, null, true); } } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 0fecd604995..9f732a38470 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -1881,6 +1881,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir _itMgr.checkIfCanUpgrade(vmInstance, newServiceOffering); ServiceOfferingVO currentServiceOffering = _offeringDao.findByIdIncludingRemoved(vmInstance.getId(), vmInstance.getServiceOfferingId()); + if (newServiceOffering.isDynamicallyScalable() != currentServiceOffering.isDynamicallyScalable()) { + throw new InvalidParameterValueException("Unable to Scale VM: since dynamicscalingenabled flag is not same for new service offering and old service offering"); + } + int newCpu = newServiceOffering.getCpu(); int newMemory = newServiceOffering.getRamSize(); int newSpeed = newServiceOffering.getSpeed(); @@ -2764,10 +2768,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir userData = vm.getUserData(); } - if (isDynamicallyScalable == null) { - isDynamicallyScalable = vm.isDynamicallyScalable(); - } - if (osTypeId == null) { osTypeId = vm.getGuestOSId(); } @@ -2778,6 +2778,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir if (isDynamicallyScalable == null) { isDynamicallyScalable = vm.isDynamicallyScalable(); + } else { + if (isDynamicallyScalable == true) { + if (!offering.isDynamicallyScalable()) { + throw new InvalidParameterValueException("Dynamic Scaling cannot be enabled on the VM since service offering is not dynamic scaling enabled"); + } + if (!UserVmManager.EnableDynamicallyScaleVm.valueIn(vm.getDataCenterId())) { + throw new InvalidParameterValueException("Dynamic Scaling cannot be enabled on the VM since global configuration \"enable.dynamic.scale.vm\" is false"); + } + } } boolean isVMware = (vm.getHypervisorType() == HypervisorType.VMware); @@ -3226,7 +3235,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList, Map customParametes, String customId, Map> dhcpOptionMap, - Map dataDiskTemplateToDiskOfferingMap, Map userVmOVFProperties) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, + Map dataDiskTemplateToDiskOfferingMap, Map userVmOVFProperties, Boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); @@ -3275,7 +3284,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId, dhcpOptionMap, - dataDiskTemplateToDiskOfferingMap, userVmOVFProperties); + dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled); } @@ -3285,7 +3294,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList, Map customParameters, String customId, Map> dhcpOptionMap, - Map dataDiskTemplateToDiskOfferingMap, Map userVmOVFProperties) throws InsufficientCapacityException, ConcurrentOperationException, + Map dataDiskTemplateToDiskOfferingMap, Map userVmOVFProperties, Boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); @@ -3386,7 +3395,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, dataDiskTemplateToDiskOfferingMap, - userVmOVFProperties); + userVmOVFProperties, dynamicScalingEnabled); } @Override @@ -3395,7 +3404,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List affinityGroupIdList, Map customParametrs, String customId, Map> dhcpOptionsMap, Map dataDiskTemplateToDiskOfferingMap, - Map userVmOVFPropertiesMap) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, + Map userVmOVFPropertiesMap, Boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); @@ -3447,7 +3456,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, httpmethod, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId, dhcpOptionsMap, - dataDiskTemplateToDiskOfferingMap, userVmOVFPropertiesMap); + dataDiskTemplateToDiskOfferingMap, userVmOVFPropertiesMap, dynamicScalingEnabled); } private NetworkVO getNetworkToAddToNetworkList(VirtualMachineTemplate template, Account owner, HypervisorType hypervisor, @@ -3562,11 +3571,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir @DB private UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate tmplt, String hostName, String displayName, Account owner, - Long diskOfferingId, Long diskSize, List networkList, List securityGroupIdList, String group, HTTPMethod httpmethod, String userData, - String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard, - List affinityGroupIdList, Map customParameters, String customId, Map> dhcpOptionMap, - Map datadiskTemplateToDiskOfferringMap, - Map userVmOVFPropertiesMap) throws InsufficientCapacityException, ResourceUnavailableException, + Long diskOfferingId, Long diskSize, List networkList, List securityGroupIdList, String group, HTTPMethod httpmethod, String userData, + String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard, + List affinityGroupIdList, Map customParameters, String customId, Map> dhcpOptionMap, + Map datadiskTemplateToDiskOfferringMap, + Map userVmOVFPropertiesMap, Boolean dynamicScalingEnabled) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { _accountMgr.checkAccess(caller, null, true, owner); @@ -3926,9 +3935,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } } + dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(dynamicScalingEnabled, offering, template, zone.getId()); + UserVmVO vm = commitUserVm(zone, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard, accountId, userId, offering, isIso, sshPublicKey, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, dhcpOptionMap, - datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap); + datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled); // Assign instance to the group try { @@ -3952,6 +3963,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir return vm; } + private Boolean checkIfDynamicScalingCanBeEnabled(Boolean dynamicScalingEnabled, ServiceOfferingVO offering, VMTemplateVO template, Long zoneId) { + if (dynamicScalingEnabled) { + if (!(offering.isDynamicallyScalable() && template.isDynamicallyScalable() && UserVmManager.EnableDynamicallyScaleVm.valueIn(zoneId))) { + s_logger.info("VM cannot be configured to be dynamically scalable if any of the service offering's dynamic scaling property, template's dynamic scaling property or global setting is false"); + } + } + return dynamicScalingEnabled && offering.isDynamicallyScalable() && template.isDynamicallyScalable() && UserVmManager.EnableDynamicallyScaleVm.valueIn(zoneId); + } + /** * Configures the Root disk size via User`s custom parameters. * If the Service Offering has the Root Disk size field configured then the User`s root disk custom parameter is overwritten by the service offering. @@ -4030,14 +4050,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir final long accountId, final long userId, final ServiceOffering offering, final boolean isIso, final String sshPublicKey, final LinkedHashMap> networkNicMap, final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map customParameters, final Map> extraDhcpOptionMap, final Map dataDiskTemplateToDiskOfferingMap, - final Map userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException { + final Map userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final Boolean dynamicScalingEnabled) throws InsufficientCapacityException { return Transaction.execute(new TransactionCallbackWithException() { @Override public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException { UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, template.getGuestOSId(), offering.isOfferHA(), offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, hostName, diskOfferingId); vm.setUuid(uuidName); - vm.setDynamicallyScalable(template.isDynamicallyScalable()); + vm.setDynamicallyScalable(dynamicScalingEnabled); Map details = template.getDetails(); if (details != null && !details.isEmpty()) { @@ -4221,13 +4241,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir final long accountId, final long userId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKey, final LinkedHashMap> networkNicMap, final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map customParameters, final Map> extraDhcpOptionMap, final Map dataDiskTemplateToDiskOfferingMap, - Map userVmOVFPropertiesMap) throws InsufficientCapacityException { + Map userVmOVFPropertiesMap, final Boolean dynamicScalingEnabled) throws InsufficientCapacityException { return commitUserVm(false, zone, null, null, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard, accountId, userId, offering, isIso, sshPublicKey, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap, - userVmOVFPropertiesMap, null); + userVmOVFPropertiesMap, null, dynamicScalingEnabled); } public void validateRootDiskResize(final HypervisorType hypervisorType, Long rootDiskSize, VMTemplateVO templateVO, UserVmVO vm, final Map customParameters) throws InvalidParameterValueException @@ -5312,6 +5332,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir Long templateId = cmd.getTemplateId(); + Boolean dynamicScalingEnabled = cmd.getDynamicScalingEnabled(); + VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); // Make sure a valid template ID was specified if (template == null) { @@ -5389,14 +5411,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId, size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData , sshKeyPairName , cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(), - dataDiskTemplateToDiskOfferingMap, userVmOVFProperties); + dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled); } } else { if (zone.isSecurityGroupEnabled()) { vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(), - dataDiskTemplateToDiskOfferingMap, userVmOVFProperties); + dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled); } else { if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) { @@ -5404,7 +5426,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(), - cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties); + cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled); } } // check if this templateId has a child ISO @@ -7480,11 +7502,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir final String uuidName = _uuidMgr.generateUuid(UserVm.class, null); final Host lastHost = powerState != VirtualMachine.PowerState.PowerOn ? host : null; + final Boolean dynamicScalingEnabled = serviceOffering.isDynamicallyScalable() && template.isDynamicallyScalable() && UserVmManager.EnableDynamicallyScaleVm.valueIn(zone.getId()); return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner, null, null, userData, caller, isDisplayVm, keyboard, accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKey, null, id, instanceName, uuidName, hypervisorType, customParameters, - null, null, null, powerState); + null, null, null, powerState, dynamicScalingEnabled); } @Override diff --git a/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java b/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java index ab73e63f287..97e15de6f84 100644 --- a/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java +++ b/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java @@ -214,7 +214,7 @@ public class DeploymentPlanningManagerImplTest { ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, - null, "FirstFitPlanner"); + null, "FirstFitPlanner", true); Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); @@ -229,7 +229,7 @@ public class DeploymentPlanningManagerImplTest { ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, - null, "UserDispersingPlanner"); + null, "UserDispersingPlanner", true); Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); @@ -245,7 +245,7 @@ public class DeploymentPlanningManagerImplTest { ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, - null, "FirstFitPlanner"); + null, "FirstFitPlanner", true); Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); DataCenterDeployment plan = new DataCenterDeployment(dataCenterId);