diff --git a/api/src/com/cloud/template/VirtualMachineTemplate.java b/api/src/com/cloud/template/VirtualMachineTemplate.java index cedc793c197..114785a28be 100755 --- a/api/src/com/cloud/template/VirtualMachineTemplate.java +++ b/api/src/com/cloud/template/VirtualMachineTemplate.java @@ -92,4 +92,6 @@ public interface VirtualMachineTemplate extends ControlledEntity, Identity, Inte String getTemplateTag(); Map getDetails(); + + Boolean isDynamicallyScalable(); } diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index ce9add62469..c172fbff422 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -158,6 +158,8 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I } } + public static final String IsDynamicScalingEnabled = "enable.dynamic.scaling"; + public enum Event { CreateRequested, StartRequested, diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 12e50978475..50832a3892e 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -509,6 +509,7 @@ public class ApiConstants { public static final String DEPLOYMENT_PLANNER = "deploymentplanner"; public static final String ACL_ID = "aclid"; public static final String NUMBER = "number"; + public static final String IS_DYNAMICALLY_SCALABLE = "isdynamicallyscalable"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java b/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java index 6fd97731189..b01c8d00a62 100644 --- a/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java @@ -54,6 +54,9 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends BaseCmd { @Parameter(name=ApiConstants.SORT_KEY, type=CommandType.INTEGER, description="sort key of the template, integer") private Integer sortKey; + @Parameter(name = ApiConstants.IS_DYNAMICALLY_SCALABLE, type = CommandType.BOOLEAN, description = "true if template/ISO contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory") + private Boolean isDynamicallyScalable; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -89,4 +92,8 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends BaseCmd { public Integer getSortKey() { return sortKey; } + + public Boolean isDynamicallyScalable() { + return isDynamicallyScalable; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java index 284d5530846..1e7e3dae329 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java @@ -93,6 +93,9 @@ public class RegisterIsoCmd extends BaseCmd { description="Image store uuid") private String imageStoreUuid; + @Parameter(name = ApiConstants.IS_DYNAMICALLY_SCALABLE, type = CommandType.BOOLEAN, description = "true if iso contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory") + protected Boolean isDynamicallyScalable; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -149,6 +152,10 @@ public class RegisterIsoCmd extends BaseCmd { return this.imageStoreUuid; } + public Boolean isDynamicallyScalable() { + return isDynamicallyScalable == null ? false : isDynamicallyScalable; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java index c9da0c28cd6..837faf69d29 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java @@ -118,6 +118,9 @@ public class RegisterTemplateCmd extends BaseCmd { @Parameter(name=ApiConstants.DETAILS, type=CommandType.MAP, description="Template details in key/value pairs.") protected Map details; + @Parameter(name = ApiConstants.IS_DYNAMICALLY_SCALABLE, type = CommandType.BOOLEAN, description = "true if template contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory") + protected Boolean isDynamicallyScalable; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -208,6 +211,10 @@ public class RegisterTemplateCmd extends BaseCmd { return params; } + public Boolean isDynamicallyScalable() { + return isDynamicallyScalable == null ? false : isDynamicallyScalable; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java index 28602830e02..26e5609f35c 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java @@ -67,6 +67,9 @@ public class UpdateVMCmd extends BaseCmd{ @Parameter(name=ApiConstants.DISPLAY_VM, type=CommandType.BOOLEAN, description="an optional field, whether to the display the vm to the end user or not.") private Boolean displayVm; + @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") + protected Boolean isDynamicallyScalable; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -95,6 +98,10 @@ public class UpdateVMCmd extends BaseCmd{ return displayVm; } + public Boolean isDynamicallyScalable() { + return isDynamicallyScalable; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/response/TemplateResponse.java b/api/src/org/apache/cloudstack/api/response/TemplateResponse.java index ed933ff18c3..2089c4b3660 100644 --- a/api/src/org/apache/cloudstack/api/response/TemplateResponse.java +++ b/api/src/org/apache/cloudstack/api/response/TemplateResponse.java @@ -139,6 +139,9 @@ public class TemplateResponse extends BaseResponse implements ControlledEntityRe @SerializedName(ApiConstants.SSHKEY_ENABLED) @Param(description="true if template is sshkey enabled, false otherwise") private Boolean sshKeyEnabled; + @SerializedName(ApiConstants.IS_DYNAMICALLY_SCALABLE) @Param(description="true if template contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory") + private Boolean isDynamicallyScalable; + @Override public String getObjectId() { return this.getId(); @@ -296,4 +299,8 @@ public class TemplateResponse extends BaseResponse implements ControlledEntityRe this.sshKeyEnabled = sshKeyEnabled; } + public void setDynamicallyScalable(boolean isDynamicallyScalable) { + this.isDynamicallyScalable = isDynamicallyScalable; + } + } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index 5b71ba228cc..0df94134e72 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -189,6 +189,9 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @SerializedName(ApiConstants.DISPLAY_VM) @Param(description="an optional field whether to the display the vm to the end user or not.") private Boolean displayVm; + @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; + public UserVmResponse(){ securityGroupList = new LinkedHashSet(); nics = new LinkedHashSet(); @@ -432,4 +435,8 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp this.affinityGroupList.add(affinityGroup); } + public void setDynamicallyScalable(boolean isDynamicallyScalable) { + this.isDynamicallyScalable = isDynamicallyScalable; + } + } diff --git a/core/src/com/cloud/agent/api/ScaleVmCommand.java b/core/src/com/cloud/agent/api/ScaleVmCommand.java index b3614856361..83cdcac2615 100644 --- a/core/src/com/cloud/agent/api/ScaleVmCommand.java +++ b/core/src/com/cloud/agent/api/ScaleVmCommand.java @@ -41,7 +41,7 @@ public class ScaleVmCommand extends Command { } public ScaleVmCommand(String vmName, int cpus, - Integer minSpeed, Integer maxSpeed, long minRam, long maxRam, boolean limitCpuUse) { + Integer minSpeed, Integer maxSpeed, long minRam, long maxRam, boolean limitCpuUse, boolean isDynamicallyScalable) { super(); this.vmName = vmName; this.cpus = cpus; @@ -50,6 +50,7 @@ public class ScaleVmCommand extends Command { this.minRam = minRam; this.maxRam = maxRam; this.vm = new VirtualMachineTO(1L, vmName, null, cpus, minSpeed, maxSpeed, minRam, maxRam, null, null, false, limitCpuUse, null); + vm.setEnableDynamicallyScaleVm(isDynamicallyScalable); /*vm.setName(vmName); vm.setCpus(cpus); vm.setRam(minRam, maxRam);*/ diff --git a/engine/schema/src/com/cloud/storage/VMTemplateVO.java b/engine/schema/src/com/cloud/storage/VMTemplateVO.java index e643d75bf1e..3bf83c0e727 100755 --- a/engine/schema/src/com/cloud/storage/VMTemplateVO.java +++ b/engine/schema/src/com/cloud/storage/VMTemplateVO.java @@ -148,6 +148,9 @@ public class VMTemplateVO implements VirtualMachineTemplate, StateObject iter = vms.iterator(); while ( iter.hasNext() ) { diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java index 8e378093f3f..f7da000d100 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java @@ -137,6 +137,7 @@ public class XenServer56FP1Resource extends XenServer56Resource { vmr.actionsAfterCrash = Types.OnCrashBehaviour.DESTROY; vmr.actionsAfterShutdown = Types.OnNormalExit.DESTROY; + Map details = vmSpec.getDetails(); if (isDmcEnabled(conn, host) && vmSpec.isEnableDynamicallyScaleVm()) { //scaling is allowed vmr.memoryStaticMin = mem_128m; //128MB diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index c0034ab7800..17cad7ed550 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -1306,6 +1306,7 @@ public class ApiResponseHelper implements ResponseGenerator { response.setTags(tagResponses); response.setObjectName("iso"); + response.setDynamicallyScalable(result.isDynamicallyScalable()); return response; } @@ -1520,6 +1521,7 @@ public class ApiResponseHelper implements ResponseGenerator { templateResponse.setTags(tagResponses); templateResponse.setObjectName("template"); + templateResponse.setDynamicallyScalable(template.isDynamicallyScalable()); responses.add(templateResponse); return responses; } @@ -1545,6 +1547,7 @@ public class ApiResponseHelper implements ResponseGenerator { isoResponse.setChecksum(iso.getChecksum()); isoResponse.setPasswordEnabled(false); isoResponse.setDetails(iso.getDetails()); + isoResponse.setDynamicallyScalable(iso.isDynamicallyScalable()); // add account ID and name Account owner = ApiDBUtils.findAccountById(iso.getAccountId()); @@ -1721,6 +1724,7 @@ public class ApiResponseHelper implements ResponseGenerator { isoResponse.setPublic(iso.isPublicTemplate()); isoResponse.setChecksum(iso.getChecksum()); isoResponse.setDetails(iso.getDetails()); + isoResponse.setDynamicallyScalable(iso.isDynamicallyScalable()); // TODO: implement GuestOS os = ApiDBUtils.findGuestOSById(iso.getGuestOSId()); diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index f9877ab98b4..64c4b207b3a 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -249,6 +249,11 @@ public class UserVmJoinDaoImpl extends GenericDaoBase implem } userVmResponse.setObjectName(objectName); + if (userVm.isDynamicallyScalable() == null) { + userVmResponse.setDynamicallyScalable(false); + } else { + userVmResponse.setDynamicallyScalable(userVm.isDynamicallyScalable()); + } return userVmResponse; } diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index c97d71a81ed..c7841040be4 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -391,6 +391,9 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name="uuid") private String uuid; + @Column(name="dynamically_scalable") + private boolean isDynamicallyScalable; + public UserVmJoinVO() { } @@ -1717,5 +1720,13 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { return affinityGroupDescription; } + public Boolean isDynamicallyScalable() { + return isDynamicallyScalable; + } + + public void setDynamicallyScalable(boolean isDynamicallyScalable) { + this.isDynamicallyScalable = isDynamicallyScalable; + } + } diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index 1ad9a1fb7c4..be36b8d22d2 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -29,6 +29,8 @@ import com.cloud.configuration.Config; import com.cloud.offering.ServiceOffering; import com.cloud.server.ConfigurationServer; import com.cloud.storage.dao.VMTemplateDetailsDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.VMTemplateVO; import com.cloud.utils.component.AdapterBase; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; @@ -37,6 +39,7 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicSecondaryIpDao; +import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; public abstract class HypervisorGuruBase extends AdapterBase implements HypervisorGuru { @@ -47,7 +50,6 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis @Inject NicSecondaryIpDao _nicSecIpDao; @Inject ConfigurationServer _configServer; - protected HypervisorGuruBase() { super(); } @@ -120,15 +122,18 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis if(detailsInVm != null) { details.putAll(detailsInVm); } + if (details.get(VirtualMachine.IsDynamicScalingEnabled) == null || details.get(VirtualMachine.IsDynamicScalingEnabled).isEmpty()) { + to. setEnableDynamicallyScaleVm(false); + } else { + // check if XStools/VMWare tools are present in the VM and dynamic scaling feature is enabled (per zone/global) + to.setEnableDynamicallyScaleVm(details.get(VirtualMachine.IsDynamicScalingEnabled).equals("true") && Boolean.parseBoolean(_configServer.getConfigValue(Config.EnableDynamicallyScaleVm.key(), Config.ConfigurationParameterScope.zone.toString(), vm.getDataCenterId()))); + } to.setDetails(details); - // Workaround to make sure the TO has the UUID we need for Niciri integration VMInstanceVO vmInstance = _virtualMachineDao.findById(to.getId()); to.setUuid(vmInstance.getUuid()); // - to.setEnableDynamicallyScaleVm(Boolean.parseBoolean(_configServer.getConfigValue(Config.EnableDynamicallyScaleVm.key(), Config.ConfigurationParameterScope.zone.toString(), vm.getDataCenterId()))); - return to; } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index cfc8333e9c8..e415f6f95af 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -1877,6 +1877,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe Boolean passwordEnabled = cmd.isPasswordEnabled(); Boolean bootable = cmd.isBootable(); Integer sortKey = cmd.getSortKey(); + Boolean isDynamicallyScalable = cmd.isDynamicallyScalable(); Account account = UserContext.current().getCaller(); // verify that template exists @@ -1898,7 +1899,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe _accountMgr.checkAccess(account, AccessType.ModifyEntry, true, template); boolean updateNeeded = !(name == null && displayText == null && format == null && guestOSId == null && passwordEnabled == null - && bootable == null && sortKey == null); + && bootable == null && sortKey == null && isDynamicallyScalable == null); if (!updateNeeded) { return template; } @@ -1947,6 +1948,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe template.setBootable(bootable); } + if (isDynamicallyScalable != null) { + template.setDynamicallyScalable(isDynamicallyScalable); + } + _templateDao.update(id, template); return _templateDao.findById(id); diff --git a/server/src/com/cloud/storage/TemplateProfile.java b/server/src/com/cloud/storage/TemplateProfile.java index 0b55f1fbea2..ca23d00058c 100755 --- a/server/src/com/cloud/storage/TemplateProfile.java +++ b/server/src/com/cloud/storage/TemplateProfile.java @@ -47,6 +47,7 @@ public class TemplateProfile { String templateTag; Long imageStoreId; Map details; + Boolean isDynamicallyScalable; public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, Long zoneId, @@ -84,11 +85,12 @@ public class TemplateProfile { public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, Long zoneId, HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details, Boolean sshKeyEnabled, - Long imageStoreId) { + Long imageStoreId, Boolean isDynamicallyScalable) { this(templateId, userId, name, displayText, bits, passwordEnabled, requiresHvm, url, isPublic, featured, isExtractable, format, guestOsId, zoneId, hypervisorType, accountName, domainId, accountId, chksum, bootable, details, sshKeyEnabled); this.templateTag = templateTag; this.imageStoreId = imageStoreId; + this.isDynamicallyScalable = isDynamicallyScalable; } public Long getTemplateId() { @@ -258,4 +260,12 @@ public class TemplateProfile { public Long getImageStoreId() { return this.imageStoreId; } + + public Boolean IsDynamicallyScalable() { + return this.isDynamicallyScalable; + } + + public void setScalabe(Boolean isDynamicallyScalabe) { + this.isDynamicallyScalable = isDynamicallyScalabe; + } } diff --git a/server/src/com/cloud/template/TemplateAdapter.java b/server/src/com/cloud/template/TemplateAdapter.java index 9a2d877926d..bb7cd239b95 100755 --- a/server/src/com/cloud/template/TemplateAdapter.java +++ b/server/src/com/cloud/template/TemplateAdapter.java @@ -69,5 +69,5 @@ public interface TemplateAdapter extends Adapter { public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, - String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid) throws ResourceAllocationException; + String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable) throws ResourceAllocationException; } diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index 0940d3e2af1..c57697b257a 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -104,14 +104,14 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, String accountName, Long domainId, String chksum, Boolean bootable, Map details) throws ResourceAllocationException { return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId, hypervisorType, - chksum, bootable, null, null, details, false, null); + chksum, bootable, null, null, details, false, null, false); } public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, - String imageStoreUuid) throws ResourceAllocationException { + String imageStoreUuid, Boolean isDynamicallyScalable) throws ResourceAllocationException { //Long accountId = null; // parameters verification @@ -226,7 +226,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat Long id = _tmpltDao.getNextInSequence(Long.class, "id"); UserContext.current().setEventDetails("Id: " +id+ " name: " + name); return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, - featured, isExtractable, imgfmt, guestOSId, zoneId, hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details, sshkeyEnabled, imageStoreId); + featured, isExtractable, imgfmt, guestOSId, zoneId, hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details, sshkeyEnabled, imageStoreId, isDynamicallyScalable); } @Override @@ -241,7 +241,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat return prepare(false, UserContext.current().getCallerUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(), cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), cmd.getZoneId(), HypervisorType.getType(cmd.getHypervisor()), - cmd.getChecksum(), true, cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), cmd.getImageStoreUuid()); + cmd.getChecksum(), true, cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), cmd.getImageStoreUuid(), cmd.isDynamicallyScalable()); } public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { @@ -252,7 +252,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat return prepare(true, UserContext.current().getCallerUserId(), cmd.getIsoName(), cmd.getDisplayText(), 64, false, true, cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), ImageFormat.ISO.toString(), cmd.getOsTypeId(), - cmd.getZoneId(), HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null, owner, null, false, cmd.getImageStoreUuid()); + cmd.getZoneId(), HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null, owner, null, false, cmd.getImageStoreUuid(), cmd.isDynamicallyScalable()); } protected VMTemplateVO persistTemplate(TemplateProfile profile) { @@ -261,7 +261,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat profile.getFeatured(), profile.getIsExtractable(), TemplateType.USER, profile.getUrl(), profile.getRequiresHVM(), profile.getBits(), profile.getAccountId(), profile.getCheckSum(), profile.getDisplayText(), profile.getPasswordEnabled(), profile.getGuestOsId(), profile.getBootable(), profile.getHypervisorType(), profile.getTemplateTag(), - profile.getDetails(), profile.getSshKeyEnabled()); + profile.getDetails(), profile.getSshKeyEnabled(), profile.IsDynamicallyScalable()); template.setImageDataStoreId(profile.getImageStoreId()); if (zoneId == null || zoneId.longValue() == -1) { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index e8ea0242e11..8147b36b31c 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1709,6 +1709,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use Long id = cmd.getId(); Long osTypeId = cmd.getOsTypeId(); String userData = cmd.getUserData(); + Boolean isDynamicallyScalable = cmd.isDynamicallyScalable(); Account caller = UserContext.current().getCaller(); // Input validation @@ -1796,6 +1797,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } + if (isDynamicallyScalable != null) { + UserVmDetailVO vmDetailVO = _vmDetailsDao.findDetail(vm.getId(), VirtualMachine.IsDynamicScalingEnabled); + if (vmDetailVO == null) { + vmDetailVO = new UserVmDetailVO(vm.getId(), VirtualMachine.IsDynamicScalingEnabled, isDynamicallyScalable.toString()); + _vmDetailsDao.persist(vmDetailVO); + } else { + vmDetailVO.setValue(isDynamicallyScalable.toString()); + _vmDetailsDao.update(vmDetailVO.getId(), vmDetailVO); + } + } + _vmDao.updateVM(id, displayName, ha, osTypeId, userData, isDisplayVmEnabled); if (updateUserdata) { @@ -2684,6 +2696,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use owner.getDomainId(), owner.getId(), offering.getId(), userData, hostName, diskOfferingId); vm.setUuid(uuidName); + vm.setDetail(VirtualMachine.IsDynamicScalingEnabled, template.isDynamicallyScalable().toString()); if (sshPublicKey != null) { vm.setDetail("SSH.PublicKey", sshPublicKey); diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 58140750d74..ef35673295e 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -168,6 +168,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; +import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.ItWorkVO.Step; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; @@ -3230,14 +3231,23 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Override public VMInstanceVO reConfigureVm(VMInstanceVO vm , ServiceOffering oldServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException, ConcurrentOperationException { + UserVmDetailVO vmDetailVO = _uservmDetailsDao.findDetail(vm.getId(), VirtualMachine.IsDynamicScalingEnabled); + Boolean isDynamicallyScalable; + if (vmDetailVO == null) { + isDynamicallyScalable = false; + } else { + isDynamicallyScalable = (vmDetailVO.getValue()).equals("true"); + } + long newServiceofferingId = vm.getServiceOfferingId(); ServiceOffering newServiceOffering = _configMgr.getServiceOffering(newServiceofferingId); - HostVO hostVo = _hostDao.findById(vm.hostId); + HostVO hostVo = _hostDao.findById(vm.getHostId()); + Float memoryOvercommitRatio = Float.parseFloat(_configServer.getConfigValue(Config.MemOverprovisioningFactor.key(), Config.ConfigurationParameterScope.cluster.toString(), hostVo.getClusterId())); Float cpuOvercommitRatio = Float.parseFloat(_configServer.getConfigValue(Config.CPUOverprovisioningFactor.key(), Config.ConfigurationParameterScope.cluster.toString(), hostVo.getClusterId())); long minMemory = (long) (newServiceOffering.getRamSize()/memoryOvercommitRatio); ScaleVmCommand reconfigureCmd = new ScaleVmCommand(vm.getInstanceName(), newServiceOffering.getCpu(), - (int) (newServiceOffering.getSpeed()/cpuOvercommitRatio), newServiceOffering.getSpeed(), minMemory * 1024 * 1024, newServiceOffering.getRamSize() * 1024 * 1024, newServiceOffering.getLimitCpuUse()); + (int) (newServiceOffering.getSpeed()/cpuOvercommitRatio), newServiceOffering.getSpeed(), minMemory * 1024 * 1024, newServiceOffering.getRamSize() * 1024 * 1024, newServiceOffering.getLimitCpuUse(), isDynamicallyScalable); Long dstHostId = vm.getHostId(); ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Running, vm.getType(), vm.getId()); diff --git a/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java b/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java index 8715c9e8663..1847a05ad4c 100644 --- a/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java +++ b/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java @@ -75,7 +75,7 @@ import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.dao.UserVmDetailsDao; import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; import com.cloud.utils.Pair; @@ -160,12 +160,15 @@ public class VirtualMachineManagerImplTest { ConfigurationServer _configServer; @Mock HostVO hostVO; + @Mock + UserVmDetailVO _vmDetailVO; @Mock ClusterDao _clusterDao; @Mock HostPodDao _podDao; @Mock DataCenterDao _dcDao; @Mock DiskOfferingDao _diskOfferingDao; @Mock PrimaryDataStoreDao _storagePoolDao; + @Mock UserVmDetailsDao _vmDetailsDao; @Mock StoragePoolHostDao _poolHostDao; @Mock NetworkManager _networkMgr; @Mock HypervisorGuruManager _hvGuruMgr; @@ -206,6 +209,7 @@ public class VirtualMachineManagerImplTest { _vmMgr._vmSnapshotMgr = _vmSnapshotMgr; _vmMgr._vmDao = _vmInstanceDao; _vmMgr._configServer = _configServer; + _vmMgr._uservmDetailsDao = _vmDetailsDao; when(_vmMock.getId()).thenReturn(314l); when(_vmInstance.getId()).thenReturn(1L); @@ -244,14 +248,20 @@ public class VirtualMachineManagerImplTest { DeployDestination dest = new DeployDestination(null, null, null, _host); long l = 1L; + doReturn(3L).when(_vmInstance).getId(); + when(_vmDetailsDao.findDetail(3L, VirtualMachine.IsDynamicScalingEnabled)).thenReturn(_vmDetailVO); + doReturn("true").when(_vmDetailVO).getValue(); when(_vmInstanceDao.findById(anyLong())).thenReturn(_vmInstance); ServiceOfferingVO newServiceOffering = getSvcoffering(512); - when(_hostDao.findById(_vmInstance.hostId)).thenReturn(hostVO); + doReturn(1L).when(_vmInstance).getHostId(); + doReturn(hostVO).when(_hostDao).findById(1L); + doReturn(1L).when(_vmInstance).getDataCenterId(); doReturn(1L).when(hostVO).getClusterId(); + when(_configServer.getConfigValue(Config.EnableDynamicallyScaleVm.key(), Config.ConfigurationParameterScope.zone.toString(), 1L)).thenReturn("true"); when(_configServer.getConfigValue(Config.MemOverprovisioningFactor.key(), Config.ConfigurationParameterScope.cluster.toString(), 1L)).thenReturn("1.0"); when(_configServer.getConfigValue(Config.CPUOverprovisioningFactor.key(), Config.ConfigurationParameterScope.cluster.toString(), 1L)).thenReturn("1.0"); ScaleVmCommand reconfigureCmd = new ScaleVmCommand("myVmName", newServiceOffering.getCpu(), - newServiceOffering.getSpeed(), newServiceOffering.getSpeed(), newServiceOffering.getRamSize(), newServiceOffering.getRamSize(), newServiceOffering.getLimitCpuUse()); + newServiceOffering.getSpeed(), newServiceOffering.getSpeed(), newServiceOffering.getRamSize(), newServiceOffering.getRamSize(), newServiceOffering.getLimitCpuUse(), true); Answer answer = new ScaleVmAnswer(reconfigureCmd, true, "details"); when(_agentMgr.send(2l, reconfigureCmd)).thenReturn(null); _vmMgr.reConfigureVm(_vmInstance, getSvcoffering(256), false); diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index c782234ff2e..76c10138e3e 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -1518,7 +1518,8 @@ CREATE VIEW `cloud`.`user_vm_view` AS affinity_group.id affinity_group_id, affinity_group.uuid affinity_group_uuid, affinity_group.name affinity_group_name, - affinity_group.description affinity_group_description + affinity_group.description affinity_group_description, + vm_details.value dynamically_scalable from `cloud`.`user_vm` @@ -1579,10 +1580,13 @@ CREATE VIEW `cloud`.`user_vm_view` AS `cloud`.`async_job` ON async_job.instance_id = vm_instance.id and async_job.instance_type = 'VirtualMachine' and async_job.job_status = 0 - left join - `cloud`.`affinity_group_vm_map` ON vm_instance.id = affinity_group_vm_map.instance_id - left join - `cloud`.`affinity_group` ON affinity_group_vm_map.affinity_group_id = affinity_group.id; + left join + `cloud`.`affinity_group_vm_map` ON vm_instance.id = affinity_group_vm_map.instance_id + left join + `cloud`.`affinity_group` ON affinity_group_vm_map.affinity_group_id = affinity_group.id + left join + `cloud`.`user_vm_details` vm_details ON vm_details.vm_id = vm_instance.id + and vm_details.name = 'enable.dynamic.scaling'; DROP VIEW IF EXISTS `cloud`.`volume_view`; CREATE VIEW `cloud`.`volume_view` AS @@ -1884,3 +1888,4 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'manag INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'execute.in.sequence.hypervisor.commands', 'false', 'If set to true, StartCommand, StopCommand, CopyVolumeCommand, CreateCommand will be synchronized on the agent side. If set to false, these commands become asynchronous. Default value is false.'); INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'execute.in.sequence.network.element.commands', 'false', 'If set to true, DhcpEntryCommand, SavePasswordCommand, UserDataCommand, VmDataCommand will be synchronized on the agent side. If set to false, these commands become asynchronous. Default value is false.'); +ALTER TABLE `cloud`.`vm_template` ADD COLUMN `dynamically_scalable` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if template contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory';