// Check that the specified service offering ID is valid
_itMgr.checkIfCanUpgrade(vmInstance, newServiceOfferingId);
//Check if its a scale "up"
ServiceOffering newServiceOffering = _configMgr.getServiceOffering(newServiceOfferingId);
ServiceOffering currentServiceOffering = _offeringDao.findByIdIncludingRemoved(vmInstance.getServiceOfferingId());
int newCpu = newServiceOffering.getCpu();
int newMemory = newServiceOffering.getRamSize();
int newSpeed = newServiceOffering.getSpeed();
int currentCpu = currentServiceOffering.getCpu();
int currentMemory = currentServiceOffering.getRamSize();
int currentSpeed = currentServiceOffering.getSpeed();
// Don't allow to scale when (Any of the new values less than current values) OR (All current and new values are same)
if( (newSpeed < currentSpeed || newMemory < currentMemory || newCpu < currentCpu)
|| ( newSpeed == currentSpeed && newMemory == currentMemory && newCpu == currentCpu)){
throw new InvalidParameterValueException("Only scaling up the vm is supported, new service offering(speed="+ newSpeed + ",cpu=" + newCpu + ",memory=," + newMemory + ")" +
" should have at least one value(cpu/ram) greater than old value and no resource value less than older(speed="+ currentSpeed + ",cpu=" + currentCpu + ",memory=," + currentMemory + ")");
}
// Check resource limits
if (newCpu > currentCpu) {
_resourceLimitMgr.checkResourceLimit(caller, ResourceType.cpu,
newCpu - currentCpu);
}
if (newMemory > currentMemory) {
_resourceLimitMgr.checkResourceLimit(caller, ResourceType.memory,
newMemory - currentMemory);
}
// Dynamically upgrade the running vms
boolean success = false;
if(vmInstance.getState().equals(State.Running)){
int retry = _scaleRetry;
ExcludeList excludes = new ExcludeList();
boolean enableDynamicallyScaleVm = Boolean.parseBoolean(_configServer.getConfigValue(Config.EnableDynamicallyScaleVm.key(), Config.ConfigurationParameterScope.zone.toString(), vmInstance.getDataCenterId()));
if(!enableDynamicallyScaleVm){
throw new PermissionDeniedException("Dynamically scaling virtual machines is disabled for this zone, please contact your admin");
}
if (!vmInstance.isDynamicallyScalable()) {
throw new CloudRuntimeException("Unable to Scale the vm: " + vmInstance.getUuid() + " as vm does not have tools to support dynamic scaling");
}
while (retry-- != 0) { // It's != so that it can match -1.
try{
boolean existingHostHasCapacity = false;
// Increment CPU and Memory count accordingly.
if (newCpu > currentCpu) {
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long (newCpu - currentCpu));
}
if (newMemory > currentMemory) {
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (newMemory - currentMemory));
}
// #1 Check existing host has capacity
if( !excludes.shouldAvoid(ApiDBUtils.findHostById(vmInstance.getHostId())) ){
existingHostHasCapacity = _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), newServiceOffering.getSpeed() - currentServiceOffering.getSpeed(),
(newServiceOffering.getRamSize() - currentServiceOffering.getRamSize()) * 1024L * 1024L, false, ApiDBUtils.getCpuOverprovisioningFactor(), 1f, false); // TO DO fill it with mem.
excludes.addHost(vmInstance.getHostId());
}
// #2 migrate the vm if host doesn't have capacity or is in avoid set
if (!existingHostHasCapacity){
vmInstance = _itMgr.findHostAndMigrate(vmInstance.getType(), vmInstance, newServiceOfferingId, excludes);
}
// #3 scale the vm now
_itMgr.upgradeVmDb(vmId, newServiceOfferingId);
vmInstance = _vmInstanceDao.findById(vmId);
vmInstance = _itMgr.reConfigureVm(vmInstance, currentServiceOffering, existingHostHasCapacity);
success = true;
return success;
}catch(InsufficientCapacityException e ){
s_logger.warn("Received exception while scaling ",e);
} catch (ResourceUnavailableException e) {
s_logger.warn("Received exception while scaling ",e);
} catch (ConcurrentOperationException e) {
s_logger.warn("Received exception while scaling ",e);
} catch (VirtualMachineMigrationException e) {
s_logger.warn("Received exception while scaling ",e);
} catch (ManagementServerException e) {
s_logger.warn("Received exception while scaling ",e);
} catch (Exception e) {
s_logger.warn("Received exception while scaling ",e);
}
finally{
if(!success){
_itMgr.upgradeVmDb(vmId, currentServiceOffering.getId()); // rollback
// Decrement CPU and Memory count accordingly.
if (newCpu > currentCpu) {
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long (newCpu - currentCpu));
}
if (newMemory > currentMemory) {