| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| package com.cloud.network.as; |
| |
| import java.security.InvalidParameterException; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.ScheduledExecutorService; |
| import java.util.concurrent.TimeUnit; |
| |
| import javax.inject.Inject; |
| |
| import org.apache.log4j.Logger; |
| |
| import com.google.gson.Gson; |
| import com.google.gson.reflect.TypeToken; |
| |
| import org.apache.cloudstack.acl.ControlledEntity; |
| import org.apache.cloudstack.api.ApiConstants; |
| import org.apache.cloudstack.api.ApiErrorCode; |
| import org.apache.cloudstack.api.BaseCmd.HTTPMethod; |
| import org.apache.cloudstack.api.BaseListAccountResourcesCmd; |
| import org.apache.cloudstack.api.ServerApiException; |
| import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScalePolicyCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScaleVmGroupCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScaleVmProfileCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.CreateConditionCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.ListAutoScalePoliciesCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.ListAutoScaleVmGroupsCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.ListAutoScaleVmProfilesCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.ListConditionsCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.ListCountersCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScalePolicyCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmGroupCmd; |
| import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmProfileCmd; |
| import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; |
| import org.apache.cloudstack.config.ApiServiceConfiguration; |
| import org.apache.cloudstack.context.CallContext; |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; |
| |
| import com.cloud.api.ApiDBUtils; |
| import com.cloud.api.dispatch.DispatchChainFactory; |
| import com.cloud.api.dispatch.DispatchTask; |
| import com.cloud.configuration.ConfigurationManager; |
| import com.cloud.dc.DataCenter; |
| import com.cloud.dc.DataCenter.NetworkType; |
| import com.cloud.dc.dao.DataCenterDao; |
| import com.cloud.event.ActionEvent; |
| import com.cloud.event.EventTypes; |
| import com.cloud.exception.ConcurrentOperationException; |
| import com.cloud.exception.InsufficientCapacityException; |
| import com.cloud.exception.InsufficientServerCapacityException; |
| import com.cloud.exception.InvalidParameterValueException; |
| import com.cloud.exception.ResourceAllocationException; |
| import com.cloud.exception.ResourceInUseException; |
| import com.cloud.exception.ResourceUnavailableException; |
| import com.cloud.hypervisor.Hypervisor.HypervisorType; |
| import com.cloud.network.Network.Capability; |
| import com.cloud.network.Network.IpAddresses; |
| import com.cloud.network.as.AutoScaleCounter.AutoScaleCounterParam; |
| import com.cloud.network.as.dao.AutoScalePolicyConditionMapDao; |
| import com.cloud.network.as.dao.AutoScalePolicyDao; |
| import com.cloud.network.as.dao.AutoScaleVmGroupDao; |
| import com.cloud.network.as.dao.AutoScaleVmGroupPolicyMapDao; |
| import com.cloud.network.as.dao.AutoScaleVmGroupVmMapDao; |
| import com.cloud.network.as.dao.AutoScaleVmProfileDao; |
| import com.cloud.network.as.dao.ConditionDao; |
| import com.cloud.network.as.dao.CounterDao; |
| import com.cloud.network.dao.IPAddressDao; |
| import com.cloud.network.dao.LoadBalancerDao; |
| import com.cloud.network.dao.LoadBalancerVMMapDao; |
| import com.cloud.network.dao.LoadBalancerVMMapVO; |
| import com.cloud.network.dao.LoadBalancerVO; |
| import com.cloud.network.dao.NetworkDao; |
| import com.cloud.network.lb.LoadBalancingRulesManager; |
| import com.cloud.network.lb.LoadBalancingRulesService; |
| import com.cloud.offering.ServiceOffering; |
| import com.cloud.projects.Project.ListProjectResourcesCriteria; |
| import com.cloud.template.TemplateManager; |
| import com.cloud.template.VirtualMachineTemplate; |
| import com.cloud.user.Account; |
| import com.cloud.user.AccountManager; |
| import com.cloud.user.AccountService; |
| import com.cloud.user.User; |
| import com.cloud.user.dao.AccountDao; |
| import com.cloud.user.dao.UserDao; |
| import com.cloud.uservm.UserVm; |
| import com.cloud.utils.Pair; |
| import com.cloud.utils.Ternary; |
| import com.cloud.utils.component.ComponentContext; |
| import com.cloud.utils.component.ManagerBase; |
| import com.cloud.utils.db.DB; |
| import com.cloud.utils.db.EntityManager; |
| import com.cloud.utils.db.Filter; |
| import com.cloud.utils.db.GenericDao; |
| import com.cloud.utils.db.JoinBuilder; |
| import com.cloud.utils.db.SearchBuilder; |
| import com.cloud.utils.db.SearchCriteria; |
| import com.cloud.utils.db.TransactionCallback; |
| import com.cloud.utils.db.SearchCriteria.Op; |
| import com.cloud.utils.db.Transaction; |
| import com.cloud.utils.db.TransactionStatus; |
| import com.cloud.utils.net.NetUtils; |
| import com.cloud.vm.UserVmManager; |
| import com.cloud.vm.UserVmService; |
| |
| public class AutoScaleManagerImpl<Type> extends ManagerBase implements AutoScaleManager, AutoScaleService { |
| private static final Logger s_logger = Logger.getLogger(AutoScaleManagerImpl.class); |
| private ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1); |
| |
| @Inject |
| protected DispatchChainFactory dispatchChainFactory = null; |
| @Inject |
| EntityManager _entityMgr; |
| @Inject |
| AccountDao _accountDao; |
| @Inject |
| AccountManager _accountMgr; |
| @Inject |
| ConfigurationManager _configMgr; |
| @Inject |
| TemplateManager _templateMgr; |
| @Inject |
| LoadBalancingRulesManager _lbRulesMgr; |
| @Inject |
| NetworkDao _networkDao; |
| @Inject |
| CounterDao _counterDao; |
| @Inject |
| ConditionDao _conditionDao; |
| @Inject |
| LoadBalancerVMMapDao _lb2VmMapDao; |
| @Inject |
| LoadBalancerDao _lbDao; |
| @Inject |
| AutoScaleVmProfileDao _autoScaleVmProfileDao; |
| @Inject |
| AutoScalePolicyDao _autoScalePolicyDao; |
| @Inject |
| AutoScalePolicyConditionMapDao _autoScalePolicyConditionMapDao; |
| @Inject |
| AutoScaleVmGroupDao _autoScaleVmGroupDao; |
| @Inject |
| AutoScaleVmGroupPolicyMapDao _autoScaleVmGroupPolicyMapDao; |
| @Inject |
| AutoScaleVmGroupVmMapDao _autoScaleVmGroupVmMapDao; |
| @Inject |
| DataCenterDao _dcDao = null; |
| @Inject |
| UserDao _userDao; |
| @Inject |
| ConfigurationDao _configDao; |
| @Inject |
| IPAddressDao _ipAddressDao; |
| @Inject |
| AccountService _accountService; |
| @Inject |
| UserVmService _userVmService; |
| @Inject |
| UserVmManager _userVmManager; |
| @Inject |
| LoadBalancerVMMapDao _lbVmMapDao; |
| @Inject |
| LoadBalancingRulesService _loadBalancingRulesService; |
| |
| public List<AutoScaleCounter> getSupportedAutoScaleCounters(long networkid) { |
| String capability = _lbRulesMgr.getLBCapability(networkid, Capability.AutoScaleCounters.getName()); |
| if (capability == null) { |
| return null; |
| } |
| Gson gson = new Gson(); |
| java.lang.reflect.Type listType = new TypeToken<List<AutoScaleCounter>>() { |
| }.getType(); |
| List<AutoScaleCounter> result = gson.fromJson(capability, listType); |
| return result; |
| } |
| |
| public void validateAutoScaleCounters(long networkid, List<Counter> counters, List<Pair<String, String>> counterParamPassed) { |
| List<AutoScaleCounter> supportedCounters = getSupportedAutoScaleCounters(networkid); |
| if (supportedCounters == null) { |
| throw new InvalidParameterException("AutoScale is not supported in the network"); |
| } |
| for (Counter counter : counters) { |
| String counterName = counter.getSource().name().toString(); |
| boolean isCounterSupported = false; |
| for (AutoScaleCounter autoScaleCounter : supportedCounters) { |
| if (autoScaleCounter.getName().equals(counterName)) { |
| isCounterSupported = true; |
| List<AutoScaleCounterParam> counterParams = autoScaleCounter.getParamList(); |
| for (AutoScaleCounterParam autoScaleCounterParam : counterParams) { |
| boolean isRequiredParameter = autoScaleCounterParam.getRequired(); |
| if (isRequiredParameter) { |
| boolean isRequiredParamPresent = false; |
| for (Pair<String, String> pair : counterParamPassed) { |
| if (pair.first().equals(autoScaleCounterParam.getParamName())) |
| isRequiredParamPresent = true; |
| |
| } |
| if (!isRequiredParamPresent) { |
| throw new InvalidParameterException("Parameter " + autoScaleCounterParam.getParamName() + " has to be set in AutoScaleVmProfile's " + |
| ApiConstants.COUNTERPARAM_LIST); |
| } |
| } |
| } |
| break; |
| } |
| } |
| if (!isCounterSupported) { |
| throw new InvalidParameterException("AutoScale counter with source='" + counter.getSource().name() + "' is not supported " + "in the network"); |
| } |
| } |
| } |
| |
| private <VO extends ControlledEntity> VO getEntityInDatabase(Account caller, String paramName, Long id, GenericDao<VO, Long> dao) { |
| |
| VO vo = dao.findById(id); |
| |
| if (vo == null) { |
| throw new InvalidParameterValueException("Unable to find " + paramName); |
| } |
| |
| _accountMgr.checkAccess(caller, null, false, (ControlledEntity)vo); |
| |
| return vo; |
| } |
| |
| private boolean isAutoScaleScaleUpPolicy(AutoScalePolicy policyVO) { |
| return policyVO.getAction().equals("scaleup"); |
| } |
| |
| private List<AutoScalePolicyVO> getAutoScalePolicies(String paramName, List<Long> policyIds, List<Counter> counters, int interval, boolean scaleUpPolicies) { |
| SearchBuilder<AutoScalePolicyVO> policySearch = _autoScalePolicyDao.createSearchBuilder(); |
| policySearch.and("ids", policySearch.entity().getId(), Op.IN); |
| policySearch.done(); |
| SearchCriteria<AutoScalePolicyVO> sc = policySearch.create(); |
| |
| sc.setParameters("ids", policyIds.toArray(new Object[0])); |
| List<AutoScalePolicyVO> policies = _autoScalePolicyDao.search(sc, null); |
| |
| int prevQuietTime = 0; |
| |
| for (AutoScalePolicyVO policy : policies) { |
| int quietTime = policy.getQuietTime(); |
| if (prevQuietTime == 0) { |
| prevQuietTime = quietTime; |
| } |
| int duration = policy.getDuration(); |
| if (duration < interval) { |
| throw new InvalidParameterValueException("duration : " + duration + " specified in a policy cannot be less than vm group's interval : " + interval); |
| } |
| |
| if (quietTime != prevQuietTime) { |
| throw new InvalidParameterValueException("quietTime should be same for all the policies specified in " + paramName); |
| } |
| |
| if (scaleUpPolicies) { |
| if (!isAutoScaleScaleUpPolicy(policy)) { |
| throw new InvalidParameterValueException("Only scaleup policies can be specified in scaleuppolicyids"); |
| } |
| } else { |
| if (isAutoScaleScaleUpPolicy(policy)) { |
| throw new InvalidParameterValueException("Only scaledown policies can be specified in scaledownpolicyids"); |
| } |
| } |
| List<AutoScalePolicyConditionMapVO> policyConditionMapVOs = _autoScalePolicyConditionMapDao.listByAll(policy.getId(), null); |
| for (AutoScalePolicyConditionMapVO policyConditionMapVO : policyConditionMapVOs) { |
| long conditionid = policyConditionMapVO.getConditionId(); |
| Condition condition = _conditionDao.findById(conditionid); |
| Counter counter = _counterDao.findById(condition.getCounterid()); |
| counters.add(counter); |
| } |
| } |
| return policies; |
| } |
| |
| @DB |
| protected AutoScaleVmProfileVO checkValidityAndPersist(AutoScaleVmProfileVO vmProfile) { |
| long templateId = vmProfile.getTemplateId(); |
| long autoscaleUserId = vmProfile.getAutoScaleUserId(); |
| int destroyVmGraceperiod = vmProfile.getDestroyVmGraceperiod(); |
| |
| VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); |
| // Make sure a valid template ID was specified |
| if (template == null) { |
| throw new InvalidParameterValueException("Unable to use the given template."); |
| } |
| |
| if (destroyVmGraceperiod < 0) { |
| throw new InvalidParameterValueException("Destroy Vm Grace Period cannot be less than 0."); |
| } |
| |
| User user = _userDao.findById(autoscaleUserId); |
| if (user.getAccountId() != vmProfile.getAccountId()) { |
| throw new InvalidParameterValueException("AutoScale User id does not belong to the same account"); |
| } |
| |
| String apiKey = user.getApiKey(); |
| String secretKey = user.getSecretKey(); |
| String csUrl = ApiServiceConfiguration.ApiServletPath.value(); |
| |
| if (apiKey == null) { |
| throw new InvalidParameterValueException("apiKey for user: " + user.getUsername() + " is empty. Please generate it"); |
| } |
| |
| if (secretKey == null) { |
| throw new InvalidParameterValueException("secretKey for user: " + user.getUsername() + " is empty. Please generate it"); |
| } |
| |
| if (csUrl == null || csUrl.contains("localhost")) { |
| throw new InvalidParameterValueException("Global setting endpointe.url has to be set to the Management Server's API end point"); |
| } |
| |
| vmProfile = _autoScaleVmProfileDao.persist(vmProfile); |
| |
| return vmProfile; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMPROFILE_CREATE, eventDescription = "creating autoscale vm profile", create = true) |
| public AutoScaleVmProfile createAutoScaleVmProfile(CreateAutoScaleVmProfileCmd cmd) { |
| |
| Account owner = _accountDao.findById(cmd.getAccountId()); |
| Account caller = CallContext.current().getCallingAccount(); |
| _accountMgr.checkAccess(caller, null, true, owner); |
| |
| long zoneId = cmd.getZoneId(); |
| long serviceOfferingId = cmd.getServiceOfferingId(); |
| long autoscaleUserId = cmd.getAutoscaleUserId(); |
| |
| DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId); |
| |
| if (zone == null) { |
| throw new InvalidParameterValueException("Unable to find zone by id"); |
| } |
| |
| ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); |
| if (serviceOffering == null) { |
| throw new InvalidParameterValueException("Unable to find service offering by id"); |
| } |
| |
| // validations |
| HashMap<String, String> deployParams = cmd.getDeployParamMap(); |
| if (deployParams.containsKey("networks") && deployParams.get("networks").length() > 0) { |
| throw new InvalidParameterValueException( |
| "'networks' is not a valid parameter, network for an AutoScaled VM is chosen automatically. An autoscaled VM is deployed in the loadbalancer's network"); |
| } |
| /* |
| * Just for making sure the values are right in other deploy params. |
| * For ex. if projectId is given as a string instead of an long value, this |
| * will be throwing an error. |
| */ |
| dispatchChainFactory.getStandardDispatchChain().dispatch(new DispatchTask(ComponentContext.inject(DeployVMCmd.class), deployParams)); |
| |
| AutoScaleVmProfileVO profileVO = |
| new AutoScaleVmProfileVO(cmd.getZoneId(), cmd.getDomainId(), cmd.getAccountId(), cmd.getServiceOfferingId(), cmd.getTemplateId(), cmd.getOtherDeployParams(), |
| cmd.getCounterParamList(), cmd.getDestroyVmGraceperiod(), autoscaleUserId); |
| |
| if (cmd.getDisplay() != null) { |
| profileVO.setDisplay(cmd.getDisplay()); |
| } |
| |
| profileVO = checkValidityAndPersist(profileVO); |
| s_logger.info("Successfully create AutoScale Vm Profile with Id: " + profileVO.getId()); |
| |
| return profileVO; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMPROFILE_UPDATE, eventDescription = "updating autoscale vm profile") |
| public AutoScaleVmProfile updateAutoScaleVmProfile(UpdateAutoScaleVmProfileCmd cmd) { |
| Long profileId = cmd.getId(); |
| Long templateId = cmd.getTemplateId(); |
| Long autoscaleUserId = cmd.getAutoscaleUserId(); |
| Map counterParamList = cmd.getCounterParamList(); |
| |
| Integer destroyVmGraceperiod = cmd.getDestroyVmGraceperiod(); |
| |
| AutoScaleVmProfileVO vmProfile = getEntityInDatabase(CallContext.current().getCallingAccount(), "Auto Scale Vm Profile", profileId, _autoScaleVmProfileDao); |
| |
| boolean physicalParameterUpdate = (templateId != null || autoscaleUserId != null || counterParamList != null || destroyVmGraceperiod != null); |
| |
| if (templateId != null) { |
| vmProfile.setTemplateId(templateId); |
| } |
| |
| if (autoscaleUserId != null) { |
| vmProfile.setAutoscaleUserId(autoscaleUserId); |
| } |
| |
| if (counterParamList != null) { |
| vmProfile.setCounterParamsForUpdate(counterParamList); |
| } |
| |
| if (destroyVmGraceperiod != null) { |
| vmProfile.setDestroyVmGraceperiod(destroyVmGraceperiod); |
| } |
| |
| if (cmd.getCustomId() != null) { |
| vmProfile.setUuid(cmd.getCustomId()); |
| } |
| |
| if (cmd.getDisplay() != null) { |
| vmProfile.setDisplay(cmd.getDisplay()); |
| } |
| |
| List<AutoScaleVmGroupVO> vmGroupList = _autoScaleVmGroupDao.listByAll(null, profileId); |
| for (AutoScaleVmGroupVO vmGroupVO : vmGroupList) { |
| if (physicalParameterUpdate && !vmGroupVO.getState().equals(AutoScaleVmGroup.State_Disabled)) { |
| throw new InvalidParameterValueException("The AutoScale Vm Profile can be updated only if the Vm Group it is associated with is disabled in state"); |
| } |
| } |
| |
| vmProfile = checkValidityAndPersist(vmProfile); |
| s_logger.info("Updated Auto Scale Vm Profile id:" + vmProfile.getId()); |
| |
| return vmProfile; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMPROFILE_DELETE, eventDescription = "deleting autoscale vm profile") |
| public boolean deleteAutoScaleVmProfile(long id) { |
| /* Check if entity is in database */ |
| getEntityInDatabase(CallContext.current().getCallingAccount(), "AutoScale Vm Profile", id, _autoScaleVmProfileDao); |
| if (_autoScaleVmGroupDao.isProfileInUse(id)) { |
| throw new InvalidParameterValueException("Cannot delete AutoScale Vm Profile when it is in use by one more vm groups"); |
| } |
| boolean success = _autoScaleVmProfileDao.remove(id); |
| if (success) { |
| s_logger.info("Successfully deleted AutoScale Vm Profile with Id: " + id); |
| } |
| return success; |
| } |
| |
| @Override |
| public List<? extends AutoScaleVmProfile> listAutoScaleVmProfiles(ListAutoScaleVmProfilesCmd cmd) { |
| Long id = cmd.getId(); |
| Long templateId = cmd.getTemplateId(); |
| String otherDeployParams = cmd.getOtherDeployParams(); |
| Long serviceOffId = cmd.getServiceOfferingId(); |
| Long zoneId = cmd.getZoneId(); |
| Boolean display = cmd.getDisplay(); |
| |
| SearchWrapper<AutoScaleVmProfileVO> searchWrapper = new SearchWrapper<AutoScaleVmProfileVO>(_autoScaleVmProfileDao, AutoScaleVmProfileVO.class, cmd, cmd.getId()); |
| SearchBuilder<AutoScaleVmProfileVO> sb = searchWrapper.getSearchBuilder(); |
| |
| sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); |
| sb.and("templateId", sb.entity().getTemplateId(), SearchCriteria.Op.EQ); |
| sb.and("serviceOfferingId", sb.entity().getServiceOfferingId(), SearchCriteria.Op.EQ); |
| sb.and("otherDeployParams", sb.entity().getOtherDeployParams(), SearchCriteria.Op.LIKE); |
| sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ); |
| sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ); |
| SearchCriteria<AutoScaleVmProfileVO> sc = searchWrapper.buildSearchCriteria(); |
| |
| if (id != null) { |
| sc.setParameters("id", id); |
| } |
| if (templateId != null) { |
| sc.setParameters("templateId", templateId); |
| } |
| if (otherDeployParams != null) { |
| sc.addAnd("otherDeployParams", SearchCriteria.Op.LIKE, "%" + otherDeployParams + "%"); |
| } |
| |
| if (serviceOffId != null) { |
| sc.setParameters("serviceOfferingId", serviceOffId); |
| } |
| |
| if (zoneId != null) { |
| sc.setParameters("zoneId", zoneId); |
| } |
| |
| if (display != null) { |
| sc.setParameters("display", display); |
| } |
| |
| return searchWrapper.search(); |
| } |
| |
| @DB |
| protected AutoScalePolicyVO checkValidityAndPersist(final AutoScalePolicyVO autoScalePolicyVOFinal, final List<Long> conditionIds) { |
| final int duration = autoScalePolicyVOFinal.getDuration(); |
| final int quietTime = autoScalePolicyVOFinal.getQuietTime(); |
| |
| if (duration < 0) { |
| throw new InvalidParameterValueException("duration is an invalid value: " + duration); |
| } |
| |
| if (quietTime < 0) { |
| throw new InvalidParameterValueException("quiettime is an invalid value: " + quietTime); |
| } |
| |
| return Transaction.execute(new TransactionCallback<AutoScalePolicyVO>() { |
| @Override |
| public AutoScalePolicyVO doInTransaction(TransactionStatus status) { |
| AutoScalePolicyVO autoScalePolicyVO = _autoScalePolicyDao.persist(autoScalePolicyVOFinal); |
| |
| if (conditionIds != null) { |
| SearchBuilder<ConditionVO> conditionsSearch = _conditionDao.createSearchBuilder(); |
| conditionsSearch.and("ids", conditionsSearch.entity().getId(), Op.IN); |
| conditionsSearch.done(); |
| SearchCriteria<ConditionVO> sc = conditionsSearch.create(); |
| |
| sc.setParameters("ids", conditionIds.toArray(new Object[0])); |
| List<ConditionVO> conditions = _conditionDao.search(sc, null); |
| |
| ControlledEntity[] sameOwnerEntities = conditions.toArray(new ControlledEntity[conditions.size() + 1]); |
| sameOwnerEntities[sameOwnerEntities.length - 1] = autoScalePolicyVO; |
| _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, sameOwnerEntities); |
| |
| if (conditionIds.size() != conditions.size()) { |
| // TODO report the condition id which could not be found |
| throw new InvalidParameterValueException("Unable to find the condition specified"); |
| } |
| |
| ArrayList<Long> counterIds = new ArrayList<Long>(); |
| for (ConditionVO condition : conditions) { |
| if (counterIds.contains(condition.getCounterid())) { |
| throw new InvalidParameterValueException( |
| "atleast two conditions in the conditionids have the same counter. It is not right to apply two different conditions for the same counter"); |
| } |
| counterIds.add(condition.getCounterid()); |
| } |
| |
| /* For update case remove the existing mappings and create fresh ones */ |
| _autoScalePolicyConditionMapDao.removeByAutoScalePolicyId(autoScalePolicyVO.getId()); |
| |
| for (Long conditionId : conditionIds) { |
| AutoScalePolicyConditionMapVO policyConditionMapVO = new AutoScalePolicyConditionMapVO(autoScalePolicyVO.getId(), conditionId); |
| _autoScalePolicyConditionMapDao.persist(policyConditionMapVO); |
| } |
| } |
| |
| return autoScalePolicyVO; |
| } |
| }); |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEPOLICY_CREATE, eventDescription = "creating autoscale policy", create = true) |
| public AutoScalePolicy createAutoScalePolicy(CreateAutoScalePolicyCmd cmd) { |
| |
| int duration = cmd.getDuration(); |
| Integer quietTime = cmd.getQuietTime(); |
| String action = cmd.getAction(); |
| |
| if (quietTime == null) { |
| quietTime = NetUtils.DEFAULT_AUTOSCALE_POLICY_QUIET_TIME; |
| } |
| |
| action = action.toLowerCase(); |
| if (!NetUtils.isValidAutoScaleAction(action)) { |
| throw new InvalidParameterValueException("action is invalid, only 'scaleup' and 'scaledown' is supported"); |
| } |
| |
| AutoScalePolicyVO policyVO = new AutoScalePolicyVO(cmd.getDomainId(), cmd.getAccountId(), duration, quietTime, null, action); |
| |
| policyVO = checkValidityAndPersist(policyVO, cmd.getConditionIds()); |
| s_logger.info("Successfully created AutoScale Policy with Id: " + policyVO.getId()); |
| return policyVO; |
| } |
| |
| @Override |
| @DB |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEPOLICY_DELETE, eventDescription = "deleting autoscale policy") |
| public boolean deleteAutoScalePolicy(final long id) { |
| /* Check if entity is in database */ |
| getEntityInDatabase(CallContext.current().getCallingAccount(), "AutoScale Policy", id, _autoScalePolicyDao); |
| |
| if (_autoScaleVmGroupPolicyMapDao.isAutoScalePolicyInUse(id)) { |
| throw new InvalidParameterValueException("Cannot delete AutoScale Policy when it is in use by one or more AutoScale Vm Groups"); |
| } |
| |
| return Transaction.execute(new TransactionCallback<Boolean>() { |
| @Override |
| public Boolean doInTransaction(TransactionStatus status) { |
| boolean success = true; |
| success = _autoScalePolicyDao.remove(id); |
| if (!success) { |
| s_logger.warn("Failed to remove AutoScale Policy db object"); |
| return false; |
| } |
| success = _autoScalePolicyConditionMapDao.removeByAutoScalePolicyId(id); |
| if (!success) { |
| s_logger.warn("Failed to remove AutoScale Policy Condition mappings"); |
| return false; |
| } |
| s_logger.info("Successfully deleted autoscale policy id : " + id); |
| |
| return success; |
| } |
| }); |
| } |
| |
| public void checkCallerAccess(String accountName, Long domainId) { |
| Account caller = CallContext.current().getCallingAccount(); |
| Account owner = _accountDao.findActiveAccount(accountName, domainId); |
| if (owner == null) { |
| List<String> idList = new ArrayList<String>(); |
| idList.add(ApiDBUtils.findDomainById(domainId).getUuid()); |
| throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain with specifed domainId"); |
| } |
| _accountMgr.checkAccess(caller, null, false, owner); |
| } |
| |
| private class SearchWrapper<VO extends ControlledEntity> { |
| GenericDao<VO, Long> dao; |
| SearchBuilder<VO> searchBuilder; |
| SearchCriteria<VO> searchCriteria; |
| Long domainId; |
| boolean isRecursive; |
| List<Long> permittedAccounts = new ArrayList<Long>(); |
| ListProjectResourcesCriteria listProjectResourcesCriteria; |
| Filter searchFilter; |
| |
| public SearchWrapper(GenericDao<VO, Long> dao, Class<VO> entityClass, BaseListAccountResourcesCmd cmd, Long id) |
| { |
| this.dao = dao; |
| this.searchBuilder = dao.createSearchBuilder(); |
| domainId = cmd.getDomainId(); |
| String accountName = cmd.getAccountName(); |
| isRecursive = cmd.isRecursive(); |
| boolean listAll = cmd.listAll(); |
| long startIndex = cmd.getStartIndex(); |
| long pageSizeVal = cmd.getPageSizeVal(); |
| Account caller = CallContext.current().getCallingAccount(); |
| |
| Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, |
| ListProjectResourcesCriteria>(domainId, isRecursive, null); |
| _accountMgr.buildACLSearchParameters(caller, id, accountName, null, permittedAccounts, domainIdRecursiveListProject, |
| listAll, false); |
| domainId = domainIdRecursiveListProject.first(); |
| isRecursive = domainIdRecursiveListProject.second(); |
| ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); |
| _accountMgr.buildACLSearchBuilder(searchBuilder, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); |
| searchFilter = new Filter(entityClass, "id", false, startIndex, pageSizeVal); |
| } |
| |
| public SearchBuilder<VO> getSearchBuilder() { |
| return searchBuilder; |
| } |
| |
| public SearchCriteria<VO> buildSearchCriteria() { |
| searchCriteria = searchBuilder.create(); |
| _accountMgr.buildACLSearchCriteria(searchCriteria, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); |
| return searchCriteria; |
| } |
| |
| public List<VO> search() { |
| return dao.search(searchCriteria, searchFilter); |
| } |
| } |
| |
| @Override |
| public List<? extends AutoScalePolicy> listAutoScalePolicies(ListAutoScalePoliciesCmd cmd) { |
| SearchWrapper<AutoScalePolicyVO> searchWrapper = new SearchWrapper<AutoScalePolicyVO>(_autoScalePolicyDao, AutoScalePolicyVO.class, cmd, cmd.getId()); |
| SearchBuilder<AutoScalePolicyVO> sb = searchWrapper.getSearchBuilder(); |
| Long id = cmd.getId(); |
| Long conditionId = cmd.getConditionId(); |
| String action = cmd.getAction(); |
| Long vmGroupId = cmd.getVmGroupId(); |
| |
| sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); |
| sb.and("action", sb.entity().getAction(), SearchCriteria.Op.EQ); |
| |
| if (conditionId != null) { |
| SearchBuilder<AutoScalePolicyConditionMapVO> asPolicyConditionSearch = _autoScalePolicyConditionMapDao.createSearchBuilder(); |
| asPolicyConditionSearch.and("conditionId", asPolicyConditionSearch.entity().getConditionId(), SearchCriteria.Op.EQ); |
| sb.join("asPolicyConditionSearch", asPolicyConditionSearch, sb.entity().getId(), asPolicyConditionSearch.entity().getPolicyId(), JoinBuilder.JoinType.INNER); |
| } |
| |
| if (vmGroupId != null) { |
| SearchBuilder<AutoScaleVmGroupPolicyMapVO> asVmGroupPolicySearch = _autoScaleVmGroupPolicyMapDao.createSearchBuilder(); |
| asVmGroupPolicySearch.and("vmGroupId", asVmGroupPolicySearch.entity().getVmGroupId(), SearchCriteria.Op.EQ); |
| sb.join("asVmGroupPolicySearch", asVmGroupPolicySearch, sb.entity().getId(), asVmGroupPolicySearch.entity().getPolicyId(), JoinBuilder.JoinType.INNER); |
| } |
| |
| SearchCriteria<AutoScalePolicyVO> sc = searchWrapper.buildSearchCriteria(); |
| |
| if (id != null) { |
| sc.setParameters("id", id); |
| } |
| |
| if (action != null) { |
| sc.setParameters("action", action); |
| } |
| |
| if (conditionId != null) { |
| sc.setJoinParameters("asPolicyConditionSearch", "conditionId", conditionId); |
| } |
| |
| if (vmGroupId != null) { |
| sc.setJoinParameters("asVmGroupPolicySearch", "vmGroupId", vmGroupId); |
| } |
| |
| return searchWrapper.search(); |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEPOLICY_UPDATE, eventDescription = "updating autoscale policy") |
| public AutoScalePolicy updateAutoScalePolicy(UpdateAutoScalePolicyCmd cmd) { |
| Long policyId = cmd.getId(); |
| Integer duration = cmd.getDuration(); |
| Integer quietTime = cmd.getQuietTime(); |
| List<Long> conditionIds = cmd.getConditionIds(); |
| AutoScalePolicyVO policy = getEntityInDatabase(CallContext.current().getCallingAccount(), "Auto Scale Policy", policyId, _autoScalePolicyDao); |
| |
| if (duration != null) { |
| policy.setDuration(duration); |
| } |
| |
| if (quietTime != null) { |
| policy.setQuietTime(quietTime); |
| } |
| |
| List<AutoScaleVmGroupPolicyMapVO> vmGroupPolicyList = _autoScaleVmGroupPolicyMapDao.listByPolicyId(policyId); |
| for (AutoScaleVmGroupPolicyMapVO vmGroupPolicy : vmGroupPolicyList) { |
| AutoScaleVmGroupVO vmGroupVO = _autoScaleVmGroupDao.findById(vmGroupPolicy.getVmGroupId()); |
| if (vmGroupVO == null) { |
| s_logger.warn("Stale database entry! There is an entry in VmGroupPolicyMap but the vmGroup is missing:" + vmGroupPolicy.getVmGroupId()); |
| |
| continue; |
| |
| } |
| if (!vmGroupVO.getState().equals(AutoScaleVmGroup.State_Disabled)) { |
| throw new InvalidParameterValueException("The AutoScale Policy can be updated only if the Vm Group it is associated with is disabled in state"); |
| } |
| if (policy.getDuration() < vmGroupVO.getInterval()) { |
| throw new InvalidParameterValueException("duration is less than the associated AutoScaleVmGroup's interval"); |
| } |
| } |
| |
| policy = checkValidityAndPersist(policy, conditionIds); |
| s_logger.info("Successfully updated Auto Scale Policy id:" + policyId); |
| return policy; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMGROUP_CREATE, eventDescription = "creating autoscale vm group", create = true) |
| public AutoScaleVmGroup createAutoScaleVmGroup(CreateAutoScaleVmGroupCmd cmd) { |
| int minMembers = cmd.getMinMembers(); |
| int maxMembers = cmd.getMaxMembers(); |
| Integer interval = cmd.getInterval(); |
| Boolean forDisplay = cmd.getDisplay(); |
| |
| if (interval == null) { |
| interval = NetUtils.DEFAULT_AUTOSCALE_POLICY_INTERVAL_TIME; |
| } |
| |
| LoadBalancerVO loadBalancer = getEntityInDatabase(CallContext.current().getCallingAccount(), ApiConstants.LBID, cmd.getLbRuleId(), _lbDao); |
| |
| Long zoneId = _ipAddressDao.findById(loadBalancer.getSourceIpAddressId()).getDataCenterId(); |
| |
| if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(loadBalancer.getId())) { |
| throw new InvalidParameterValueException("an AutoScaleVmGroup is already attached to the lb rule, the existing vm group has to be first deleted"); |
| } |
| |
| if (_lb2VmMapDao.isVmAttachedToLoadBalancer(loadBalancer.getId())) { |
| throw new InvalidParameterValueException( |
| "there are Vms already bound to the specified LoadBalancing Rule. User bound Vms and AutoScaled Vm Group cannot co-exist on a Load Balancing Rule"); |
| } |
| |
| AutoScaleVmGroupVO vmGroupVO = new AutoScaleVmGroupVO(cmd.getLbRuleId(), zoneId, loadBalancer.getDomainId(), loadBalancer.getAccountId(), minMembers, maxMembers, |
| loadBalancer.getDefaultPortStart(), interval, null, cmd.getProfileId(), AutoScaleVmGroup.State_New); |
| |
| if (forDisplay != null) { |
| vmGroupVO.setDisplay(forDisplay); |
| } |
| |
| vmGroupVO = checkValidityAndPersist(vmGroupVO, cmd.getScaleUpPolicyIds(), cmd.getScaleDownPolicyIds()); |
| s_logger.info("Successfully created Autoscale Vm Group with Id: " + vmGroupVO.getId()); |
| |
| return vmGroupVO; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMGROUP_CREATE, eventDescription = "creating autoscale vm group", async = true) |
| public boolean configureAutoScaleVmGroup(CreateAutoScaleVmGroupCmd cmd) throws ResourceUnavailableException { |
| return configureAutoScaleVmGroup(cmd.getEntityId(), AutoScaleVmGroup.State_New); |
| } |
| |
| public boolean isLoadBalancerBasedAutoScaleVmGroup(AutoScaleVmGroup vmGroup) { |
| return vmGroup.getLoadBalancerId() != null; |
| } |
| |
| private boolean configureAutoScaleVmGroup(long vmGroupid, String currentState) throws ResourceUnavailableException { |
| AutoScaleVmGroup vmGroup = _autoScaleVmGroupDao.findById(vmGroupid); |
| |
| if (isLoadBalancerBasedAutoScaleVmGroup(vmGroup)) { |
| try { |
| return _lbRulesMgr.configureLbAutoScaleVmGroup(vmGroupid, currentState); |
| } catch (ResourceUnavailableException re) { |
| throw re; |
| } catch (Exception e) { |
| s_logger.warn("Exception during configureLbAutoScaleVmGroup in lb rules manager", e); |
| return false; |
| } |
| } |
| |
| // This should never happen, because today loadbalancerruleid is manadatory for AutoScaleVmGroup. |
| throw new InvalidParameterValueException("Only LoadBalancer based AutoScale is supported"); |
| } |
| |
| @Override |
| @DB |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMGROUP_DELETE, eventDescription = "deleting autoscale vm group", async = true) |
| public boolean deleteAutoScaleVmGroup(final long id) { |
| AutoScaleVmGroupVO autoScaleVmGroupVO = getEntityInDatabase(CallContext.current().getCallingAccount(), "AutoScale Vm Group", id, _autoScaleVmGroupDao); |
| |
| if (autoScaleVmGroupVO.getState().equals(AutoScaleVmGroup.State_New)) { |
| /* This condition is for handling failures during creation command */ |
| return _autoScaleVmGroupDao.remove(id); |
| } |
| String bakupState = autoScaleVmGroupVO.getState(); |
| autoScaleVmGroupVO.setState(AutoScaleVmGroup.State_Revoke); |
| _autoScaleVmGroupDao.persist(autoScaleVmGroupVO); |
| boolean success = false; |
| |
| try { |
| success = configureAutoScaleVmGroup(id, bakupState); |
| } catch (ResourceUnavailableException e) { |
| autoScaleVmGroupVO.setState(bakupState); |
| _autoScaleVmGroupDao.persist(autoScaleVmGroupVO); |
| } finally { |
| if (!success) { |
| s_logger.warn("Could not delete AutoScale Vm Group id : " + id); |
| return false; |
| } |
| } |
| |
| return Transaction.execute(new TransactionCallback<Boolean>() { |
| @Override |
| public Boolean doInTransaction(TransactionStatus status) { |
| boolean success = _autoScaleVmGroupDao.remove(id); |
| |
| if (!success) { |
| s_logger.warn("Failed to remove AutoScale Group db object"); |
| return false; |
| } |
| |
| success = _autoScaleVmGroupPolicyMapDao.removeByGroupId(id); |
| if (!success) { |
| s_logger.warn("Failed to remove AutoScale Group Policy mappings"); |
| return false; |
| } |
| |
| s_logger.info("Successfully deleted autoscale vm group id : " + id); |
| return success; // Successfull |
| } |
| }); |
| |
| } |
| |
| @Override |
| public List<? extends AutoScaleVmGroup> listAutoScaleVmGroups(ListAutoScaleVmGroupsCmd cmd) { |
| Long id = cmd.getId(); |
| Long policyId = cmd.getPolicyId(); |
| Long loadBalancerId = cmd.getLoadBalancerId(); |
| Long profileId = cmd.getProfileId(); |
| Long zoneId = cmd.getZoneId(); |
| Boolean forDisplay = cmd.getDisplay(); |
| |
| SearchWrapper<AutoScaleVmGroupVO> searchWrapper = new SearchWrapper<AutoScaleVmGroupVO>(_autoScaleVmGroupDao, AutoScaleVmGroupVO.class, cmd, cmd.getId()); |
| SearchBuilder<AutoScaleVmGroupVO> sb = searchWrapper.getSearchBuilder(); |
| |
| sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); |
| sb.and("loadBalancerId", sb.entity().getLoadBalancerId(), SearchCriteria.Op.EQ); |
| sb.and("profileId", sb.entity().getProfileId(), SearchCriteria.Op.EQ); |
| sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ); |
| sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ); |
| |
| if (policyId != null) { |
| SearchBuilder<AutoScaleVmGroupPolicyMapVO> asVmGroupPolicySearch = _autoScaleVmGroupPolicyMapDao.createSearchBuilder(); |
| asVmGroupPolicySearch.and("policyId", asVmGroupPolicySearch.entity().getPolicyId(), SearchCriteria.Op.EQ); |
| sb.join("asVmGroupPolicySearch", asVmGroupPolicySearch, sb.entity().getId(), asVmGroupPolicySearch.entity().getVmGroupId(), JoinBuilder.JoinType.INNER); |
| } |
| |
| SearchCriteria<AutoScaleVmGroupVO> sc = searchWrapper.buildSearchCriteria(); |
| if (id != null) { |
| sc.setParameters("id", id); |
| } |
| if (loadBalancerId != null) { |
| sc.setParameters("loadBalancerId", loadBalancerId); |
| } |
| if (profileId != null) { |
| sc.setParameters("profileId", profileId); |
| } |
| if (zoneId != null) { |
| sc.setParameters("zoneId", zoneId); |
| } |
| if (policyId != null) { |
| sc.setJoinParameters("asVmGroupPolicySearch", "policyId", policyId); |
| } |
| if (forDisplay != null) { |
| sc.setParameters("display", forDisplay); |
| } |
| return searchWrapper.search(); |
| } |
| |
| @DB |
| protected AutoScaleVmGroupVO checkValidityAndPersist(final AutoScaleVmGroupVO vmGroup, final List<Long> passedScaleUpPolicyIds, |
| final List<Long> passedScaleDownPolicyIds) { |
| int minMembers = vmGroup.getMinMembers(); |
| int maxMembers = vmGroup.getMaxMembers(); |
| int interval = vmGroup.getInterval(); |
| List<Counter> counters = new ArrayList<Counter>(); |
| List<AutoScalePolicyVO> policies = new ArrayList<AutoScalePolicyVO>(); |
| final List<Long> policyIds = new ArrayList<Long>(); |
| List<Long> currentScaleUpPolicyIds = new ArrayList<Long>(); |
| List<Long> currentScaleDownPolicyIds = new ArrayList<Long>(); |
| if (vmGroup.getCreated() != null) { |
| ApiDBUtils.getAutoScaleVmGroupPolicyIds(vmGroup.getId(), currentScaleUpPolicyIds, currentScaleDownPolicyIds); |
| } |
| |
| if (minMembers < 0) { |
| throw new InvalidParameterValueException(ApiConstants.MIN_MEMBERS + " is an invalid value: " + minMembers); |
| } |
| |
| if (maxMembers < 0) { |
| throw new InvalidParameterValueException(ApiConstants.MAX_MEMBERS + " is an invalid value: " + maxMembers); |
| } |
| |
| if (minMembers > maxMembers) { |
| throw new InvalidParameterValueException(ApiConstants.MIN_MEMBERS + " (" + minMembers + ")cannot be greater than " + ApiConstants.MAX_MEMBERS + " (" + |
| maxMembers + ")"); |
| } |
| |
| if (interval < 0) { |
| throw new InvalidParameterValueException("interval is an invalid value: " + interval); |
| } |
| |
| if (passedScaleUpPolicyIds != null) { |
| policies.addAll(getAutoScalePolicies("scaleuppolicyid", passedScaleUpPolicyIds, counters, interval, true)); |
| policyIds.addAll(passedScaleUpPolicyIds); |
| } else { |
| // Run the interval check for existing policies |
| getAutoScalePolicies("scaleuppolicyid", currentScaleUpPolicyIds, counters, interval, true); |
| policyIds.addAll(currentScaleUpPolicyIds); |
| } |
| |
| if (passedScaleDownPolicyIds != null) { |
| policies.addAll(getAutoScalePolicies("scaledownpolicyid", passedScaleDownPolicyIds, counters, interval, false)); |
| policyIds.addAll(passedScaleDownPolicyIds); |
| } else { |
| // Run the interval check for existing policies |
| getAutoScalePolicies("scaledownpolicyid", currentScaleDownPolicyIds, counters, interval, false); |
| policyIds.addAll(currentScaleDownPolicyIds); |
| } |
| AutoScaleVmProfileVO profileVO = |
| getEntityInDatabase(CallContext.current().getCallingAccount(), ApiConstants.VMPROFILE_ID, vmGroup.getProfileId(), _autoScaleVmProfileDao); |
| |
| LoadBalancerVO loadBalancer = getEntityInDatabase(CallContext.current().getCallingAccount(), ApiConstants.LBID, vmGroup.getLoadBalancerId(), _lbDao); |
| validateAutoScaleCounters(loadBalancer.getNetworkId(), counters, profileVO.getCounterParams()); |
| |
| ControlledEntity[] sameOwnerEntities = policies.toArray(new ControlledEntity[policies.size() + 2]); |
| sameOwnerEntities[sameOwnerEntities.length - 2] = loadBalancer; |
| sameOwnerEntities[sameOwnerEntities.length - 1] = profileVO; |
| _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, sameOwnerEntities); |
| |
| return Transaction.execute(new TransactionCallback<AutoScaleVmGroupVO>() { |
| @Override |
| public AutoScaleVmGroupVO doInTransaction(TransactionStatus status) { |
| AutoScaleVmGroupVO vmGroupNew = _autoScaleVmGroupDao.persist(vmGroup); |
| |
| if (passedScaleUpPolicyIds != null || passedScaleDownPolicyIds != null) { |
| _autoScaleVmGroupPolicyMapDao.removeByGroupId(vmGroupNew.getId()); |
| |
| for (Long policyId : policyIds) { |
| _autoScaleVmGroupPolicyMapDao.persist(new AutoScaleVmGroupPolicyMapVO(vmGroupNew.getId(), policyId)); |
| } |
| } |
| |
| return vmGroupNew; |
| } |
| }); |
| |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMGROUP_UPDATE, eventDescription = "updating autoscale vm group", async = true) |
| public AutoScaleVmGroup updateAutoScaleVmGroup(UpdateAutoScaleVmGroupCmd cmd) { |
| Long vmGroupId = cmd.getId(); |
| Integer minMembers = cmd.getMinMembers(); |
| Integer maxMembers = cmd.getMaxMembers(); |
| Integer interval = cmd.getInterval(); |
| Boolean forDisplay = cmd.getDisplay(); |
| |
| List<Long> scaleUpPolicyIds = cmd.getScaleUpPolicyIds(); |
| List<Long> scaleDownPolicyIds = cmd.getScaleDownPolicyIds(); |
| |
| AutoScaleVmGroupVO vmGroupVO = getEntityInDatabase(CallContext.current().getCallingAccount(), "AutoScale Vm Group", vmGroupId, _autoScaleVmGroupDao); |
| |
| boolean physicalParametersUpdate = (minMembers != null || maxMembers != null || interval != null); |
| |
| if (physicalParametersUpdate && !vmGroupVO.getState().equals(AutoScaleVmGroup.State_Disabled)) { |
| throw new InvalidParameterValueException("An AutoScale Vm Group can be updated with minMembers/maxMembers/Interval only when it is in disabled state"); |
| } |
| |
| if (minMembers != null) { |
| vmGroupVO.setMinMembers(minMembers); |
| } |
| |
| if (maxMembers != null) { |
| vmGroupVO.setMaxMembers(maxMembers); |
| } |
| |
| if (maxMembers != null) { |
| vmGroupVO.setInterval(interval); |
| } |
| |
| if (cmd.getCustomId() != null) { |
| vmGroupVO.setUuid(cmd.getCustomId()); |
| } |
| |
| if (forDisplay != null) { |
| vmGroupVO.setDisplay(forDisplay); |
| } |
| |
| vmGroupVO = checkValidityAndPersist(vmGroupVO, scaleUpPolicyIds, scaleDownPolicyIds); |
| if (vmGroupVO != null) { |
| s_logger.debug("Updated Auto Scale VmGroup id:" + vmGroupId); |
| return vmGroupVO; |
| } else |
| return null; |
| } |
| |
| @Override |
| @DB |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMGROUP_ENABLE, eventDescription = "enabling autoscale vm group", async = true) |
| public AutoScaleVmGroup enableAutoScaleVmGroup(Long id) { |
| AutoScaleVmGroupVO vmGroup = getEntityInDatabase(CallContext.current().getCallingAccount(), "AutoScale Vm Group", id, _autoScaleVmGroupDao); |
| boolean success = false; |
| if (!vmGroup.getState().equals(AutoScaleVmGroup.State_Disabled)) { |
| throw new InvalidParameterValueException("Only a AutoScale Vm Group which is in Disabled state can be enabled."); |
| } |
| |
| try { |
| vmGroup.setState(AutoScaleVmGroup.State_Enabled); |
| vmGroup = _autoScaleVmGroupDao.persist(vmGroup); |
| success = configureAutoScaleVmGroup(id, AutoScaleVmGroup.State_Disabled); |
| } catch (ResourceUnavailableException e) { |
| vmGroup.setState(AutoScaleVmGroup.State_Disabled); |
| _autoScaleVmGroupDao.persist(vmGroup); |
| } finally { |
| if (!success) { |
| s_logger.warn("Failed to enable AutoScale Vm Group id : " + id); |
| return null; |
| } |
| s_logger.info("Successfully enabled AutoScale Vm Group with Id:" + id); |
| } |
| return vmGroup; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMGROUP_DISABLE, eventDescription = "disabling autoscale vm group", async = true) |
| @DB |
| public AutoScaleVmGroup disableAutoScaleVmGroup(Long id) { |
| AutoScaleVmGroupVO vmGroup = getEntityInDatabase(CallContext.current().getCallingAccount(), "AutoScale Vm Group", id, _autoScaleVmGroupDao); |
| boolean success = false; |
| if (!vmGroup.getState().equals(AutoScaleVmGroup.State_Enabled)) { |
| throw new InvalidParameterValueException("Only a AutoScale Vm Group which is in Enabled state can be disabled."); |
| } |
| |
| try { |
| vmGroup.setState(AutoScaleVmGroup.State_Disabled); |
| vmGroup = _autoScaleVmGroupDao.persist(vmGroup); |
| success = configureAutoScaleVmGroup(id, AutoScaleVmGroup.State_Enabled); |
| } catch (ResourceUnavailableException e) { |
| vmGroup.setState(AutoScaleVmGroup.State_Enabled); |
| _autoScaleVmGroupDao.persist(vmGroup); |
| } finally { |
| if (!success) { |
| s_logger.warn("Failed to disable AutoScale Vm Group id : " + id); |
| return null; |
| } |
| s_logger.info("Successfully disabled AutoScale Vm Group with Id:" + id); |
| } |
| return vmGroup; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_COUNTER_CREATE, eventDescription = "Counter", create = true) |
| @DB |
| public Counter createCounter(CreateCounterCmd cmd) { |
| String source = cmd.getSource().toLowerCase(); |
| String name = cmd.getName(); |
| Counter.Source src; |
| // Validate Source |
| try { |
| src = Counter.Source.valueOf(source); |
| } catch (Exception ex) { |
| throw new InvalidParameterValueException("The Source " + source + " does not exist; Unable to create Counter"); |
| } |
| |
| CounterVO counter = null; |
| |
| s_logger.debug("Adding Counter " + name); |
| counter = _counterDao.persist(new CounterVO(src, name, cmd.getValue())); |
| |
| CallContext.current().setEventDetails(" Id: " + counter.getId() + " Name: " + name); |
| return counter; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_CONDITION_CREATE, eventDescription = "Condition", create = true) |
| public Condition createCondition(CreateConditionCmd cmd) { |
| checkCallerAccess(cmd.getAccountName(), cmd.getDomainId()); |
| String opr = cmd.getRelationalOperator().toUpperCase(); |
| long cid = cmd.getCounterId(); |
| long threshold = cmd.getThreshold(); |
| Condition.Operator op; |
| // Validate Relational Operator |
| try { |
| op = Condition.Operator.valueOf(opr); |
| } catch (IllegalArgumentException ex) { |
| throw new InvalidParameterValueException("The Operator " + opr + " does not exist; Unable to create Condition."); |
| } |
| // TODO - Validate threshold |
| |
| CounterVO counter = _counterDao.findById(cid); |
| |
| if (counter == null) { |
| throw new InvalidParameterValueException("Unable to find counter"); |
| } |
| ConditionVO condition = null; |
| |
| condition = _conditionDao.persist(new ConditionVO(cid, threshold, cmd.getEntityOwnerId(), cmd.getDomainId(), op)); |
| s_logger.info("Successfully created condition with Id: " + condition.getId()); |
| |
| CallContext.current().setEventDetails(" Id: " + condition.getId()); |
| return condition; |
| } |
| |
| @Override |
| public List<? extends Counter> listCounters(ListCountersCmd cmd) { |
| String name = cmd.getName(); |
| Long id = cmd.getId(); |
| String source = cmd.getSource(); |
| if (source != null) |
| source = source.toLowerCase(); |
| |
| Filter searchFilter = new Filter(CounterVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal()); |
| |
| List<CounterVO> counters = _counterDao.listCounters(id, name, source, cmd.getKeyword(), searchFilter); |
| |
| return counters; |
| } |
| |
| @Override |
| public List<? extends Condition> listConditions(ListConditionsCmd cmd) { |
| Long id = cmd.getId(); |
| Long counterId = cmd.getCounterId(); |
| Long policyId = cmd.getPolicyId(); |
| SearchWrapper<ConditionVO> searchWrapper = new SearchWrapper<ConditionVO>(_conditionDao, ConditionVO.class, cmd, cmd.getId()); |
| SearchBuilder<ConditionVO> sb = searchWrapper.getSearchBuilder(); |
| if (policyId != null) { |
| SearchBuilder<AutoScalePolicyConditionMapVO> asPolicyConditionSearch = _autoScalePolicyConditionMapDao.createSearchBuilder(); |
| asPolicyConditionSearch.and("policyId", asPolicyConditionSearch.entity().getPolicyId(), SearchCriteria.Op.EQ); |
| sb.join("asPolicyConditionSearch", asPolicyConditionSearch, sb.entity().getId(), asPolicyConditionSearch.entity().getConditionId(), |
| JoinBuilder.JoinType.INNER); |
| } |
| |
| sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); |
| sb.and("counterId", sb.entity().getCounterid(), SearchCriteria.Op.EQ); |
| |
| // now set the SC criteria... |
| SearchCriteria<ConditionVO> sc = searchWrapper.buildSearchCriteria(); |
| |
| if (id != null) { |
| sc.setParameters("id", id); |
| } |
| |
| if (counterId != null) { |
| sc.setParameters("counterId", counterId); |
| } |
| |
| if (policyId != null) { |
| sc.setJoinParameters("asPolicyConditionSearch", "policyId", policyId); |
| } |
| |
| return searchWrapper.search(); |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_COUNTER_DELETE, eventDescription = "counter") |
| public boolean deleteCounter(long counterId) throws ResourceInUseException { |
| // Verify Counter id |
| CounterVO counter = _counterDao.findById(counterId); |
| if (counter == null) { |
| throw new InvalidParameterValueException("Unable to find Counter"); |
| } |
| |
| // Verify if it is used in any Condition |
| |
| ConditionVO condition = _conditionDao.findByCounterId(counterId); |
| if (condition != null) { |
| s_logger.info("Cannot delete counter " + counter.getName() + " as it is being used in a condition."); |
| throw new ResourceInUseException("Counter is in use."); |
| } |
| |
| boolean success = _counterDao.remove(counterId); |
| if (success) { |
| s_logger.info("Successfully deleted counter with Id: " + counterId); |
| } |
| |
| return success; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_CONDITION_DELETE, eventDescription = "condition") |
| public boolean deleteCondition(long conditionId) throws ResourceInUseException { |
| /* Check if entity is in database */ |
| ConditionVO condition = getEntityInDatabase(CallContext.current().getCallingAccount(), "Condition", conditionId, _conditionDao); |
| if (condition == null) { |
| throw new InvalidParameterValueException("Unable to find Condition"); |
| } |
| |
| // Verify if condition is used in any autoscale policy |
| if (_autoScalePolicyConditionMapDao.isConditionInUse(conditionId)) { |
| s_logger.info("Cannot delete condition " + conditionId + " as it is being used in a condition."); |
| throw new ResourceInUseException("Cannot delete Condition when it is in use by one or more AutoScale Policies."); |
| } |
| boolean success = _conditionDao.remove(conditionId); |
| if (success) { |
| s_logger.info("Successfully deleted condition " + condition.getId()); |
| } |
| return success; |
| } |
| |
| @Override |
| public void cleanUpAutoScaleResources(Long accountId) { |
| // cleans Autoscale VmProfiles, AutoScale Policies and Conditions belonging to an account |
| int count = 0; |
| count = _autoScaleVmProfileDao.removeByAccountId(accountId); |
| if (count > 0) { |
| s_logger.debug("Deleted " + count + " AutoScale Vm Profile for account Id: " + accountId); |
| } |
| count = _autoScalePolicyDao.removeByAccountId(accountId); |
| if (count > 0) { |
| s_logger.debug("Deleted " + count + " AutoScale Policies for account Id: " + accountId); |
| } |
| count = _conditionDao.removeByAccountId(accountId); |
| if (count > 0) { |
| s_logger.debug("Deleted " + count + " Conditions for account Id: " + accountId); |
| } |
| } |
| |
| private boolean checkConditionUp(AutoScaleVmGroupVO asGroup, Integer numVm) { |
| // check maximum |
| Integer currentVM = _autoScaleVmGroupVmMapDao.countByGroup(asGroup.getId()); |
| Integer maxVm = asGroup.getMaxMembers(); |
| if (currentVM + numVm > maxVm) { |
| s_logger.warn("number of VM will greater than the maximum in this group if scaling up, so do nothing more"); |
| return false; |
| } |
| return true; |
| } |
| |
| private boolean checkConditionDown(AutoScaleVmGroupVO asGroup) { |
| Integer currentVM = _autoScaleVmGroupVmMapDao.countByGroup(asGroup.getId()); |
| Integer minVm = asGroup.getMinMembers(); |
| if (currentVM - 1 < minVm) { |
| s_logger.warn("number of VM will less than the minimum in this group if scaling down, so do nothing more"); |
| return false; |
| } |
| return true; |
| } |
| |
| private long createNewVM(AutoScaleVmGroupVO asGroup) { |
| AutoScaleVmProfileVO profileVo = _autoScaleVmProfileDao.findById(asGroup.getProfileId()); |
| long templateId = profileVo.getTemplateId(); |
| long serviceOfferingId = profileVo.getServiceOfferingId(); |
| if (templateId == -1) { |
| return -1; |
| } |
| // create new VM into DB |
| try { |
| //Verify that all objects exist before passing them to the service |
| Account owner = _accountService.getActiveAccountById(profileVo.getAccountId()); |
| |
| DataCenter zone = _entityMgr.findById(DataCenter.class, profileVo.getZoneId()); |
| if (zone == null) { |
| throw new InvalidParameterValueException("Unable to find zone by id=" + profileVo.getZoneId()); |
| } |
| |
| ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); |
| if (serviceOffering == null) { |
| throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId); |
| } |
| |
| VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); |
| // Make sure a valid template ID was specified |
| if (template == null) { |
| throw new InvalidParameterValueException("Unable to use template " + templateId); |
| } |
| |
| if (!zone.isLocalStorageEnabled()) { |
| if (serviceOffering.getUseLocalStorage()) { |
| throw new InvalidParameterValueException("Zone is not configured to use local storage but service offering " + serviceOffering.getName() + " uses it"); |
| } |
| } |
| |
| UserVm vm = null; |
| IpAddresses addrs = new IpAddresses(null, null); |
| if (zone.getNetworkType() == NetworkType.Basic) { |
| 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); |
| } 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); |
| |
| } 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); |
| |
| } |
| } |
| |
| if (vm != null) { |
| return vm.getId(); |
| } else { |
| return -1; |
| } |
| } catch (InsufficientCapacityException ex) { |
| s_logger.info(ex); |
| s_logger.trace(ex.getMessage(), ex); |
| throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage()); |
| } catch (ResourceUnavailableException ex) { |
| s_logger.warn("Exception: ", ex); |
| throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); |
| } catch (ConcurrentOperationException ex) { |
| s_logger.warn("Exception: ", ex); |
| throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); |
| } catch (ResourceAllocationException ex) { |
| s_logger.warn("Exception: ", ex); |
| throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage()); |
| } |
| } |
| |
| private String getCurrentTimeStampString() { |
| Date current = new Date(); |
| SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); |
| |
| return sdf.format(current); |
| } |
| |
| private boolean startNewVM(long vmId) { |
| try { |
| CallContext.current().setEventDetails("Vm Id: " + vmId); |
| _userVmManager.startVirtualMachine(vmId, null, null, null); |
| } catch (final ResourceUnavailableException ex) { |
| s_logger.warn("Exception: ", ex); |
| throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); |
| } catch (ConcurrentOperationException ex) { |
| s_logger.warn("Exception: ", ex); |
| throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); |
| } catch (InsufficientCapacityException ex) { |
| StringBuilder message = new StringBuilder(ex.getMessage()); |
| if (ex instanceof InsufficientServerCapacityException) { |
| if (((InsufficientServerCapacityException)ex).isAffinityApplied()) { |
| message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them"); |
| } |
| } |
| s_logger.info(ex); |
| s_logger.info(message.toString(), ex); |
| throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString()); |
| } |
| return true; |
| } |
| |
| private boolean assignLBruleToNewVm(long vmId, AutoScaleVmGroupVO asGroup) { |
| List<Long> lstVmId = new ArrayList<Long>(); |
| long lbId = asGroup.getLoadBalancerId(); |
| |
| List<LoadBalancerVMMapVO> LbVmMapVos = _lbVmMapDao.listByLoadBalancerId(lbId); |
| if ((LbVmMapVos != null) && (LbVmMapVos.size() > 0)) { |
| for (LoadBalancerVMMapVO LbVmMapVo : LbVmMapVos) { |
| long instanceId = LbVmMapVo.getInstanceId(); |
| if (instanceId == vmId) { |
| s_logger.warn("the new VM is already mapped to LB rule. What's wrong?"); |
| return true; |
| } |
| } |
| } |
| lstVmId.add(new Long(vmId)); |
| return _loadBalancingRulesService.assignToLoadBalancer(lbId, lstVmId, new HashMap<Long, List<String>>()); |
| |
| } |
| |
| private long removeLBrule(AutoScaleVmGroupVO asGroup) { |
| long lbId = asGroup.getLoadBalancerId(); |
| long instanceId = -1; |
| List<LoadBalancerVMMapVO> LbVmMapVos = _lbVmMapDao.listByLoadBalancerId(lbId); |
| if ((LbVmMapVos != null) && (LbVmMapVos.size() > 0)) { |
| for (LoadBalancerVMMapVO LbVmMapVo : LbVmMapVos) { |
| instanceId = LbVmMapVo.getInstanceId(); |
| } |
| } |
| // take last VM out of the list |
| List<Long> lstVmId = new ArrayList<Long>(); |
| if (instanceId != -1) |
| lstVmId.add(instanceId); |
| if (_loadBalancingRulesService.removeFromLoadBalancer(lbId, lstVmId, new HashMap<Long, List<String>>())) |
| return instanceId; |
| else |
| return -1; |
| } |
| |
| @Override |
| public void doScaleUp(long groupId, Integer numVm) { |
| AutoScaleVmGroupVO asGroup = _autoScaleVmGroupDao.findById(groupId); |
| if (asGroup == null) { |
| s_logger.error("Can not find the groupid " + groupId + " for scaling up"); |
| return; |
| } |
| if (!checkConditionUp(asGroup, numVm)) { |
| return; |
| } |
| for (int i = 0; i < numVm; i++) { |
| long vmId = createNewVM(asGroup); |
| if (vmId == -1) { |
| s_logger.error("Can not deploy new VM for scaling up in the group " |
| + asGroup.getId() + ". Waiting for next round"); |
| break; |
| } |
| if (startNewVM(vmId)) { |
| if (assignLBruleToNewVm(vmId, asGroup)) { |
| // persist to DB |
| AutoScaleVmGroupVmMapVO GroupVmVO = new AutoScaleVmGroupVmMapVO( |
| asGroup.getId(), vmId); |
| _autoScaleVmGroupVmMapDao.persist(GroupVmVO); |
| // update last_quiettime |
| List<AutoScaleVmGroupPolicyMapVO> GroupPolicyVOs = _autoScaleVmGroupPolicyMapDao |
| .listByVmGroupId(groupId); |
| for (AutoScaleVmGroupPolicyMapVO GroupPolicyVO : GroupPolicyVOs) { |
| AutoScalePolicyVO vo = _autoScalePolicyDao |
| .findById(GroupPolicyVO.getPolicyId()); |
| if (vo.getAction().equals("scaleup")) { |
| vo.setLastQuiteTime(new Date()); |
| _autoScalePolicyDao.persist(vo); |
| break; |
| } |
| } |
| } else { |
| s_logger.error("Can not assign LB rule for this new VM"); |
| break; |
| } |
| } else { |
| s_logger.error("Can not deploy new VM for scaling up in the group " |
| + asGroup.getId() + ". Waiting for next round"); |
| break; |
| } |
| } |
| } |
| |
| @Override |
| public void doScaleDown(final long groupId) { |
| AutoScaleVmGroupVO asGroup = _autoScaleVmGroupDao.findById(groupId); |
| if (asGroup == null) { |
| s_logger.error("Can not find the groupid " + groupId + " for scaling up"); |
| return; |
| } |
| if (!checkConditionDown(asGroup)) { |
| return; |
| } |
| final long vmId = removeLBrule(asGroup); |
| if (vmId != -1) { |
| long profileId = asGroup.getProfileId(); |
| |
| // update group-vm mapping |
| _autoScaleVmGroupVmMapDao.remove(groupId, vmId); |
| // update last_quiettime |
| List<AutoScaleVmGroupPolicyMapVO> GroupPolicyVOs = _autoScaleVmGroupPolicyMapDao.listByVmGroupId(groupId); |
| for (AutoScaleVmGroupPolicyMapVO GroupPolicyVO : GroupPolicyVOs) { |
| AutoScalePolicyVO vo = _autoScalePolicyDao.findById(GroupPolicyVO.getPolicyId()); |
| if (vo.getAction().equals("scaledown")) { |
| vo.setLastQuiteTime(new Date()); |
| _autoScalePolicyDao.persist(vo); |
| break; |
| } |
| } |
| |
| // get destroyvmgrace param |
| AutoScaleVmProfileVO asProfile = _autoScaleVmProfileDao.findById(profileId); |
| Integer destroyVmGracePeriod = asProfile.getDestroyVmGraceperiod(); |
| if (destroyVmGracePeriod >= 0) { |
| _executor.schedule(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| |
| _userVmManager.destroyVm(vmId, false); |
| |
| } catch (ResourceUnavailableException e) { |
| e.printStackTrace(); |
| } catch (ConcurrentOperationException e) { |
| e.printStackTrace(); |
| } |
| } |
| }, destroyVmGracePeriod, TimeUnit.SECONDS); |
| } |
| } else { |
| s_logger.error("Can not remove LB rule for the VM being destroyed. Do nothing more."); |
| } |
| } |
| |
| } |