mirror of https://github.com/apache/cloudstack.git
server: VM dynamic scaling option granularity (#4643)
This PR introduces new granularity levels to configure VM dynamic scalability. Previously VM is configured to be dynamically scalable based on the template and global setting. Now we bringing this option to configure at service offering and VM level also.
VM can dynamically scale only when all flags are ON at VM level, template, service offering and global setting. If any of the flags is set to false then VM cannot be scalable. This result will be persisted in DB for each VM and will be honoured for that VM till it is updated.
We are introducing 'dynamicscalingallowed' parameter with permitted values of true or false for deployVM API and createServiceOffering API.
Following are the API parameter changes:
createServiceOffering API:
dynamicscalingenabled: an optional parameter of type Boolean with default value “true”.
deployVirtualMachine API:
dynamicscalingenabled: an optional parameter of type Boolean with default value “true”.
Following are the UI changes:
Service offering creation has ON/OFF switch for dynamic scaling enabled with default value true
This commit is contained in:
parent
1286ffd37b
commit
083646b3c3
|
|
@ -116,4 +116,6 @@ public interface ServiceOffering extends DiskOffering, InfrastructureEntity, Int
|
|||
String getDeploymentPlanner();
|
||||
|
||||
boolean isDynamic();
|
||||
|
||||
boolean isDynamicScalingEnabled();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ public interface UserVmService {
|
|||
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFProperties) throws InsufficientCapacityException,
|
||||
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled) throws InsufficientCapacityException,
|
||||
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
|
||||
|
||||
/**
|
||||
|
|
@ -300,7 +300,7 @@ public interface UserVmService {
|
|||
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFProperties) throws InsufficientCapacityException,
|
||||
Map<String, String> 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<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> templateOvfPropertiesMap)
|
||||
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled)
|
||||
|
||||
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
|
||||
|
||||
|
|
|
|||
|
|
@ -342,4 +342,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Partition,
|
|||
@Override
|
||||
boolean isDisplay();
|
||||
|
||||
boolean isDynamicallyScalable();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -838,6 +838,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 DYNAMIC_SCALING_ENABLED = "dynamicscalingenabled";
|
||||
|
||||
public static final String POOL_TYPE ="pooltype";
|
||||
|
||||
|
|
|
|||
|
|
@ -223,6 +223,10 @@ 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.DYNAMIC_SCALING_ENABLED, type = CommandType.BOOLEAN, since = "4.16",
|
||||
description = "true if virtual machine needs to be dynamically scalable of cpu or memory")
|
||||
protected Boolean isDynamicScalingEnabled;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -441,6 +445,10 @@ public class CreateServiceOfferingCmd extends BaseCmd {
|
|||
return storagePolicy;
|
||||
}
|
||||
|
||||
public boolean getDynamicScalingEnabled() {
|
||||
return isDynamicScalingEnabled == null ? true : isDynamicScalingEnabled;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -235,6 +235,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||
private Map vAppNetworks;
|
||||
|
||||
@Parameter(name = ApiConstants.DYNAMIC_SCALING_ENABLED, type = CommandType.BOOLEAN, since = "4.16",
|
||||
description = "true if virtual machine needs to be dynamically scalable")
|
||||
protected Boolean dynamicScalingEnabled;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -623,6 +627,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||
return bootIntoSetup;
|
||||
}
|
||||
|
||||
public boolean isDynamicScalingEnabled() {
|
||||
return dynamicScalingEnabled == null ? true : dynamicScalingEnabled;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction,
|
|||
|
||||
@Parameter(name = ApiConstants.IS_DYNAMICALLY_SCALABLE,
|
||||
type = CommandType.BOOLEAN,
|
||||
description = "true if VM contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory")
|
||||
description = "true if VM contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory. This can be updated only when dynamic scaling is enabled on template, service offering and the corresponding global setting")
|
||||
protected Boolean isDynamicallyScalable;
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "new host name of the vm. The VM has to be stopped/started for this update to take affect", since = "4.4")
|
||||
|
|
|
|||
|
|
@ -204,6 +204,10 @@ public class ServiceOfferingResponse extends BaseResponse {
|
|||
@Param(description = "Root disk size in GB", since = "4.15")
|
||||
private Long rootDiskSize;
|
||||
|
||||
@SerializedName(ApiConstants.DYNAMIC_SCALING_ENABLED)
|
||||
@Param(description = "true if virtual machine needs to be dynamically scalable of cpu or memory", since = "4.16")
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3917,6 +3917,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
if (currentServiceOffering.isDynamic() && !newServiceOffering.isDynamic()) {
|
||||
removeCustomOfferingDetails(vmId);
|
||||
}
|
||||
VMTemplateVO template = _templateDao.findById(vmForUpdate.getTemplateId());
|
||||
boolean dynamicScalingEnabled = _userVmMgr.checkIfDynamicScalingCanBeEnabled(vmForUpdate, newServiceOffering, template, vmForUpdate.getDataCenterId());
|
||||
vmForUpdate.setDynamicallyScalable(dynamicScalingEnabled);
|
||||
return _vmDao.update(vmId, vmForUpdate);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
|||
@Column(name = "deployment_planner")
|
||||
private String deploymentPlanner = null;
|
||||
|
||||
@Column(name = "dynamic_scaling_enabled")
|
||||
private boolean dynamicScalingEnabled = true;
|
||||
|
||||
// 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.dynamicScalingEnabled = 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();
|
||||
dynamicScalingEnabled = offering.isDynamicScalingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -334,4 +296,13 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
|||
public boolean isCustomCpuSpeedSupported() {
|
||||
return isCustomized() && getDetail("minCPU") != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamicScalingEnabled() {
|
||||
return dynamicScalingEnabled;
|
||||
}
|
||||
|
||||
public void setDynamicScalingEnabled(boolean dynamicScalingEnabled) {
|
||||
this.dynamicScalingEnabled = dynamicScalingEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
|
|||
this.dynamicallyScalable = dynamicallyScalable;
|
||||
}
|
||||
|
||||
public Boolean isDynamicallyScalable() {
|
||||
public boolean isDynamicallyScalable() {
|
||||
return dynamicallyScalable;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -189,6 +189,9 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject<State, Virt
|
|||
@Column(name = "backup_volumes")
|
||||
private String backupVolumes;
|
||||
|
||||
@Column(name = "dynamically_scalable")
|
||||
protected boolean dynamicallyScalable;
|
||||
|
||||
@Transient
|
||||
private VMReservationVO vmReservation;
|
||||
|
||||
|
|
@ -561,6 +564,11 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject<State, Virt
|
|||
return display;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamicallyScalable() {
|
||||
return dynamicallyScalable;
|
||||
}
|
||||
|
||||
public void setDisplay(boolean display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,97 @@
|
|||
-- Schema upgrade from 4.15.1.0 to 4.16.0.0
|
||||
--;
|
||||
|
||||
-- Adding dynamic scalable flag for service offering table
|
||||
ALTER TABLE `cloud`.`service_offering` ADD COLUMN `dynamic_scaling_enabled` tinyint(1) unsigned NOT NULL DEFAULT 1 COMMENT 'true(1) if VM needs to be dynamically scalable of cpu or memory';
|
||||
DROP VIEW IF EXISTS `cloud`.`service_offering_view`;
|
||||
CREATE VIEW `cloud`.`service_offering_view` AS
|
||||
SELECT
|
||||
`service_offering`.`id` AS `id`,
|
||||
`disk_offering`.`uuid` AS `uuid`,
|
||||
`disk_offering`.`name` AS `name`,
|
||||
`disk_offering`.`display_text` AS `display_text`,
|
||||
`disk_offering`.`provisioning_type` AS `provisioning_type`,
|
||||
`disk_offering`.`created` AS `created`,
|
||||
`disk_offering`.`tags` AS `tags`,
|
||||
`disk_offering`.`removed` AS `removed`,
|
||||
`disk_offering`.`use_local_storage` AS `use_local_storage`,
|
||||
`disk_offering`.`system_use` AS `system_use`,
|
||||
`disk_offering`.`customized_iops` AS `customized_iops`,
|
||||
`disk_offering`.`min_iops` AS `min_iops`,
|
||||
`disk_offering`.`max_iops` AS `max_iops`,
|
||||
`disk_offering`.`hv_ss_reserve` AS `hv_ss_reserve`,
|
||||
`disk_offering`.`bytes_read_rate` AS `bytes_read_rate`,
|
||||
`disk_offering`.`bytes_read_rate_max` AS `bytes_read_rate_max`,
|
||||
`disk_offering`.`bytes_read_rate_max_length` AS `bytes_read_rate_max_length`,
|
||||
`disk_offering`.`bytes_write_rate` AS `bytes_write_rate`,
|
||||
`disk_offering`.`bytes_write_rate_max` AS `bytes_write_rate_max`,
|
||||
`disk_offering`.`bytes_write_rate_max_length` AS `bytes_write_rate_max_length`,
|
||||
`disk_offering`.`iops_read_rate` AS `iops_read_rate`,
|
||||
`disk_offering`.`iops_read_rate_max` AS `iops_read_rate_max`,
|
||||
`disk_offering`.`iops_read_rate_max_length` AS `iops_read_rate_max_length`,
|
||||
`disk_offering`.`iops_write_rate` AS `iops_write_rate`,
|
||||
`disk_offering`.`iops_write_rate_max` AS `iops_write_rate_max`,
|
||||
`disk_offering`.`iops_write_rate_max_length` AS `iops_write_rate_max_length`,
|
||||
`disk_offering`.`cache_mode` AS `cache_mode`,
|
||||
`disk_offering`.`disk_size` AS `root_disk_size`,
|
||||
`service_offering`.`cpu` AS `cpu`,
|
||||
`service_offering`.`speed` AS `speed`,
|
||||
`service_offering`.`ram_size` AS `ram_size`,
|
||||
`service_offering`.`nw_rate` AS `nw_rate`,
|
||||
`service_offering`.`mc_rate` AS `mc_rate`,
|
||||
`service_offering`.`ha_enabled` AS `ha_enabled`,
|
||||
`service_offering`.`limit_cpu_use` AS `limit_cpu_use`,
|
||||
`service_offering`.`host_tag` AS `host_tag`,
|
||||
`service_offering`.`default_use` AS `default_use`,
|
||||
`service_offering`.`vm_type` AS `vm_type`,
|
||||
`service_offering`.`sort_key` AS `sort_key`,
|
||||
`service_offering`.`is_volatile` AS `is_volatile`,
|
||||
`service_offering`.`deployment_planner` AS `deployment_planner`,
|
||||
`service_offering`.`dynamic_scaling_enabled` AS `dynamic_scaling_enabled`,
|
||||
`vsphere_storage_policy`.`value` AS `vsphere_storage_policy`,
|
||||
GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id,
|
||||
GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid,
|
||||
GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name,
|
||||
GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path,
|
||||
GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id,
|
||||
GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid,
|
||||
GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name,
|
||||
IFNULL(`min_compute_details`.`value`, `cpu`) AS min_cpu,
|
||||
IFNULL(`max_compute_details`.`value`, `cpu`) AS max_cpu,
|
||||
IFNULL(`min_memory_details`.`value`, `ram_size`) AS min_memory,
|
||||
IFNULL(`max_memory_details`.`value`, `ram_size`) AS max_memory
|
||||
FROM
|
||||
`cloud`.`service_offering`
|
||||
INNER JOIN
|
||||
`cloud`.`disk_offering_view` AS `disk_offering` ON service_offering.id = disk_offering.id
|
||||
LEFT JOIN
|
||||
`cloud`.`service_offering_details` AS `domain_details` ON `domain_details`.`service_offering_id` = `disk_offering`.`id` AND `domain_details`.`name`='domainid'
|
||||
LEFT JOIN
|
||||
`cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`)
|
||||
LEFT JOIN
|
||||
`cloud`.`service_offering_details` AS `zone_details` ON `zone_details`.`service_offering_id` = `disk_offering`.`id` AND `zone_details`.`name`='zoneid'
|
||||
LEFT JOIN
|
||||
`cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`)
|
||||
LEFT JOIN
|
||||
`cloud`.`service_offering_details` AS `min_compute_details` ON `min_compute_details`.`service_offering_id` = `disk_offering`.`id`
|
||||
AND `min_compute_details`.`name` = 'mincpunumber'
|
||||
LEFT JOIN
|
||||
`cloud`.`service_offering_details` AS `max_compute_details` ON `max_compute_details`.`service_offering_id` = `disk_offering`.`id`
|
||||
AND `max_compute_details`.`name` = 'maxcpunumber'
|
||||
LEFT JOIN
|
||||
`cloud`.`service_offering_details` AS `min_memory_details` ON `min_memory_details`.`service_offering_id` = `disk_offering`.`id`
|
||||
AND `min_memory_details`.`name` = 'minmemory'
|
||||
LEFT JOIN
|
||||
`cloud`.`service_offering_details` AS `max_memory_details` ON `max_memory_details`.`service_offering_id` = `disk_offering`.`id`
|
||||
AND `max_memory_details`.`name` = 'maxmemory'
|
||||
LEFT JOIN
|
||||
`cloud`.`service_offering_details` AS `vsphere_storage_policy` ON `vsphere_storage_policy`.`service_offering_id` = `disk_offering`.`id`
|
||||
AND `vsphere_storage_policy`.`name` = 'storagepolicy'
|
||||
WHERE
|
||||
`disk_offering`.`state`='Active'
|
||||
GROUP BY
|
||||
`service_offering`.`id`;
|
||||
|
||||
--;
|
||||
-- Stored procedure to do idempotent column add;
|
||||
-- This is copied from schema-41000to41100.sql
|
||||
|
|
@ -300,7 +391,7 @@ from
|
|||
left join
|
||||
`cloud`.`resource_count` secondary_storage_count ON domain.id = secondary_storage_count.domain_id
|
||||
and secondary_storage_count.type = 'secondary_storage';
|
||||
|
||||
|
||||
-- Update name for global configuration user.vm.readonly.ui.details
|
||||
Update configuration set name='user.vm.readonly.details' where name='user.vm.readonly.ui.details';
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
|||
@Column(name = "deployment_planner")
|
||||
private String deploymentPlanner = null;
|
||||
|
||||
@Column(name = "dynamic_scaling_enabled")
|
||||
private boolean dynamicScalingEnabled;
|
||||
|
||||
@Transient
|
||||
Map<String, String> details = new HashMap<String, String>();
|
||||
|
||||
|
|
@ -284,4 +287,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
|||
public void setDynamicFlag(boolean isdynamic) {
|
||||
isDynamic = isdynamic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamicScalingEnabled() {
|
||||
return dynamicScalingEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
|||
controlVm = 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, true);
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info(String.format("Created control VM ID: %s, %s in the Kubernetes cluster : %s", controlVm.getUuid(), hostName, kubernetesCluster.getName()));
|
||||
}
|
||||
|
|
@ -265,7 +265,7 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
|||
additionalControlVm = 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 control VM ID : %s, %s in the Kubernetes cluster : %s", additionalControlVm.getUuid(), hostName, kubernetesCluster.getName()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -2971,11 +2971,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||
// 1. Only return offerings with the same storage type than the storage pool where the VM's root volume is allocated
|
||||
sc.addAnd("useLocalStorage", SearchCriteria.Op.EQ, isRootVolumeUsingLocalStorage);
|
||||
|
||||
// 2.In case vm is running return only offerings greater than equal to current offering compute.
|
||||
// 2.In case vm is running return only offerings greater than equal to current offering compute and offering's dynamic scalability should match
|
||||
if (vmInstance.getState() == VirtualMachine.State.Running) {
|
||||
sc.addAnd("cpu", Op.GTEQ, currentVmOffering.getCpu());
|
||||
sc.addAnd("speed", Op.GTEQ, currentVmOffering.getSpeed());
|
||||
sc.addAnd("ramSize", Op.GTEQ, currentVmOffering.getRamSize());
|
||||
sc.addAnd("dynamicScalingEnabled", Op.EQ, currentVmOffering.isDynamicScalingEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ public class ServiceOfferingJoinDaoImpl extends GenericDaoBase<ServiceOfferingJo
|
|||
offeringResponse.setObjectName("serviceoffering");
|
||||
offeringResponse.setIscutomized(offering.isDynamic());
|
||||
offeringResponse.setCacheMode(offering.getCacheMode());
|
||||
offeringResponse.setDynamicScalingEnabled(offering.isDynamicScalingEnabled());
|
||||
|
||||
if (offeringDetails != null && !offeringDetails.isEmpty()) {
|
||||
String vsphereStoragePolicyId = offeringDetails.get(ApiConstants.STORAGE_POLICY);
|
||||
|
|
|
|||
|
|
@ -193,6 +193,9 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit
|
|||
@Column(name = "root_disk_size")
|
||||
private Long rootDiskSize;
|
||||
|
||||
@Column(name = "dynamic_scaling_enabled")
|
||||
private boolean dynamicScalingEnabled;
|
||||
|
||||
public ServiceOfferingJoinVO() {
|
||||
}
|
||||
|
||||
|
|
@ -397,4 +400,12 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit
|
|||
public Long getRootDiskSize() {
|
||||
return rootDiskSize ;
|
||||
}
|
||||
|
||||
public boolean isDynamicScalingEnabled() {
|
||||
return dynamicScalingEnabled;
|
||||
}
|
||||
|
||||
public void setDynamicScalingEnabled(boolean dynamicScalingEnabled) {
|
||||
this.dynamicScalingEnabled = dynamicScalingEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2481,7 +2481,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||
cmd.getBytesWriteRate(), cmd.getBytesWriteRateMax(), cmd.getBytesWriteRateMaxLength(),
|
||||
cmd.getIopsReadRate(), cmd.getIopsReadRateMax(), cmd.getIopsReadRateMaxLength(),
|
||||
cmd.getIopsWriteRate(), cmd.getIopsWriteRateMax(), cmd.getIopsWriteRateMaxLength(),
|
||||
cmd.getHypervisorSnapshotReserve(), cmd.getCacheMode(), storagePolicyId);
|
||||
cmd.getHypervisorSnapshotReserve(), cmd.getCacheMode(), storagePolicyId, cmd.getDynamicScalingEnabled());
|
||||
}
|
||||
|
||||
protected ServiceOfferingVO createServiceOffering(final long userId, final boolean isSystem, final VirtualMachine.Type vmType,
|
||||
|
|
@ -2492,7 +2492,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||
Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength,
|
||||
Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength,
|
||||
Long iopsWriteRate, Long iopsWriteRateMax, Long iopsWriteRateMaxLength,
|
||||
final Integer hypervisorSnapshotReserve, String cacheMode, final Long storagePolicyID) {
|
||||
final Integer hypervisorSnapshotReserve, String cacheMode, final Long storagePolicyID, final boolean dynamicScalingEnabled) {
|
||||
// Filter child domains when both parent and child domains are present
|
||||
List<Long> 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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -257,9 +256,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());
|
||||
to.setEnableDynamicallyScaleVm(isDynamicallyScalable);
|
||||
to.setEnableDynamicallyScaleVm(vmInstance.isDynamicallyScalable());
|
||||
to.setUuid(vmInstance.getUuid());
|
||||
|
||||
to.setVmData(vmProfile.getVmData());
|
||||
|
|
|
|||
|
|
@ -1325,18 +1325,18 @@ public class AutoScaleManagerImpl<Type> 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
|
||||
|
|
@ -124,4 +126,7 @@ public interface UserVmManager extends UserVmService {
|
|||
void persistDeviceBusInfo(UserVmVO paramUserVmVO, String paramString);
|
||||
|
||||
HashMap<Long, List<VmNetworkStatsEntry>> getVmNetworkStatistics(long hostId, String hostName, List<Long> vmIds);
|
||||
|
||||
boolean checkIfDynamicScalingCanBeEnabled(VirtualMachine vm, ServiceOffering offering, VirtualMachineTemplate template, Long zoneId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1888,6 +1888,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
_itMgr.checkIfCanUpgrade(vmInstance, newServiceOffering);
|
||||
|
||||
ServiceOfferingVO currentServiceOffering = _offeringDao.findByIdIncludingRemoved(vmInstance.getId(), vmInstance.getServiceOfferingId());
|
||||
if (newServiceOffering.isDynamicScalingEnabled() != currentServiceOffering.isDynamicScalingEnabled()) {
|
||||
throw new InvalidParameterValueException("Unable to Scale VM: since dynamic scaling enabled flag is not same for new service offering and old service offering");
|
||||
}
|
||||
|
||||
int newCpu = newServiceOffering.getCpu();
|
||||
int newMemory = newServiceOffering.getRamSize();
|
||||
int newSpeed = newServiceOffering.getSpeed();
|
||||
|
|
@ -1939,7 +1943,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
|
||||
// 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("Unable to Scale the VM: " + vmInstance.getUuid() + " as VM is not configured to be dynamically scalable");
|
||||
}
|
||||
|
||||
// Check disable threshold for cluster is not crossed
|
||||
|
|
@ -2777,10 +2781,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
userData = vm.getUserData();
|
||||
}
|
||||
|
||||
if (isDynamicallyScalable == null) {
|
||||
isDynamicallyScalable = vm.isDynamicallyScalable();
|
||||
}
|
||||
|
||||
if (osTypeId == null) {
|
||||
osTypeId = vm.getGuestOSId();
|
||||
}
|
||||
|
|
@ -2791,6 +2791,20 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
|
||||
if (isDynamicallyScalable == null) {
|
||||
isDynamicallyScalable = vm.isDynamicallyScalable();
|
||||
} else {
|
||||
if (isDynamicallyScalable == true) {
|
||||
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
|
||||
if (!template.isDynamicallyScalable()) {
|
||||
throw new InvalidParameterValueException("Dynamic Scaling cannot be enabled for the VM since its template does not have dynamic scaling enabled");
|
||||
}
|
||||
if (!offering.isDynamicScalingEnabled()) {
|
||||
throw new InvalidParameterValueException("Dynamic Scaling cannot be enabled for the VM since its service offering does not have dynamic scaling enabled");
|
||||
}
|
||||
if (!UserVmManager.EnableDynamicallyScaleVm.valueIn(vm.getDataCenterId())) {
|
||||
s_logger.debug(String.format("Dynamic Scaling cannot be enabled for the VM %s since the global setting enable.dynamic.scale.vm is set to false", vm.getUuid()));
|
||||
throw new InvalidParameterValueException("Dynamic Scaling cannot be enabled for the VM since corresponding global setting is set to false");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isVMware = (vm.getHypervisorType() == HypervisorType.VMware);
|
||||
|
|
@ -3239,7 +3253,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<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParametes, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
StorageUnavailableException, ResourceAllocationException {
|
||||
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
|
|
@ -3288,7 +3302,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);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -3298,7 +3312,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
|
||||
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties) throws InsufficientCapacityException, ConcurrentOperationException,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException,
|
||||
ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
|
||||
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
|
|
@ -3399,7 +3413,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
|
||||
|
|
@ -3408,7 +3422,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<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParametrs, String customId, Map<String, Map<Integer, String>> dhcpOptionsMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFPropertiesMap) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
StorageUnavailableException, ResourceAllocationException {
|
||||
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
|
|
@ -3460,7 +3474,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,
|
||||
|
|
@ -3575,11 +3589,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<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData,
|
||||
String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
||||
Map<String, String> userVmOVFPropertiesMap) throws InsufficientCapacityException, ResourceUnavailableException,
|
||||
Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData,
|
||||
String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
||||
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled) throws InsufficientCapacityException, ResourceUnavailableException,
|
||||
ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException {
|
||||
|
||||
_accountMgr.checkAccess(caller, null, true, owner);
|
||||
|
|
@ -3939,9 +3953,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
}
|
||||
}
|
||||
|
||||
dynamicScalingEnabled = dynamicScalingEnabled && checkIfDynamicScalingCanBeEnabled(null, 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 {
|
||||
|
|
@ -3965,6 +3981,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
return vm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkIfDynamicScalingCanBeEnabled(VirtualMachine vm, ServiceOffering offering, VirtualMachineTemplate template, Long zoneId) {
|
||||
boolean canEnableDynamicScaling = (vm != null ? vm.isDynamicallyScalable() : true) && offering.isDynamicScalingEnabled() && template.isDynamicallyScalable() && UserVmManager.EnableDynamicallyScaleVm.valueIn(zoneId);
|
||||
if (!canEnableDynamicScaling) {
|
||||
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 canEnableDynamicScaling;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
@ -4043,14 +4069,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<String, List<NicProfile>> networkNicMap,
|
||||
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
|
||||
final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException {
|
||||
final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled) throws InsufficientCapacityException {
|
||||
return Transaction.execute(new TransactionCallbackWithException<UserVmVO, InsufficientCapacityException>() {
|
||||
@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<String, String> details = template.getDetails();
|
||||
if (details != null && !details.isEmpty()) {
|
||||
|
|
@ -4235,13 +4261,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<String, List<NicProfile>> networkNicMap,
|
||||
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final Map<String,
|
||||
Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFPropertiesMap) throws InsufficientCapacityException {
|
||||
Map<String, String> 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<String, String> customParameters) throws InvalidParameterValueException
|
||||
|
|
@ -5326,6 +5352,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
|
||||
Long templateId = cmd.getTemplateId();
|
||||
|
||||
boolean dynamicScalingEnabled = cmd.isDynamicScalingEnabled();
|
||||
|
||||
VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId);
|
||||
// Make sure a valid template ID was specified
|
||||
if (template == null) {
|
||||
|
|
@ -5403,14 +5431,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()) {
|
||||
|
|
@ -5418,7 +5446,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
|
||||
|
|
@ -7083,13 +7111,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
vm.setIsoId(newTemplateId);
|
||||
vm.setGuestOSId(template.getGuestOSId());
|
||||
vm.setTemplateId(newTemplateId);
|
||||
_vmDao.update(vmId, vm);
|
||||
} else {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, newTemplateId);
|
||||
vm.setGuestOSId(template.getGuestOSId());
|
||||
vm.setTemplateId(newTemplateId);
|
||||
_vmDao.update(vmId, vm);
|
||||
}
|
||||
// check and update VM if it can be dynamically scalable with the new template
|
||||
updateVMDynamicallyScalabilityUsingTemplate(vm, newTemplateId);
|
||||
} else {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, null);
|
||||
}
|
||||
|
|
@ -7177,6 +7205,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
|
||||
}
|
||||
|
||||
private void updateVMDynamicallyScalabilityUsingTemplate(UserVmVO vm, Long newTemplateId) {
|
||||
ServiceOfferingVO serviceOffering = _offeringDao.findById(vm.getServiceOfferingId());
|
||||
VMTemplateVO newTemplate = _templateDao.findById(newTemplateId);
|
||||
boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(vm, serviceOffering, newTemplate, vm.getDataCenterId());
|
||||
vm.setDynamicallyScalable(dynamicScalingEnabled);
|
||||
_vmDao.update(vm.getId(), vm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform basic checkings to make sure restore is possible. If not, #InvalidParameterValueException is thrown.
|
||||
*
|
||||
|
|
@ -7494,11 +7530,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 = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, 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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ class TestScaleVm(cloudstackTestCase):
|
|||
if cls.template == FAILED:
|
||||
assert False, "get_template() failed to return template\
|
||||
with description %s" % cls.services["ostype"]
|
||||
cls.template = Template.update(
|
||||
cls.template,
|
||||
cls.apiclient,
|
||||
isdynamicallyscalable='true'
|
||||
)
|
||||
else:
|
||||
cls.template = Template.register(
|
||||
cls.apiclient,
|
||||
|
|
@ -107,6 +112,18 @@ class TestScaleVm(cloudstackTestCase):
|
|||
value="true"
|
||||
)
|
||||
|
||||
cls.small_offering_dynamic_scaling_disabled = ServiceOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["service_offerings"]["small"],
|
||||
dynamicscalingenabled=False
|
||||
)
|
||||
|
||||
cls.big_offering_dynamic_scaling_disabled = ServiceOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["service_offerings"]["small"],
|
||||
dynamicscalingenabled=False
|
||||
)
|
||||
|
||||
# create a virtual machine
|
||||
cls.virtual_machine = VirtualMachine.create(
|
||||
cls.apiclient,
|
||||
|
|
@ -117,8 +134,42 @@ class TestScaleVm(cloudstackTestCase):
|
|||
mode=cls.services["mode"]
|
||||
)
|
||||
|
||||
# create a virtual machine which cannot be dynamically scalable
|
||||
cls.virtual_machine_with_service_offering_dynamic_scaling_disabled = VirtualMachine.create(
|
||||
cls.apiclient,
|
||||
cls.services["small"],
|
||||
accountid=cls.account.name,
|
||||
domainid=cls.account.domainid,
|
||||
serviceofferingid=cls.small_offering_dynamic_scaling_disabled.id,
|
||||
mode=cls.services["mode"]
|
||||
)
|
||||
|
||||
# create a virtual machine which cannot be dynamically scalable
|
||||
cls.virtual_machine_not_dynamically_scalable = VirtualMachine.create(
|
||||
cls.apiclient,
|
||||
cls.services["small"],
|
||||
accountid=cls.account.name,
|
||||
domainid=cls.account.domainid,
|
||||
serviceofferingid=cls.small_offering.id,
|
||||
mode=cls.services["mode"],
|
||||
dynamicscalingenabled=False
|
||||
)
|
||||
|
||||
cls._cleanup = [
|
||||
cls.small_offering,
|
||||
cls.big_offering,
|
||||
cls.small_offering_dynamic_scaling_disabled,
|
||||
cls.big_offering_dynamic_scaling_disabled,
|
||||
cls.account
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
Configurations.update(
|
||||
cls.apiclient,
|
||||
name="enable.dynamic.scale.vm",
|
||||
value="false"
|
||||
)
|
||||
super(TestScaleVm,cls).tearDownClass()
|
||||
return
|
||||
|
||||
|
|
@ -132,11 +183,6 @@ class TestScaleVm(cloudstackTestCase):
|
|||
%s" % self.hypervisor)
|
||||
|
||||
def tearDown(self):
|
||||
Configurations.update(
|
||||
self.apiclient,
|
||||
name="enable.dynamic.scale.vm",
|
||||
value="false"
|
||||
)
|
||||
# Clean up, terminate the created ISOs
|
||||
super(TestScaleVm,self).tearDown()
|
||||
return
|
||||
|
|
@ -265,3 +311,173 @@ class TestScaleVm(cloudstackTestCase):
|
|||
"Check the state of VM"
|
||||
)
|
||||
return
|
||||
|
||||
@attr(tags=["advanced", "basic"], required_hardware="false")
|
||||
def test_02_scale_vm(self):
|
||||
"""Test scale virtual machine which is created from a service offering for which dynamicscalingenabled is false. Scaling operation should fail.
|
||||
"""
|
||||
|
||||
# VirtualMachine should be updated to tell cloudstack
|
||||
# it has PV tools
|
||||
# available and successfully scaled. We will only mock
|
||||
# that behaviour
|
||||
# here but it is not expected in production since the VM
|
||||
# scaling is not
|
||||
# guaranteed until tools are installed, vm rebooted
|
||||
|
||||
# If hypervisor is Vmware, then check if
|
||||
# the vmware tools are installed and the process is running
|
||||
# Vmware tools are necessary for scale VM operation
|
||||
if self.hypervisor.lower() == "vmware":
|
||||
sshClient = self.virtual_machine_with_service_offering_dynamic_scaling_disabled.get_ssh_client()
|
||||
result = str(
|
||||
sshClient.execute("service vmware-tools status")).lower()
|
||||
self.debug("and result is: %s" % result)
|
||||
if not "running" in result:
|
||||
self.skipTest("Skipping scale VM operation because\
|
||||
VMware tools are not installed on the VM")
|
||||
|
||||
list_vm_response = VirtualMachine.list(
|
||||
self.apiclient,
|
||||
id=self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id
|
||||
)
|
||||
self.assertEqual(
|
||||
isinstance(list_vm_response, list),
|
||||
True,
|
||||
"Check list response returns a valid list"
|
||||
)
|
||||
self.assertNotEqual(
|
||||
list_vm_response,
|
||||
None,
|
||||
"Check virtual machine is in listVirtualMachines"
|
||||
)
|
||||
|
||||
vm_response = list_vm_response[0]
|
||||
self.assertEqual(
|
||||
vm_response.id,
|
||||
self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id,
|
||||
"Check virtual machine ID of scaled VM"
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
vm_response.isdynamicallyscalable,
|
||||
False,
|
||||
"Check if VM is not dynamically scalable"
|
||||
)
|
||||
|
||||
self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is disabled and VM state %s" % (
|
||||
self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id,
|
||||
self.big_offering_dynamic_scaling_disabled.id,
|
||||
self.virtual_machine.state
|
||||
))
|
||||
|
||||
cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
|
||||
cmd.serviceofferingid = self.big_offering_dynamic_scaling_disabled.id
|
||||
cmd.id = self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id
|
||||
|
||||
try:
|
||||
self.apiclient.scaleVirtualMachine(cmd)
|
||||
except Exception as e:
|
||||
if "LicenceRestriction" in str(e):
|
||||
self.skipTest("Your XenServer License does not allow scaling")
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
self.fail("Expected an exception to be thrown, failing")
|
||||
|
||||
self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is enabled and VM state %s" % (
|
||||
self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id,
|
||||
self.big_offering.id,
|
||||
self.virtual_machine.state
|
||||
))
|
||||
|
||||
cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
|
||||
cmd.serviceofferingid = self.big_offering.id
|
||||
cmd.id = self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id
|
||||
|
||||
try:
|
||||
self.apiclient.scaleVirtualMachine(cmd)
|
||||
except Exception as e:
|
||||
if "LicenceRestriction" in str(e):
|
||||
self.skipTest("Your XenServer License does not allow scaling")
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
self.fail("Expected an exception to be thrown, failing")
|
||||
|
||||
return
|
||||
|
||||
@attr(tags=["advanced", "basic"], required_hardware="false")
|
||||
def test_03_scale_vm(self):
|
||||
"""Test scale virtual machine which is not dynamically scalable to a service offering. Scaling operation should fail.
|
||||
"""
|
||||
# Validate the following
|
||||
# Scale up the vm which is not dynamically scalable and see if scaling operation fails
|
||||
|
||||
# VirtualMachine should be updated to tell cloudstack
|
||||
# it has PV tools
|
||||
# available and successfully scaled. We will only mock
|
||||
# that behaviour
|
||||
# here but it is not expected in production since the VM
|
||||
# scaling is not
|
||||
# guaranteed until tools are installed, vm rebooted
|
||||
|
||||
# If hypervisor is Vmware, then check if
|
||||
# the vmware tools are installed and the process is running
|
||||
# Vmware tools are necessary for scale VM operation
|
||||
if self.hypervisor.lower() == "vmware":
|
||||
sshClient = self.virtual_machine_not_dynamically_scalable.get_ssh_client()
|
||||
result = str(
|
||||
sshClient.execute("service vmware-tools status")).lower()
|
||||
self.debug("and result is: %s" % result)
|
||||
if not "running" in result:
|
||||
self.skipTest("Skipping scale VM operation because\
|
||||
VMware tools are not installed on the VM")
|
||||
|
||||
list_vm_response = VirtualMachine.list(
|
||||
self.apiclient,
|
||||
id=self.virtual_machine_not_dynamically_scalable.id
|
||||
)
|
||||
self.assertEqual(
|
||||
isinstance(list_vm_response, list),
|
||||
True,
|
||||
"Check list response returns a valid list"
|
||||
)
|
||||
self.assertNotEqual(
|
||||
list_vm_response,
|
||||
None,
|
||||
"Check virtual machine is in listVirtualMachines"
|
||||
)
|
||||
vm_response = list_vm_response[0]
|
||||
self.assertEqual(
|
||||
vm_response.id,
|
||||
self.virtual_machine_not_dynamically_scalable.id,
|
||||
"Check virtual machine ID of scaled VM"
|
||||
)
|
||||
self.assertEqual(
|
||||
vm_response.isdynamicallyscalable,
|
||||
False,
|
||||
"Check if VM is not dynamically scalable"
|
||||
)
|
||||
|
||||
self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is enabled and VM state %s" % (
|
||||
self.virtual_machine_not_dynamically_scalable.id,
|
||||
self.big_offering.id,
|
||||
self.virtual_machine.state
|
||||
))
|
||||
|
||||
cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
|
||||
cmd.serviceofferingid = self.big_offering.id
|
||||
cmd.id = self.virtual_machine_not_dynamically_scalable.id
|
||||
|
||||
try:
|
||||
self.apiclient.scaleVirtualMachine(cmd)
|
||||
except Exception as e:
|
||||
if "LicenceRestriction" in str(e):
|
||||
self.skipTest("Your XenServer License does not allow scaling")
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
self.fail("Expected an exception to be thrown, failing")
|
||||
|
||||
return
|
||||
|
|
@ -522,7 +522,7 @@ class VirtualMachine:
|
|||
method='GET', hypervisor=None, customcpunumber=None,
|
||||
customcpuspeed=None, custommemory=None, rootdisksize=None,
|
||||
rootdiskcontroller=None, vpcid=None, macaddress=None, datadisktemplate_diskoffering_list={},
|
||||
properties=None, nicnetworklist=None, bootmode=None, boottype=None):
|
||||
properties=None, nicnetworklist=None, bootmode=None, boottype=None, dynamicscalingenabled=None):
|
||||
"""Create the instance"""
|
||||
|
||||
cmd = deployVirtualMachine.deployVirtualMachineCmd()
|
||||
|
|
@ -615,6 +615,9 @@ class VirtualMachine:
|
|||
if "dhcpoptionsnetworklist" in services:
|
||||
cmd.dhcpoptionsnetworklist = services["dhcpoptionsnetworklist"]
|
||||
|
||||
if dynamicscalingenabled is not None:
|
||||
cmd.dynamicscalingenabled = dynamicscalingenabled
|
||||
|
||||
cmd.details = [{}]
|
||||
|
||||
if customcpunumber:
|
||||
|
|
@ -2293,6 +2296,9 @@ class ServiceOffering:
|
|||
if "offerha" in services:
|
||||
cmd.offerha = services["offerha"]
|
||||
|
||||
if "dynamicscalingenabled" in services:
|
||||
cmd.dynamicscalingenabled = services["dynamicscalingenabled"]
|
||||
|
||||
# Service Offering private to that domain
|
||||
if domainid:
|
||||
cmd.domainid = domainid
|
||||
|
|
|
|||
|
|
@ -783,6 +783,7 @@
|
|||
"label.drag.new.position": "Ziehe zu neuer Position",
|
||||
"label.driver": "Treiber",
|
||||
"label.duration.in.sec": "Dauer (in Sekunden)",
|
||||
"label.dynamicscalingenabled": "Dynamische Skalierung aktiviert",
|
||||
"label.edit": "Bearbeiten",
|
||||
"label.edit.acl.list": "Edit ACL List",
|
||||
"label.edit.acl.rule": "ACL-Regel bearbeiten",
|
||||
|
|
|
|||
|
|
@ -810,6 +810,8 @@
|
|||
"label.drag.new.position": "Drag to new position",
|
||||
"label.driver": "Driver",
|
||||
"label.duration.in.sec": "Duration (in sec)",
|
||||
"label.dynamicscalingenabled": "Dynamic Scaling Enabled",
|
||||
"label.dynamicscalingenabled.tooltip": "VM can dynamically scale only when dynamic scaling is enabled on template, service offering and global setting",
|
||||
"label.edit": "Edit",
|
||||
"label.edit.acl.list": "Edit ACL List",
|
||||
"label.edit.acl.rule": "Edit ACL rule",
|
||||
|
|
|
|||
|
|
@ -670,6 +670,7 @@
|
|||
"label.drag.new.position": "Arrastrar a una nueva ubicaci\u00f3n",
|
||||
"label.driver": "Controlador",
|
||||
"label.duration.in.sec": "Duraci\u00f3n (en seg)",
|
||||
"label.dynamicscalingenabled": "Escalado din\u00e1mico habilitado",
|
||||
"label.edit": "Editar",
|
||||
"label.edit.acl.list": "Edit ACL List",
|
||||
"label.edit.acl.rule": "Editar regla ACL",
|
||||
|
|
|
|||
|
|
@ -658,6 +658,7 @@
|
|||
"label.drag.new.position": "\u00daj helyre h\u00faz\u00e1s",
|
||||
"label.driver": "Driver",
|
||||
"label.duration.in.sec": "Id\u0151tartam (mp)",
|
||||
"label.dynamicscalingenabled": "dinamikus méretezés engedélyezve",
|
||||
"label.edit": "Szerkeszt\u00e9s",
|
||||
"label.edit.acl.list": "Edit ACL List",
|
||||
"label.edit.acl.rule": "ACL szab\u00e1ly szerkeszt\u00e9se",
|
||||
|
|
|
|||
|
|
@ -658,6 +658,7 @@
|
|||
"label.dpd": "Dead Peer detectie",
|
||||
"label.drag.new.position": "Sleep naar nieuwe positie",
|
||||
"label.driver": "Driver",
|
||||
"label.dynamicscalingenabled": "Dynamisch schalen ingeschakeld\n",
|
||||
"label.duration.in.sec": "duur (in sec)",
|
||||
"label.edit": "Wijzig",
|
||||
"label.edit.acl.list": "Verander een ACL lijst",
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@
|
|||
action.showBadge && (
|
||||
(!dataView && ((action.listView && ('show' in action ? action.show(resource, $store.getters) : true)) || (action.groupAction && selectedRowKeys.length > 0 && ('groupShow' in action ? action.show(resource, $store.getters) : true)))) ||
|
||||
(dataView && action.dataView && ('show' in action ? action.show(resource, $store.getters) : true))
|
||||
)" >
|
||||
)"
|
||||
:disabled="'disabled' in action ? action.disabled(resource, $store.getters) : false" >
|
||||
<a-button
|
||||
:type="action.icon === 'delete' ? 'danger' : (action.icon === 'plus' ? 'primary' : 'default')"
|
||||
:shape="!dataView && action.icon === 'plus' ? 'round' : 'circle'"
|
||||
|
|
@ -59,6 +60,7 @@
|
|||
(!dataView && ((action.listView && ('show' in action ? action.show(resource, $store.getters) : true)) || (action.groupAction && selectedRowKeys.length > 0 && ('groupShow' in action ? action.show(resource, $store.getters) : true)))) ||
|
||||
(dataView && action.dataView && ('show' in action ? action.show(resource, $store.getters) : true))
|
||||
)"
|
||||
:disabled="'disabled' in action ? action.disabled(resource, $store.getters) : false"
|
||||
:type="action.icon === 'delete' ? 'danger' : (action.icon === 'plus' ? 'primary' : 'default')"
|
||||
:shape="!dataView && ['plus', 'user-add'].includes(action.icon) ? 'round' : 'circle'"
|
||||
style="margin-left: 5px"
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@ export default {
|
|||
docHelp: 'adminguide/virtual_machines.html#how-to-dynamically-scale-cpu-and-ram',
|
||||
dataView: true,
|
||||
show: (record) => { return ['Stopped'].includes(record.state) || (['Running'].includes(record.state) && record.hypervisor !== 'KVM' && record.hypervisor !== 'LXC') },
|
||||
disabled: (record) => { return !record.isdynamicallyscalable },
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/ScaleVM.vue')
|
||||
},
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export default {
|
|||
docHelp: 'adminguide/systemvm.html',
|
||||
permission: ['listSystemVms'],
|
||||
columns: ['name', 'state', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'hostname', 'zonename'],
|
||||
details: ['name', 'id', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'gateway', 'hostname', 'zonename', 'created', 'activeviewersessions'],
|
||||
details: ['name', 'id', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'gateway', 'hostname', 'zonename', 'created', 'activeviewersessions', 'isdynamicallyscalable'],
|
||||
actions: [
|
||||
{
|
||||
api: 'startSystemVm',
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default {
|
|||
params: { isrecursive: 'true' },
|
||||
columns: ['name', 'displaytext', 'cpunumber', 'cpuspeed', 'memory', 'domain', 'zone', 'order'],
|
||||
details: () => {
|
||||
var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'domain', 'zone', 'created']
|
||||
var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled']
|
||||
if (store.getters.apis.createServiceOffering &&
|
||||
store.getters.apis.createServiceOffering.params.filter(x => x.name === 'storagepolicy').length > 0) {
|
||||
fields.splice(6, 0, 'vspherestoragepolicy')
|
||||
|
|
@ -87,7 +87,7 @@ export default {
|
|||
permission: ['listServiceOfferings', 'listInfrastructure'],
|
||||
params: { issystem: 'true', isrecursive: 'true' },
|
||||
columns: ['name', 'systemvmtype', 'cpunumber', 'cpuspeed', 'memory', 'storagetype', 'order'],
|
||||
details: ['name', 'id', 'displaytext', 'systemvmtype', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'domain', 'zone', 'created'],
|
||||
details: ['name', 'id', 'displaytext', 'systemvmtype', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled'],
|
||||
actions: [{
|
||||
api: 'createServiceOffering',
|
||||
icon: 'plus',
|
||||
|
|
|
|||
|
|
@ -509,6 +509,21 @@
|
|||
v-decorator="['bootintosetup']">
|
||||
</a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
{{ $t('label.dynamicscalingenabled') }}
|
||||
<a-tooltip :title="$t('label.dynamicscalingenabled.tooltip')">
|
||||
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-form-item>
|
||||
<a-switch
|
||||
v-decorator="['dynamicscalingenabled']"
|
||||
:checked="isDynamicallyScalable() && dynamicscalingenabled"
|
||||
:disabled="!isDynamicallyScalable()"
|
||||
@change="val => { dynamicscalingenabled = val }"/>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('label.userdata')">
|
||||
<a-textarea
|
||||
v-decorator="['userdata']">
|
||||
|
|
@ -675,6 +690,7 @@ export default {
|
|||
clusterId: null,
|
||||
zoneSelected: false,
|
||||
startvm: true,
|
||||
dynamicscalingenabled: true,
|
||||
vm: {
|
||||
name: null,
|
||||
zoneid: null,
|
||||
|
|
@ -710,7 +726,8 @@ export default {
|
|||
groups: [],
|
||||
keyboards: [],
|
||||
bootTypes: [],
|
||||
bootModes: []
|
||||
bootModes: [],
|
||||
dynamicScalingVmConfig: false
|
||||
},
|
||||
rowCount: {},
|
||||
loading: {
|
||||
|
|
@ -892,6 +909,13 @@ export default {
|
|||
type: 'Routing'
|
||||
},
|
||||
field: 'hostid'
|
||||
},
|
||||
dynamicScalingVmConfig: {
|
||||
list: 'listConfigurations',
|
||||
options: {
|
||||
zoneid: _.get(this.zone, 'id'),
|
||||
name: 'enable.dynamic.scale.vm'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -970,6 +994,9 @@ export default {
|
|||
},
|
||||
showSecurityGroupSection () {
|
||||
return (this.networks.length > 0 && this.zone.securitygroupsenabled) || (this.zone && this.zone.networktype === 'Basic')
|
||||
},
|
||||
dynamicScalingVmConfigValue () {
|
||||
return this.options.dynamicScalingVmConfig?.[0]?.value === 'true'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -1086,6 +1113,16 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
serviceOffering (oldValue, newValue) {
|
||||
if (oldValue && newValue && oldValue.id !== newValue.id) {
|
||||
this.dynamicscalingenabled = this.isDynamicallyScalable()
|
||||
}
|
||||
},
|
||||
template (oldValue, newValue) {
|
||||
if (oldValue && newValue && oldValue.id !== newValue.id) {
|
||||
this.dynamicscalingenabled = this.isDynamicallyScalable()
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.form = this.$form.createForm(this, {
|
||||
onValuesChange: (props, fields) => {
|
||||
|
|
@ -1179,6 +1216,9 @@ export default {
|
|||
this.instanceConfig = this.form.getFieldsValue() // ToDo: maybe initialize with some other defaults
|
||||
})
|
||||
},
|
||||
isDynamicallyScalable () {
|
||||
return this.serviceOffering && this.serviceOffering.dynamicscalingenabled && this.template && this.template.isdynamicallyscalable && this.dynamicScalingVmConfigValue
|
||||
},
|
||||
async fetchDataByZone (zoneId) {
|
||||
this.fillValue('zoneid')
|
||||
this.options.zones = await this.fetchZones()
|
||||
|
|
@ -1416,6 +1456,7 @@ export default {
|
|||
deployVmData.keyboard = values.keyboard
|
||||
deployVmData.boottype = values.boottype
|
||||
deployVmData.bootmode = values.bootmode
|
||||
deployVmData.dynamicscalingenabled = values.dynamicscalingenabled
|
||||
if (values.userdata && values.userdata.length > 0) {
|
||||
deployVmData.userdata = encodeURIComponent(btoa(this.sanitizeReverse(values.userdata)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@
|
|||
</span>
|
||||
<a-switch
|
||||
:default-checked="resource.isdynamicallyscalable"
|
||||
v-decorator="['isdynamicallyscalable']" />
|
||||
v-decorator="['isdynamicallyscalable']"
|
||||
:disabled="!canDynamicScalingEnabled()" />
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
|
|
@ -125,6 +126,9 @@ export default {
|
|||
},
|
||||
data () {
|
||||
return {
|
||||
serviceOffering: {},
|
||||
template: {},
|
||||
dynamicScalingVmConfig: false,
|
||||
loading: false,
|
||||
osTypes: {
|
||||
loading: false,
|
||||
|
|
@ -151,6 +155,44 @@ export default {
|
|||
fetchData () {
|
||||
this.fetchOsTypes()
|
||||
this.fetchInstaceGroups()
|
||||
this.fetchServiceOfferingData()
|
||||
this.fetchTemplateData()
|
||||
this.fetchDynamicScalingVmConfig()
|
||||
},
|
||||
fetchServiceOfferingData () {
|
||||
const params = {}
|
||||
params.id = this.resource.serviceofferingid
|
||||
params.isrecursive = true
|
||||
var apiName = 'listServiceOfferings'
|
||||
api(apiName, params).then(json => {
|
||||
const offerings = json.listserviceofferingsresponse.serviceoffering
|
||||
this.serviceOffering = offerings[0]
|
||||
})
|
||||
},
|
||||
fetchTemplateData () {
|
||||
const params = {}
|
||||
console.log('templateid ' + this.resource.templateid)
|
||||
params.id = this.resource.templateid
|
||||
params.isrecursive = true
|
||||
params.templatefilter = 'all'
|
||||
var apiName = 'listTemplates'
|
||||
api(apiName, params).then(json => {
|
||||
const templateResponses = json.listtemplatesresponse.template
|
||||
this.template = templateResponses[0]
|
||||
})
|
||||
},
|
||||
fetchDynamicScalingVmConfig () {
|
||||
const params = {}
|
||||
params.name = 'enable.dynamic.scale.vm'
|
||||
params.zoneid = this.resource.zoneid
|
||||
var apiName = 'listConfigurations'
|
||||
api(apiName, params).then(json => {
|
||||
const configResponse = json.listconfigurationsresponse.configuration
|
||||
this.dynamicScalingVmConfig = configResponse[0]?.value === 'true'
|
||||
})
|
||||
},
|
||||
canDynamicScalingEnabled () {
|
||||
return this.template.isdynamicallyscalable && this.serviceOffering.dynamicscalingenabled && this.dynamicScalingVmConfig
|
||||
},
|
||||
fetchOsTypes () {
|
||||
this.osTypes.loading = true
|
||||
|
|
|
|||
|
|
@ -532,6 +532,15 @@
|
|||
</span>
|
||||
<a-switch v-decorator="['offerha', {initialValue: false}]" />
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
{{ $t('label.dynamicscalingenabled') }}
|
||||
<a-tooltip :title="apiParams.dynamicscalingenabled.description">
|
||||
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-switch v-decorator="['dynamicscalingenabled', {initialValue: dynamicscalingenabled}]" :checked="dynamicscalingenabled" @change="val => { dynamicscalingenabled = val }"/>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="this.isAdmin()">
|
||||
<span slot="label">
|
||||
{{ $t('label.hosttags') }}
|
||||
|
|
@ -797,7 +806,8 @@ export default {
|
|||
],
|
||||
vGpuVisible: false,
|
||||
vGpuTypes: [],
|
||||
loading: false
|
||||
loading: false,
|
||||
dynamicscalingenabled: true
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
|
@ -959,7 +969,8 @@ export default {
|
|||
cachemode: values.cachemode,
|
||||
customized: values.offeringtype !== 'fixed',
|
||||
offerha: values.offerha === true,
|
||||
limitcpuuse: values.limitcpuuse === true
|
||||
limitcpuuse: values.limitcpuuse === true,
|
||||
dynamicscalingenabled: values.dynamicscalingenabled
|
||||
}
|
||||
|
||||
// custom fields (begin)
|
||||
|
|
|
|||
Loading…
Reference in New Issue