| // 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.lb; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import java.util.HashMap; | |
| import java.util.HashSet; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Set; | |
| import javax.inject.Inject; | |
| import com.cloud.offerings.NetworkOfferingServiceMapVO; | |
| import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; | |
| import org.apache.cloudstack.acl.SecurityChecker; | |
| import org.apache.cloudstack.api.ApiConstants; | |
| import org.apache.cloudstack.api.ApiErrorCode; | |
| import org.apache.cloudstack.api.ServerApiException; | |
| import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; | |
| import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; | |
| import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd; | |
| import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd; | |
| import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd; | |
| import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd; | |
| import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd; | |
| import org.apache.cloudstack.api.response.ServiceResponse; | |
| import org.apache.cloudstack.config.ApiServiceConfiguration; | |
| import org.apache.cloudstack.context.CallContext; | |
| import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; | |
| import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; | |
| import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; | |
| import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; | |
| import org.apache.commons.collections.CollectionUtils; | |
| import org.apache.commons.lang3.StringUtils; | |
| import com.cloud.agent.api.to.LoadBalancerTO; | |
| 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.dc.dao.VlanDao; | |
| import com.cloud.domain.dao.DomainDao; | |
| import com.cloud.event.ActionEvent; | |
| import com.cloud.event.EventTypes; | |
| import com.cloud.event.UsageEventUtils; | |
| import com.cloud.event.dao.EventDao; | |
| import com.cloud.event.dao.UsageEventDao; | |
| import com.cloud.exception.InsufficientAddressCapacityException; | |
| import com.cloud.exception.InvalidParameterValueException; | |
| import com.cloud.exception.NetworkRuleConflictException; | |
| import com.cloud.exception.PermissionDeniedException; | |
| import com.cloud.exception.ResourceUnavailableException; | |
| import com.cloud.network.ExternalDeviceUsageManager; | |
| import com.cloud.network.IpAddress; | |
| import com.cloud.network.IpAddressManager; | |
| import com.cloud.network.LBHealthCheckPolicyVO; | |
| import com.cloud.network.Network; | |
| import com.cloud.network.Network.Capability; | |
| import com.cloud.network.Network.Provider; | |
| import com.cloud.network.Network.Service; | |
| import com.cloud.network.NetworkModel; | |
| import com.cloud.network.addr.PublicIp; | |
| import com.cloud.network.as.AutoScaleManager; | |
| import com.cloud.network.as.AutoScalePolicy; | |
| import com.cloud.network.as.AutoScalePolicyConditionMapVO; | |
| import com.cloud.network.as.AutoScaleVmGroup; | |
| import com.cloud.network.as.AutoScaleVmGroupPolicyMapVO; | |
| import com.cloud.network.as.AutoScaleVmGroupVO; | |
| import com.cloud.network.as.AutoScaleVmProfile; | |
| import com.cloud.network.as.Condition; | |
| import com.cloud.network.as.Counter; | |
| 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.FirewallRulesCidrsDao; | |
| import com.cloud.network.dao.FirewallRulesDao; | |
| import com.cloud.network.dao.IPAddressDao; | |
| import com.cloud.network.dao.IPAddressVO; | |
| import com.cloud.network.dao.LBHealthCheckPolicyDao; | |
| import com.cloud.network.dao.LBStickinessPolicyDao; | |
| import com.cloud.network.dao.LBStickinessPolicyVO; | |
| import com.cloud.network.dao.LoadBalancerCertMapDao; | |
| import com.cloud.network.dao.LoadBalancerCertMapVO; | |
| 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.dao.NetworkServiceMapDao; | |
| import com.cloud.network.dao.NetworkVO; | |
| import com.cloud.network.dao.SslCertVO; | |
| import com.cloud.network.element.LoadBalancingServiceProvider; | |
| import com.cloud.network.lb.LoadBalancingRule.LbAutoScalePolicy; | |
| import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmGroup; | |
| import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmProfile; | |
| import com.cloud.network.lb.LoadBalancingRule.LbCondition; | |
| import com.cloud.network.lb.LoadBalancingRule.LbDestination; | |
| import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; | |
| import com.cloud.network.lb.LoadBalancingRule.LbSslCert; | |
| import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; | |
| import com.cloud.network.rules.FirewallManager; | |
| import com.cloud.network.rules.FirewallRule; | |
| import com.cloud.network.rules.FirewallRule.FirewallRuleType; | |
| import com.cloud.network.rules.FirewallRule.Purpose; | |
| import com.cloud.network.rules.FirewallRuleVO; | |
| import com.cloud.network.rules.HealthCheckPolicy; | |
| import com.cloud.network.rules.LbStickinessMethod; | |
| import com.cloud.network.rules.LbStickinessMethod.LbStickinessMethodParam; | |
| import com.cloud.network.rules.LoadBalancer; | |
| import com.cloud.network.rules.LoadBalancerContainer.Scheme; | |
| import com.cloud.network.rules.RulesManager; | |
| import com.cloud.network.rules.StickinessPolicy; | |
| import com.cloud.network.vpc.VpcManager; | |
| import com.cloud.offering.NetworkOffering; | |
| import com.cloud.projects.Project.ListProjectResourcesCriteria; | |
| import com.cloud.server.ResourceTag.ResourceObjectType; | |
| import com.cloud.service.dao.ServiceOfferingDao; | |
| import com.cloud.storage.dao.VMTemplateDao; | |
| import com.cloud.tags.ResourceTagVO; | |
| import com.cloud.tags.dao.ResourceTagDao; | |
| import com.cloud.user.Account; | |
| import com.cloud.user.AccountManager; | |
| import com.cloud.user.DomainService; | |
| 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.ManagerBase; | |
| import com.cloud.utils.db.DB; | |
| import com.cloud.utils.db.EntityManager; | |
| import com.cloud.utils.db.Filter; | |
| import com.cloud.utils.db.JoinBuilder; | |
| import com.cloud.utils.db.SearchBuilder; | |
| import com.cloud.utils.db.SearchCriteria; | |
| import com.cloud.utils.db.Transaction; | |
| import com.cloud.utils.db.TransactionCallback; | |
| import com.cloud.utils.db.TransactionCallbackNoReturn; | |
| import com.cloud.utils.db.TransactionCallbackWithException; | |
| import com.cloud.utils.db.TransactionStatus; | |
| import com.cloud.utils.exception.CloudRuntimeException; | |
| import com.cloud.utils.net.Ip; | |
| import com.cloud.utils.net.NetUtils; | |
| import com.cloud.vm.Nic; | |
| import com.cloud.vm.UserVmVO; | |
| import com.cloud.vm.VirtualMachine.State; | |
| import com.cloud.vm.dao.NicDao; | |
| import com.cloud.vm.dao.NicSecondaryIpDao; | |
| import com.cloud.vm.dao.UserVmDao; | |
| import com.google.gson.Gson; | |
| import com.google.gson.reflect.TypeToken; | |
| public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements LoadBalancingRulesManager, LoadBalancingRulesService { | |
| @Inject | |
| NetworkOrchestrationService _networkMgr; | |
| @Inject | |
| NetworkModel _networkModel; | |
| @Inject | |
| RulesManager _rulesMgr; | |
| @Inject | |
| AccountManager _accountMgr; | |
| @Inject | |
| IPAddressDao _ipAddressDao; | |
| @Inject | |
| LoadBalancerDao _lbDao; | |
| @Inject | |
| VlanDao _vlanDao; | |
| @Inject | |
| EventDao _eventDao; | |
| @Inject | |
| LoadBalancerVMMapDao _lb2VmMapDao; | |
| @Inject | |
| LBStickinessPolicyDao _lb2stickinesspoliciesDao; | |
| @Inject | |
| LBHealthCheckPolicyDao _lb2healthcheckDao; | |
| @Inject | |
| UserVmDao _vmDao; | |
| @Inject | |
| AccountDao _accountDao; | |
| @Inject | |
| DomainDao _domainDao; | |
| @Inject | |
| NicDao _nicDao; | |
| @Inject | |
| UsageEventDao _usageEventDao; | |
| @Inject | |
| FirewallRulesCidrsDao _firewallCidrsDao; | |
| @Inject | |
| FirewallManager _firewallMgr; | |
| @Inject | |
| NetworkDao _networkDao; | |
| @Inject | |
| NetworkOfferingServiceMapDao _networkOfferingServiceDao; | |
| @Inject | |
| FirewallRulesDao _firewallDao; | |
| @Inject | |
| DomainService _domainMgr; | |
| @Inject | |
| ConfigurationManager _configMgr; | |
| @Inject | |
| ExternalDeviceUsageManager _externalDeviceUsageMgr; | |
| @Inject | |
| NetworkServiceMapDao _ntwkSrvcDao; | |
| @Inject | |
| ResourceTagDao _resourceTagDao; | |
| @Inject | |
| VpcManager _vpcMgr; | |
| @Inject | |
| VMTemplateDao _templateDao; | |
| @Inject | |
| ServiceOfferingDao _offeringsDao; | |
| @Inject | |
| CounterDao _counterDao; | |
| @Inject | |
| ConditionDao _conditionDao; | |
| @Inject | |
| AutoScaleVmProfileDao _autoScaleVmProfileDao; | |
| @Inject | |
| AutoScalePolicyDao _autoScalePolicyDao; | |
| @Inject | |
| AutoScalePolicyConditionMapDao _autoScalePolicyConditionMapDao; | |
| @Inject | |
| AutoScaleVmGroupDao _autoScaleVmGroupDao; | |
| @Inject | |
| AutoScaleVmGroupPolicyMapDao _autoScaleVmGroupPolicyMapDao; | |
| @Inject | |
| AutoScaleVmGroupVmMapDao autoScaleVmGroupVmMapDao; | |
| @Inject | |
| AutoScaleManager autoScaleManager; | |
| @Inject | |
| ConfigurationDao _configDao; | |
| @Inject | |
| DataCenterDao _dcDao = null; | |
| @Inject | |
| UserDao _userDao; | |
| List<LoadBalancingServiceProvider> _lbProviders; | |
| @Inject | |
| ApplicationLoadBalancerRuleDao _appLbRuleDao; | |
| @Inject | |
| IpAddressManager _ipAddrMgr; | |
| @Inject | |
| EntityManager _entityMgr; | |
| @Inject | |
| LoadBalancerCertMapDao _lbCertMapDao; | |
| @Inject | |
| NicSecondaryIpDao _nicSecondaryIpDao; | |
| private static final int DNS_PORT = 53; | |
| // Will return a string. For LB Stickiness this will be a json, for | |
| // autoscale this will be "," separated values | |
| @Override | |
| public String getLBCapability(long networkid, String capabilityName) { | |
| Map<Service, Map<Capability, String>> serviceCapabilitiesMap = _networkModel.getNetworkCapabilities(networkid); | |
| if (serviceCapabilitiesMap != null) { | |
| for (Service service : serviceCapabilitiesMap.keySet()) { | |
| ServiceResponse serviceResponse = new ServiceResponse(); | |
| serviceResponse.setName(service.getName()); | |
| if ("Lb".equalsIgnoreCase(service.getName())) { | |
| Map<Capability, String> serviceCapabilities = serviceCapabilitiesMap.get(service); | |
| if (serviceCapabilities != null) { | |
| for (Capability capability : serviceCapabilities.keySet()) { | |
| if (capabilityName.equals(capability.getName())) { | |
| return serviceCapabilities.get(capability); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return null; | |
| } | |
| private LbAutoScaleVmGroup getLbAutoScaleVmGroup(AutoScaleVmGroupVO vmGroup, AutoScaleVmGroup.State currentState, LoadBalancerVO lb) { | |
| long lbNetworkId = lb.getNetworkId(); | |
| String lbName = lb.getName(); | |
| List<AutoScaleVmGroupPolicyMapVO> vmGroupPolicyMapList = _autoScaleVmGroupPolicyMapDao.listByVmGroupId(vmGroup.getId()); | |
| List<LbAutoScalePolicy> autoScalePolicies = new ArrayList<LbAutoScalePolicy>(); | |
| for (AutoScaleVmGroupPolicyMapVO vmGroupPolicyMap : vmGroupPolicyMapList) { | |
| AutoScalePolicy autoScalePolicy = _autoScalePolicyDao.findById(vmGroupPolicyMap.getPolicyId()); | |
| List<AutoScalePolicyConditionMapVO> autoScalePolicyConditionMapList = _autoScalePolicyConditionMapDao.listByAll(autoScalePolicy.getId(), null); | |
| List<LbCondition> lbConditions = new ArrayList<LbCondition>(); | |
| for (AutoScalePolicyConditionMapVO autoScalePolicyConditionMap : autoScalePolicyConditionMapList) { | |
| Condition condition = _conditionDao.findById(autoScalePolicyConditionMap.getConditionId()); | |
| Counter counter = _counterDao.findById(condition.getCounterId()); | |
| lbConditions.add(new LbCondition(counter, condition)); | |
| } | |
| autoScalePolicies.add(new LbAutoScalePolicy(autoScalePolicy, lbConditions)); | |
| } | |
| AutoScaleVmProfile autoScaleVmProfile = _autoScaleVmProfileDao.findById(vmGroup.getProfileId()); | |
| String zoneId = _dcDao.findById(autoScaleVmProfile.getZoneId()).getUuid(); | |
| String domainId = _domainDao.findById(autoScaleVmProfile.getDomainId()).getUuid(); | |
| String serviceOfferingId = _offeringsDao.findById(autoScaleVmProfile.getServiceOfferingId()).getUuid(); | |
| String templateId = _templateDao.findById(autoScaleVmProfile.getTemplateId()).getUuid(); | |
| String vmName = "AutoScale-LB-" + lbName; | |
| String lbNetworkUuid = null; | |
| DataCenter zone = _entityMgr.findById(DataCenter.class, vmGroup.getZoneId()); | |
| if (zone == null) { | |
| // This should never happen, but still a cautious check | |
| logger.warn("Unable to find zone while packaging AutoScale Vm Group, zoneid: " + vmGroup.getZoneId()); | |
| throw new InvalidParameterValueException("Unable to find zone"); | |
| } else { | |
| if (zone.getNetworkType() == NetworkType.Advanced) { | |
| NetworkVO lbNetwork = _networkDao.findById(lbNetworkId); | |
| lbNetworkUuid = lbNetwork.getUuid(); | |
| } | |
| } | |
| String apiKey = null; | |
| String secretKey = null; | |
| String csUrl = ApiServiceConfiguration.ApiServletPath.value(); | |
| Network.Provider provider = getLoadBalancerServiceProvider(lb); | |
| if (Network.Provider.Netscaler.equals(provider)) { | |
| Long autoscaleUserId = autoScaleVmProfile.getAutoScaleUserId(); | |
| if (autoscaleUserId == null) { | |
| throw new InvalidParameterValueException("autoscaleUserId is required but not specified"); | |
| } | |
| User user = _userDao.findById(autoscaleUserId); | |
| if (user == null) { | |
| throw new InvalidParameterValueException("Unable to find user by id " + autoscaleUserId); | |
| } | |
| apiKey = user.getApiKey(); | |
| secretKey = user.getSecretKey(); | |
| 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(String.format("Global setting %s has to be set to the Management Server's API end point", ApiServiceConfiguration.ApiServletPath.key())); | |
| } | |
| } | |
| LbAutoScaleVmProfile lbAutoScaleVmProfile = | |
| new LbAutoScaleVmProfile(autoScaleVmProfile, apiKey, secretKey, csUrl, zoneId, domainId, serviceOfferingId, templateId, vmName, lbNetworkUuid); | |
| return new LbAutoScaleVmGroup(vmGroup, autoScalePolicies, lbAutoScaleVmProfile, currentState); | |
| } | |
| @Override | |
| public LoadBalancerTO.AutoScaleVmGroupTO toAutoScaleVmGroupTO(LbAutoScaleVmGroup lbAutoScaleVmGroup) { | |
| List<LbAutoScalePolicy> lbAutoScalePolicies = lbAutoScaleVmGroup.getPolicies(); | |
| List<LoadBalancerTO.AutoScalePolicyTO> autoScalePolicyTOs = new ArrayList<>(lbAutoScalePolicies.size()); | |
| for (LbAutoScalePolicy lbAutoScalePolicy : lbAutoScalePolicies) { | |
| List<LbCondition> lbConditions = lbAutoScalePolicy.getConditions(); | |
| List<LoadBalancerTO.ConditionTO> conditionTOs = new ArrayList<>(lbConditions.size()); | |
| for (LbCondition lbCondition : lbConditions) { | |
| Counter counter = lbCondition.getCounter(); | |
| LoadBalancerTO.CounterTO counterTO = new LoadBalancerTO.CounterTO(counter.getId(), counter.getUuid(), counter.getName(), counter.getSource(), "" + counter.getValue(), counter.getProvider()); | |
| Condition condition = lbCondition.getCondition(); | |
| LoadBalancerTO.ConditionTO conditionTO = new LoadBalancerTO.ConditionTO(condition.getId(), condition.getUuid(), condition.getThreshold(), condition.getRelationalOperator(), counterTO); | |
| conditionTOs.add(conditionTO); | |
| } | |
| AutoScalePolicy autoScalePolicy = lbAutoScalePolicy.getPolicy(); | |
| autoScalePolicyTOs.add(new LoadBalancerTO.AutoScalePolicyTO(autoScalePolicy.getId(), autoScalePolicy.getUuid(), autoScalePolicy.getDuration(), autoScalePolicy.getQuietTime(), | |
| autoScalePolicy.getLastQuietTime(), autoScalePolicy.getAction(), conditionTOs, lbAutoScalePolicy.isRevoked())); | |
| } | |
| LbAutoScaleVmProfile lbAutoScaleVmProfile = lbAutoScaleVmGroup.getProfile(); | |
| AutoScaleVmProfile autoScaleVmProfile = lbAutoScaleVmProfile.getProfile(); | |
| LoadBalancerTO.AutoScaleVmProfileTO autoScaleVmProfileTO = | |
| new LoadBalancerTO.AutoScaleVmProfileTO(lbAutoScaleVmProfile.getZoneId(), lbAutoScaleVmProfile.getDomainId(), lbAutoScaleVmProfile.getCsUrl(), | |
| lbAutoScaleVmProfile.getAutoScaleUserApiKey(), lbAutoScaleVmProfile.getAutoScaleUserSecretKey(), lbAutoScaleVmProfile.getServiceOfferingId(), | |
| lbAutoScaleVmProfile.getTemplateId(), lbAutoScaleVmProfile.getVmName(), lbAutoScaleVmProfile.getNetworkId(), autoScaleVmProfile.getOtherDeployParams(), | |
| autoScaleVmProfile.getCounterParams(), autoScaleVmProfile.getExpungeVmGracePeriod()); | |
| AutoScaleVmGroup autoScaleVmGroup = lbAutoScaleVmGroup.getVmGroup(); | |
| return | |
| new LoadBalancerTO.AutoScaleVmGroupTO(autoScaleVmGroup.getId(), autoScaleVmGroup.getUuid(), autoScaleVmGroup.getMinMembers(), autoScaleVmGroup.getMaxMembers(), autoScaleVmGroup.getMemberPort(), | |
| autoScaleVmGroup.getInterval(), autoScalePolicyTOs, autoScaleVmProfileTO, autoScaleVmGroup.getState(), lbAutoScaleVmGroup.getCurrentState(), autoScaleVmGroup.getLoadBalancerId()); | |
| } | |
| @Override | |
| public LoadBalancerTO.AutoScaleVmGroupTO toAutoScaleVmGroupTO(AutoScaleVmGroupVO vmGroup) { | |
| final LoadBalancerVO loadBalancer = _lbDao.findById(vmGroup.getLoadBalancerId()); | |
| if (loadBalancer == null) { | |
| throw new CloudRuntimeException("Unable to find load balancer with id: " + vmGroup.getLoadBalancerId()); | |
| } | |
| LbAutoScaleVmGroup lbAutoScaleVmGroup = getLbAutoScaleVmGroup(vmGroup, vmGroup.getState(), loadBalancer); | |
| return toAutoScaleVmGroupTO(lbAutoScaleVmGroup); | |
| } | |
| @Override | |
| public Network.Provider getLoadBalancerServiceProvider(LoadBalancerVO loadBalancer) { | |
| Network network = _networkDao.findById(loadBalancer.getNetworkId()); | |
| List<Network.Provider> providers = _networkMgr.getProvidersForServiceInNetwork(network, Network.Service.Lb); | |
| if (CollectionUtils.isEmpty(providers)) { | |
| throw new CloudRuntimeException(String.format("Unable to find LB provider for network: %s ", network)); | |
| } | |
| return providers.get(0); | |
| } | |
| private boolean applyAutoScaleConfig(LoadBalancerVO lb, AutoScaleVmGroupVO vmGroup, AutoScaleVmGroup.State currentState) throws ResourceUnavailableException { | |
| LbAutoScaleVmGroup lbAutoScaleVmGroup = getLbAutoScaleVmGroup(vmGroup, currentState, lb); | |
| /* | |
| * Regular config like destinations need not be packed for applying | |
| * autoscale config as of today. | |
| */ | |
| List<LbStickinessPolicy> policyList = getStickinessPolicies(lb.getId()); | |
| Ip sourceIp = getSourceIp(lb); | |
| LoadBalancingRule rule = new LoadBalancingRule(lb, null, policyList, null, sourceIp, null, lb.getLbProtocol()); | |
| rule.setAutoScaleVmGroup(lbAutoScaleVmGroup); | |
| if (!isRollBackAllowedForProvider(lb)) { | |
| // this is for Netscaler type of devices. if their is failure the db | |
| // entries will be rollbacked. | |
| return false; | |
| } | |
| List<LoadBalancingRule> rules = Arrays.asList(rule); | |
| if (!applyLbRules(new ArrayList<>(rules), false)) { | |
| logger.debug("LB rules' autoscale config are not completely applied"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| private Ip getSourceIp(LoadBalancer lb) { | |
| Ip sourceIp = null; | |
| if (lb.getScheme() == Scheme.Public) { | |
| sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); | |
| } else if (lb.getScheme() == Scheme.Internal) { | |
| ApplicationLoadBalancerRuleVO appLbRule = _appLbRuleDao.findById(lb.getId()); | |
| sourceIp = appLbRule.getSourceIp(); | |
| } | |
| return sourceIp; | |
| } | |
| @Override | |
| @DB | |
| public boolean configureLbAutoScaleVmGroup(final long vmGroupid, AutoScaleVmGroup.State currentState) throws ResourceUnavailableException { | |
| final AutoScaleVmGroupVO vmGroup = _autoScaleVmGroupDao.findById(vmGroupid); | |
| boolean success = false; | |
| final LoadBalancerVO loadBalancer = _lbDao.findById(vmGroup.getLoadBalancerId()); | |
| FirewallRule.State backupState = loadBalancer.getState(); | |
| if (vmGroup.getState().equals(AutoScaleVmGroup.State.NEW) | |
| || (loadBalancer.getState() == FirewallRule.State.Active && vmGroup.getState().equals(AutoScaleVmGroup.State.REVOKE))) { | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| } | |
| try { | |
| success = applyAutoScaleConfig(loadBalancer, vmGroup, currentState); | |
| } catch (ResourceUnavailableException e) { | |
| logger.warn("Unable to configure AutoScaleVmGroup to the lb rule: {} because resource is unavailable:", loadBalancer, e); | |
| if (isRollBackAllowedForProvider(loadBalancer)) { | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| logger.debug("LB Rollback rule: {} lb state rollback while creating AutoscaleVmGroup", loadBalancer); | |
| } | |
| throw e; | |
| } finally { | |
| if (!success) { | |
| logger.warn(String.format("Failed to configure LB Auto Scale Vm Group: %s", vmGroup)); | |
| } | |
| } | |
| if (success) { | |
| if (vmGroup.getState().equals(AutoScaleVmGroup.State.NEW)) { | |
| Transaction.execute(new TransactionCallbackNoReturn() { | |
| @Override | |
| public void doInTransactionWithoutResult(TransactionStatus status) { | |
| loadBalancer.setState(FirewallRule.State.Active); | |
| logger.debug("LB rule {} state is set to Active", loadBalancer); | |
| _lbDao.persist(loadBalancer); | |
| vmGroup.setState(AutoScaleVmGroup.State.ENABLED); | |
| _autoScaleVmGroupDao.persist(vmGroup); | |
| logger.debug("LB Auto Scale Vm Group: {} is set to Enabled state.", vmGroup); | |
| } | |
| }); | |
| } | |
| logger.info("Successfully configured LB Autoscale Vm Group: {}", vmGroup); | |
| } | |
| return success; | |
| } | |
| private boolean validateHealthCheck(CreateLBHealthCheckPolicyCmd cmd) { | |
| LoadBalancerVO loadBalancer = _lbDao.findById(cmd.getLbRuleId()); | |
| String capability = getLBCapability(loadBalancer.getNetworkId(), Capability.HealthCheckPolicy.getName()); | |
| if (capability != null) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| private boolean genericValidator(CreateLBStickinessPolicyCmd cmd) throws InvalidParameterValueException { | |
| LoadBalancerVO loadBalancer = _lbDao.findById(cmd.getLbRuleId()); | |
| /* Validation : check for valid Method name and params */ | |
| List<LbStickinessMethod> stickinessMethodList = getStickinessMethods(loadBalancer.getNetworkId()); | |
| boolean methodMatch = false; | |
| if (stickinessMethodList == null) { | |
| throw new InvalidParameterValueException("Failed: No Stickiness method available for LB rule:" + cmd.getLbRuleId()); | |
| } | |
| for (LbStickinessMethod method : stickinessMethodList) { | |
| if (method.getMethodName().equalsIgnoreCase(cmd.getStickinessMethodName())) { | |
| methodMatch = true; | |
| Map apiParamList = cmd.getparamList(); | |
| List<LbStickinessMethodParam> methodParamList = method.getParamList(); | |
| Map<String, String> tempParamList = new HashMap<String, String>(); | |
| /* | |
| * validation-1: check for any extra params that are not | |
| * required by the policymethod(capability), FIXME: make the | |
| * below loop simple without using raw data type | |
| */ | |
| if (apiParamList != null) { | |
| Collection userGroupCollection = apiParamList.values(); | |
| Iterator iter = userGroupCollection.iterator(); | |
| while (iter.hasNext()) { | |
| HashMap<String, String> paramKVpair = (HashMap)iter.next(); | |
| String paramName = paramKVpair.get("name"); | |
| String paramValue = paramKVpair.get("value"); | |
| tempParamList.put(paramName, paramValue); | |
| Boolean found = false; | |
| for (LbStickinessMethodParam param : methodParamList) { | |
| if (param.getParamName().equalsIgnoreCase(paramName)) { | |
| if ((param.getIsflag() == false) && (paramValue == null)) { | |
| throw new InvalidParameterValueException("Failed : Value expected for the Param :" + param.getParamName()); | |
| } | |
| found = true; | |
| break; | |
| } | |
| } | |
| if (!found) { | |
| throw new InvalidParameterValueException("Failed : Stickiness policy does not support param name :" + paramName); | |
| } | |
| } | |
| } | |
| /* validation-2: check for mandatory params */ | |
| for (LbStickinessMethodParam param : methodParamList) { | |
| if (param.getRequired()) { | |
| if (tempParamList.get(param.getParamName()) == null) { | |
| throw new InvalidParameterValueException("Failed : Missing Manadatory Param :" + param.getParamName()); | |
| } | |
| } | |
| } | |
| /* Successfully completed the Validation */ | |
| break; | |
| } | |
| } | |
| if (methodMatch == false) { | |
| throw new InvalidParameterValueException("Failed to match Stickiness method name for LB rule:" + cmd.getLbRuleId()); | |
| } | |
| /* Validation : check for the multiple policies to the rule id */ | |
| List<LBStickinessPolicyVO> stickinessPolicies = _lb2stickinesspoliciesDao.listByLoadBalancerId(cmd.getLbRuleId(), false); | |
| if (stickinessPolicies.size() > 1) { | |
| throw new InvalidParameterValueException("Failed to create Stickiness policy: Already two policies attached " + cmd.getLbRuleId()); | |
| } | |
| return true; | |
| } | |
| @SuppressWarnings("rawtypes") | |
| @Override | |
| @DB | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_STICKINESSPOLICY_CREATE, eventDescription = "create lb stickinesspolicy to load balancer", create = true) | |
| public StickinessPolicy createLBStickinessPolicy(CreateLBStickinessPolicyCmd cmd) throws NetworkRuleConflictException { | |
| CallContext caller = CallContext.current(); | |
| /* Validation : check corresponding load balancer rule exist */ | |
| LoadBalancerVO loadBalancer = _lbDao.findById(cmd.getLbRuleId()); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException("Failed: LB rule id: " + cmd.getLbRuleId() + " not present "); | |
| } | |
| _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); | |
| if (loadBalancer.getState() == FirewallRule.State.Revoke) { | |
| throw new InvalidParameterValueException(String.format("Failed: LB rule: %s is in deleting state: ", loadBalancer)); | |
| } | |
| /* Generic validations */ | |
| if (!genericValidator(cmd)) { | |
| throw new InvalidParameterValueException(String.format("Failed to create Stickiness policy: Validation Failed %s", loadBalancer)); | |
| } | |
| /* | |
| * Specific validations using network element validator for specific | |
| * validations | |
| */ | |
| LBStickinessPolicyVO lbpolicy = | |
| new LBStickinessPolicyVO(loadBalancer.getId(), cmd.getLBStickinessPolicyName(), cmd.getStickinessMethodName(), cmd.getparamList(), cmd.getDescription()); | |
| List<LbStickinessPolicy> policyList = new ArrayList<LbStickinessPolicy>(); | |
| policyList.add(new LbStickinessPolicy(cmd.getStickinessMethodName(), lbpolicy.getParams())); | |
| Ip sourceIp = getSourceIp(loadBalancer); | |
| LoadBalancingRule lbRule = | |
| new LoadBalancingRule(loadBalancer, getExistingDestinations(lbpolicy.getId()), policyList, null, sourceIp, null, loadBalancer.getLbProtocol()); | |
| if (!validateLbRule(lbRule)) { | |
| throw new InvalidParameterValueException(String.format("Failed to create Stickiness policy: Validation Failed %s", loadBalancer)); | |
| } | |
| /* Finally Insert into DB */ | |
| LBStickinessPolicyVO policy = | |
| new LBStickinessPolicyVO(loadBalancer.getId(), cmd.getLBStickinessPolicyName(), cmd.getStickinessMethodName(), cmd.getparamList(), cmd.getDescription()); | |
| Boolean forDisplay = cmd.getDisplay(); | |
| if (forDisplay != null) { | |
| policy.setDisplay(forDisplay); | |
| } | |
| policy = _lb2stickinesspoliciesDao.persist(policy); | |
| return policy; | |
| } | |
| @Override | |
| @DB | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_HEALTHCHECKPOLICY_CREATE, eventDescription = "create load balancer health check to load balancer", create = true) | |
| public HealthCheckPolicy createLBHealthCheckPolicy(CreateLBHealthCheckPolicyCmd cmd) { | |
| CallContext caller = CallContext.current(); | |
| /* | |
| * Validation of cmd Monitor interval must be greater than response | |
| * timeout | |
| */ | |
| Map<String, String> paramMap = cmd.getFullUrlParams(); | |
| if (paramMap.containsKey(ApiConstants.HEALTHCHECK_RESPONSE_TIMEOUT) && paramMap.containsKey(ApiConstants.HEALTHCHECK_INTERVAL_TIME)) { | |
| if (cmd.getResponsTimeOut() > cmd.getHealthCheckInterval()) | |
| throw new InvalidParameterValueException("Failed to create HealthCheck policy : Monitor interval must be greater than response timeout"); | |
| } | |
| /* Validation : check corresponding load balancer rule exist */ | |
| LoadBalancerVO loadBalancer = _lbDao.findById(cmd.getLbRuleId()); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException("Failed: LB rule id: " + cmd.getLbRuleId() + " not present "); | |
| } | |
| _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); | |
| if (loadBalancer.getState() == FirewallRule.State.Revoke) { | |
| throw new InvalidParameterValueException(String.format("Failed: LB rule: %s is in deleting state: ", loadBalancer)); | |
| } | |
| /* | |
| * Validate Whether LB Provider has the capabilities to support Health | |
| * Checks | |
| */ | |
| if (!validateHealthCheck(cmd)) { | |
| throw new InvalidParameterValueException( | |
| String.format("Failed to create HealthCheck policy: Validation Failed (HealthCheck Policy is not supported by LB Provider for the LB rule:%s)", loadBalancer)); | |
| } | |
| /* Validation : check for the multiple hc policies to the rule id */ | |
| List<LBHealthCheckPolicyVO> hcPolicies = _lb2healthcheckDao.listByLoadBalancerId(cmd.getLbRuleId(), false); | |
| if (hcPolicies.size() > 0) { | |
| throw new InvalidParameterValueException(String.format("Failed to create HealthCheck policy: Already policy attached for the LB Rule:%s", loadBalancer)); | |
| } | |
| /* | |
| * Specific validations using network element validator for specific | |
| * validations | |
| */ | |
| LBHealthCheckPolicyVO hcpolicy = | |
| new LBHealthCheckPolicyVO(loadBalancer.getId(), cmd.getPingPath(), cmd.getDescription(), cmd.getResponsTimeOut(), cmd.getHealthCheckInterval(), | |
| cmd.getHealthyThreshold(), cmd.getUnhealthyThreshold()); | |
| List<LbHealthCheckPolicy> hcPolicyList = new ArrayList<LbHealthCheckPolicy>(); | |
| hcPolicyList.add(new LbHealthCheckPolicy(hcpolicy.getpingpath(), hcpolicy.getDescription(), hcpolicy.getResponseTime(), hcpolicy.getHealthcheckInterval(), | |
| hcpolicy.getHealthcheckThresshold(), hcpolicy.getUnhealthThresshold())); | |
| // Finally Insert into DB | |
| LBHealthCheckPolicyVO policy = | |
| new LBHealthCheckPolicyVO(loadBalancer.getId(), cmd.getPingPath(), cmd.getDescription(), cmd.getResponsTimeOut(), cmd.getHealthCheckInterval(), | |
| cmd.getHealthyThreshold(), cmd.getUnhealthyThreshold()); | |
| Boolean forDisplay = cmd.getDisplay(); | |
| if (forDisplay != null) { | |
| policy.setDisplay(forDisplay); | |
| } | |
| policy = _lb2healthcheckDao.persist(policy); | |
| return policy; | |
| } | |
| @Override | |
| public boolean validateLbRule(LoadBalancingRule lbRule) { | |
| Network network = _networkDao.findById(lbRule.getNetworkId()); | |
| Purpose purpose = lbRule.getPurpose(); | |
| if (purpose != Purpose.LoadBalancing) { | |
| logger.debug("Unable to validate network rules for purpose: " + purpose.toString()); | |
| return false; | |
| } | |
| for (LoadBalancingServiceProvider ne : _lbProviders) { | |
| boolean validated = ne.validateLBRule(network, lbRule); | |
| if (!validated) | |
| return false; | |
| } | |
| return true; | |
| } | |
| @Override | |
| @DB | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_STICKINESSPOLICY_CREATE, eventDescription = "Apply Stickinesspolicy to load balancer ", async = true) | |
| public boolean applyLBStickinessPolicy(CreateLBStickinessPolicyCmd cmd) { | |
| boolean success = true; | |
| FirewallRule.State backupState = null; | |
| long oldStickinessPolicyId = 0; | |
| LoadBalancerVO loadBalancer = _lbDao.findById(cmd.getLbRuleId()); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException("Invalid Load balancer Id:" + cmd.getLbRuleId()); | |
| } | |
| _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, loadBalancer); | |
| List<LBStickinessPolicyVO> stickinessPolicies = _lb2stickinesspoliciesDao.listByLoadBalancerId(cmd.getLbRuleId(), false); | |
| for (LBStickinessPolicyVO stickinessPolicy : stickinessPolicies) { | |
| if (stickinessPolicy.getId() == cmd.getEntityId()) { | |
| backupState = loadBalancer.getState(); | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| } else { | |
| oldStickinessPolicyId = stickinessPolicy.getId(); | |
| stickinessPolicy.setRevoke(true); | |
| _lb2stickinesspoliciesDao.persist(stickinessPolicy); | |
| } | |
| } | |
| try { | |
| applyLoadBalancerConfig(cmd.getLbRuleId()); | |
| } catch (ResourceUnavailableException e) { | |
| logger.warn("Unable to apply Stickiness policy to the lb rule: {} because resource is unavailable:", loadBalancer, e); | |
| if (isRollBackAllowedForProvider(loadBalancer)) { | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| deleteLBStickinessPolicy(cmd.getEntityId(), false); | |
| logger.debug("LB Rollback rule: {} lb state rollback while creating sticky policy", loadBalancer); | |
| } else { | |
| deleteLBStickinessPolicy(cmd.getEntityId(), false); | |
| if (oldStickinessPolicyId != 0) { | |
| LBStickinessPolicyVO stickinessPolicy = _lb2stickinesspoliciesDao.findById(oldStickinessPolicyId); | |
| stickinessPolicy.setRevoke(false); | |
| _lb2stickinesspoliciesDao.persist(stickinessPolicy); | |
| try { | |
| if (backupState.equals(FirewallRule.State.Active)) | |
| applyLoadBalancerConfig(cmd.getLbRuleId()); | |
| } catch (ResourceUnavailableException e1) { | |
| logger.info("[ignored] applying load balancer config.", e1); | |
| } finally { | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| } | |
| } | |
| } | |
| success = false; | |
| } | |
| return success; | |
| } | |
| @Override | |
| @DB | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_HEALTHCHECKPOLICY_CREATE, eventDescription = "Apply HealthCheckPolicy to load balancer ", async = true) | |
| public boolean applyLBHealthCheckPolicy(CreateLBHealthCheckPolicyCmd cmd) { | |
| boolean success = true; | |
| LoadBalancerVO loadBalancer = _lbDao.findById(cmd.getLbRuleId()); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException("Invalid Load balancer Id:" + cmd.getLbRuleId()); | |
| } | |
| _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, loadBalancer); | |
| FirewallRule.State backupState = loadBalancer.getState(); | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| try { | |
| applyLoadBalancerConfig(cmd.getLbRuleId()); | |
| } catch (ResourceUnavailableException e) { | |
| logger.warn("Unable to apply healthcheck policy to the lb rule: {} because resource is unavailable:", loadBalancer, e); | |
| if (isRollBackAllowedForProvider(loadBalancer)) { | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| logger.debug("LB Rollback rule: {} lb state rollback while creating healthcheck policy", loadBalancer); | |
| } | |
| deleteLBHealthCheckPolicy(cmd.getEntityId(), false); | |
| success = false; | |
| } | |
| return success; | |
| } | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_STICKINESSPOLICY_DELETE, eventDescription = "revoking LB Stickiness policy ", async = true) | |
| public boolean deleteLBStickinessPolicy(long stickinessPolicyId, boolean apply) { | |
| boolean success = true; | |
| CallContext caller = CallContext.current(); | |
| LBStickinessPolicyVO stickinessPolicy = _lb2stickinesspoliciesDao.findById(stickinessPolicyId); | |
| if (stickinessPolicy == null) { | |
| throw new InvalidParameterValueException("Invalid Stickiness policy id value: " + stickinessPolicyId); | |
| } | |
| LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(stickinessPolicy.getLoadBalancerId())); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException(String.format("Invalid Load balancer: %d for Stickiness policy: %s", | |
| stickinessPolicy.getLoadBalancerId(), stickinessPolicy)); | |
| } | |
| long loadBalancerId = loadBalancer.getId(); | |
| FirewallRule.State backupState = loadBalancer.getState(); | |
| _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); | |
| if (apply) { | |
| if (loadBalancer.getState() == FirewallRule.State.Active) { | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| } | |
| boolean backupStickyState = stickinessPolicy.isRevoke(); | |
| stickinessPolicy.setRevoke(true); | |
| _lb2stickinesspoliciesDao.persist(stickinessPolicy); | |
| logger.debug("Set load balancer rule for revoke: rule {}, stickinesspolicy {}", loadBalancer, stickinessPolicy); | |
| try { | |
| if (!applyLoadBalancerConfig(loadBalancerId)) { | |
| String error = String.format("Failed to remove load balancer rule %s for stickinesspolicy %s", loadBalancer, stickinessPolicy); | |
| logger.warn(error); | |
| throw new CloudRuntimeException(error); | |
| } | |
| } catch (ResourceUnavailableException e) { | |
| if (isRollBackAllowedForProvider(loadBalancer)) { | |
| stickinessPolicy.setRevoke(backupStickyState); | |
| _lb2stickinesspoliciesDao.persist(stickinessPolicy); | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| logger.debug("LB Rollback rule: {} while deleting sticky policy: {}", loadBalancer, stickinessPolicy); | |
| } | |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); | |
| success = false; | |
| } | |
| } else { | |
| _lb2stickinesspoliciesDao.expunge(stickinessPolicyId); | |
| } | |
| return success; | |
| } | |
| @DB | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_HEALTHCHECKPOLICY_DELETE, eventDescription = "revoking LB HealthCheck policy ", async = true) | |
| public boolean deleteLBHealthCheckPolicy(long healthCheckPolicyId, boolean apply) { | |
| boolean success = true; | |
| CallContext caller = CallContext.current(); | |
| LBHealthCheckPolicyVO healthCheckPolicy = _lb2healthcheckDao.findById(healthCheckPolicyId); | |
| if (healthCheckPolicy == null) { | |
| throw new InvalidParameterValueException("Invalid HealthCheck policy id value: " + healthCheckPolicyId); | |
| } | |
| LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(healthCheckPolicy.getLoadBalancerId())); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException(String.format("Invalid Load balancer: %d for HealthCheck policy: %s", healthCheckPolicy.getLoadBalancerId(), healthCheckPolicy)); | |
| } | |
| final long loadBalancerId = loadBalancer.getId(); | |
| FirewallRule.State backupState = loadBalancer.getState(); | |
| _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); | |
| if (apply) { | |
| if (loadBalancer.getState() == FirewallRule.State.Active) { | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| } | |
| boolean backupStickyState = healthCheckPolicy.isRevoke(); | |
| healthCheckPolicy.setRevoke(true); | |
| _lb2healthcheckDao.persist(healthCheckPolicy); | |
| logger.debug("Set health check policy to revoke for loadbalancing rule : {}, healthCheckpolicy {}", loadBalancer, healthCheckPolicy); | |
| // removing the state of services set by the monitor. | |
| final List<LoadBalancerVMMapVO> maps = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId); | |
| if (maps != null) { | |
| Transaction.execute(new TransactionCallbackNoReturn() { | |
| @Override | |
| public void doInTransactionWithoutResult(TransactionStatus status) { | |
| logger.debug("Resetting health state policy for services in loadbalancing rule: {}", loadBalancer); | |
| for (LoadBalancerVMMapVO map : maps) { | |
| map.setState(null); | |
| _lb2VmMapDao.persist(map); | |
| } | |
| } | |
| }); | |
| } | |
| try { | |
| if (!applyLoadBalancerConfig(loadBalancerId)) { | |
| String error = String.format("Failed to remove load balancer rule %s for healthCheckpolicy %s", loadBalancer, healthCheckPolicy); | |
| logger.warn(error); | |
| throw new CloudRuntimeException(error); | |
| } | |
| } catch (ResourceUnavailableException e) { | |
| if (isRollBackAllowedForProvider(loadBalancer)) { | |
| healthCheckPolicy.setRevoke(backupStickyState); | |
| _lb2healthcheckDao.persist(healthCheckPolicy); | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| logger.debug("LB Rollback rule: {} while deleting healthcheck policy: {}", loadBalancer, healthCheckPolicy); | |
| } | |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); | |
| success = false; | |
| } | |
| } else { | |
| _lb2healthcheckDao.remove(healthCheckPolicy.getLoadBalancerId()); | |
| } | |
| return success; | |
| } | |
| // This method will check the status of services which has monitors created | |
| // by CloudStack and update them in lbvmmap table | |
| @DB | |
| @Override | |
| public void updateLBHealthChecks(Scheme scheme) throws ResourceUnavailableException { | |
| List<LoadBalancerVO> rules = _lbDao.listAll(); | |
| List<NetworkVO> networks = _networkDao.listAll(); | |
| List<LoadBalancerTO> stateRules = null; | |
| boolean isHandled = false; | |
| for (NetworkVO ntwk : networks) { | |
| Network network = _networkDao.findById(ntwk.getId()); | |
| String capability = getLBCapability(network.getId(), Capability.HealthCheckPolicy.getName()); | |
| if (capability != null && capability.equalsIgnoreCase("true")) { | |
| /* | |
| * logger.debug( | |
| * "HealthCheck Manager :: LB Provider in the Network has the Healthcheck policy capability :: " | |
| * + provider.get(0).getName()); | |
| */ | |
| rules = _lbDao.listByNetworkIdAndScheme(network.getId(), scheme); | |
| if (rules != null && rules.size() > 0) { | |
| List<LoadBalancingRule> lbrules = new ArrayList<LoadBalancingRule>(); | |
| for (LoadBalancerVO lb : rules) { | |
| List<LbDestination> dstList = getExistingDestinations(lb.getId()); | |
| List<LbHealthCheckPolicy> hcPolicyList = getHealthCheckPolicies(lb.getId()); | |
| // Now retrive the status of services from NS even there are no policies. because there is default monitor | |
| Ip sourceIp = getSourceIp(lb); | |
| LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, null, hcPolicyList, sourceIp, null, lb.getLbProtocol()); | |
| lbrules.add(loadBalancing); | |
| } | |
| if (lbrules.size() > 0) { | |
| isHandled = false; | |
| for (LoadBalancingServiceProvider lbElement : _lbProviders) { | |
| stateRules = lbElement.updateHealthChecks(network, lbrules); | |
| if (stateRules != null && stateRules.size() > 0) { | |
| for (LoadBalancerTO lbto : stateRules) { | |
| LoadBalancerVO ulb = _lbDao.findByUuid(lbto.getUuid()); | |
| List<LoadBalancerVMMapVO> lbVmMaps = _lb2VmMapDao.listByLoadBalancerId(ulb.getId()); | |
| for (LoadBalancerVMMapVO lbVmMap : lbVmMaps) { | |
| UserVm vm = _vmDao.findById(lbVmMap.getInstanceId()); | |
| Nic nic = _nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(ulb.getNetworkId(), vm.getId()); | |
| String dstIp = lbVmMap.getInstanceIp() == null ? nic.getIPv4Address(): lbVmMap.getInstanceIp(); | |
| for (int i = 0; i < lbto.getDestinations().length; i++) { | |
| LoadBalancerTO.DestinationTO des = lbto.getDestinations()[i]; | |
| if (dstIp.equalsIgnoreCase(lbto.getDestinations()[i].getDestIp())) { | |
| lbVmMap.setState(des.getMonitorState()); | |
| _lb2VmMapDao.persist(lbVmMap); | |
| logger.debug("Updating the LB VM Map table with the service state"); | |
| } | |
| } | |
| } | |
| } | |
| isHandled = true; | |
| } | |
| if (isHandled) { | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } else { | |
| // logger.debug("HealthCheck Manager :: LB Provider in the Network DNOT the Healthcheck policy capability "); | |
| } | |
| } | |
| } | |
| private boolean isRollBackAllowedForProvider(LoadBalancerVO loadBalancer) { | |
| Network network = _networkDao.findById(loadBalancer.getNetworkId()); | |
| List<Provider> provider = _networkMgr.getProvidersForServiceInNetwork(network, Service.Lb); | |
| if (provider == null || provider.size() == 0) { | |
| return false; | |
| } | |
| if (provider.get(0) == Provider.Netscaler || provider.get(0) == Provider.F5BigIp || | |
| provider.get(0) == Provider.VirtualRouter || provider.get(0) == Provider.VPCVirtualRouter) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| @Override | |
| @DB | |
| @ActionEvent(eventType = EventTypes.EVENT_ASSIGN_TO_LOAD_BALANCER_RULE, eventDescription = "assigning to load balancer", async = true) | |
| public boolean assignToLoadBalancer(long loadBalancerId, List<Long> instanceIds, Map<Long, List<String>> vmIdIpMap, boolean isAutoScaleVM) { | |
| CallContext ctx = CallContext.current(); | |
| Account caller = ctx.getCallingAccount(); | |
| final LoadBalancerVO loadBalancer = _lbDao.findById(loadBalancerId); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException("Failed to assign to load balancer " + loadBalancerId + ", the load balancer was not found."); | |
| } | |
| if (!isAutoScaleVM && _autoScaleVmGroupDao.isAutoScaleLoadBalancer(loadBalancerId)) { | |
| throw new InvalidParameterValueException(String.format("Failed to assign to load balancer %s because it is being used by an Autoscale VM group.", loadBalancer)); | |
| } | |
| if (instanceIds == null && vmIdIpMap.isEmpty()) { | |
| throw new InvalidParameterValueException("Both instanceids and vmidipmap can't be null"); | |
| } | |
| // instanceIds and vmIdipmap is passed | |
| if (instanceIds != null && !vmIdIpMap.isEmpty()) { | |
| for(long instanceId: instanceIds) { | |
| if (!vmIdIpMap.containsKey(instanceId)) { | |
| vmIdIpMap.put(instanceId, null); | |
| } | |
| } | |
| } | |
| //only instanceids list passed | |
| if (instanceIds != null && vmIdIpMap.isEmpty()){ | |
| vmIdIpMap = new HashMap<Long, List<String>>(); | |
| for (long instanceId: instanceIds){ | |
| vmIdIpMap.put(instanceId, null); | |
| } | |
| } | |
| List<LoadBalancerVMMapVO> mappedInstances = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId, false); | |
| Set<Long> mappedInstanceIds = new HashSet<Long>(); | |
| for (LoadBalancerVMMapVO mappedInstance : mappedInstances) { | |
| mappedInstanceIds.add(Long.valueOf(mappedInstance.getInstanceId())); | |
| } | |
| Map<Long, List<String>> existingVmIdIps = new HashMap<Long, List<String>>(); | |
| // now get the ips of vm and add it to map | |
| for (LoadBalancerVMMapVO mappedInstance : mappedInstances) { | |
| List<String> ipsList = null; | |
| if (existingVmIdIps.containsKey(mappedInstance.getInstanceId())) { | |
| ipsList = existingVmIdIps.get(mappedInstance.getInstanceId()); | |
| } else { | |
| ipsList = new ArrayList<String>(); | |
| } | |
| ipsList.add(mappedInstance.getInstanceIp()); | |
| existingVmIdIps.put(mappedInstance.getInstanceId(), ipsList); | |
| } | |
| final List<UserVm> vmsToAdd = new ArrayList<UserVm>(); | |
| // check for conflict | |
| Set<Long> passedInstanceIds = vmIdIpMap.keySet(); | |
| for (Long instanceId : passedInstanceIds) { | |
| UserVm vm = _vmDao.findById(instanceId); | |
| if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging) { | |
| InvalidParameterValueException ex = new InvalidParameterValueException("Invalid instance id specified"); | |
| if (vm == null) { | |
| ex.addProxyObject(instanceId.toString(), "instanceId"); | |
| } else { | |
| ex.addProxyObject(vm.getUuid(), "instanceId"); | |
| } | |
| throw ex; | |
| } | |
| _rulesMgr.checkRuleAndUserVm(loadBalancer, vm, caller); | |
| Account vmOwner = _accountDao.findById(vm.getAccountId()); | |
| Network network = _networkDao.findById(loadBalancer.getNetworkId()); | |
| _accountMgr.checkAccess(vmOwner, SecurityChecker.AccessType.UseEntry, false, network); | |
| // Let's check to make sure the vm has a nic in the same network as | |
| // the load balancing rule. | |
| List<? extends Nic> nics = _networkModel.getNics(vm.getId()); | |
| Nic nicInSameNetwork = null; | |
| for (Nic nic : nics) { | |
| if (nic.getNetworkId() == loadBalancer.getNetworkId()) { | |
| nicInSameNetwork = nic; | |
| break; | |
| } | |
| } | |
| if (nicInSameNetwork == null) { | |
| InvalidParameterValueException ex = | |
| new InvalidParameterValueException("VM with id specified cannot be added because it doesn't belong in the same network."); | |
| ex.addProxyObject(vm.getUuid(), "instanceId"); | |
| throw ex; | |
| } | |
| String priIp = nicInSameNetwork.getIPv4Address(); | |
| if (existingVmIdIps.containsKey(instanceId)) { | |
| // now check for ip address | |
| List<String> mappedIps = existingVmIdIps.get(instanceId); | |
| List<String> newIps = vmIdIpMap.get(instanceId); | |
| if (newIps == null) { | |
| newIps = new ArrayList<String>(); | |
| newIps.add(priIp); | |
| } | |
| for (String newIp: newIps) { | |
| if (mappedIps.contains(newIp)) { | |
| throw new InvalidParameterValueException("VM " + instanceId + " with " + newIp +" is already mapped to load balancer."); | |
| } | |
| } | |
| } | |
| List<String> vmIpsList = vmIdIpMap.get(instanceId); | |
| String vmLbIp = null; | |
| if (vmIpsList != null) { | |
| //check if the ips belongs to nic secondary ip | |
| for (String ip: vmIpsList) { | |
| // skip the primary ip from vm secondary ip comparisions | |
| if (ip.equals(priIp)) { | |
| continue; | |
| } | |
| if(_nicSecondaryIpDao.findByIp4AddressAndNicId(ip,nicInSameNetwork.getId()) == null) { | |
| throw new InvalidParameterValueException("VM ip "+ ip + " specified does not belong to " + | |
| "nic in network " + nicInSameNetwork.getNetworkId()); | |
| } | |
| } | |
| } else { | |
| vmIpsList = new ArrayList<String>(); | |
| vmIpsList.add(priIp); | |
| } | |
| // when vm id is passed in instance ids and in vmidipmap | |
| // assign for primary ip and ip passed in vmidipmap | |
| if (instanceIds != null ) { | |
| if (instanceIds.contains(instanceId)) { | |
| vmIpsList.add(priIp); | |
| } | |
| } | |
| vmIdIpMap.put(instanceId, vmIpsList); | |
| if (logger.isDebugEnabled()) { | |
| logger.debug("Adding " + vm + " to the load balancer pool"); | |
| } | |
| vmsToAdd.add(vm); | |
| } | |
| final Set<Long> vmIds = vmIdIpMap.keySet(); | |
| final Map<Long, List<String>> newMap = vmIdIpMap; | |
| Transaction.execute(new TransactionCallbackNoReturn() { | |
| @Override | |
| public void doInTransactionWithoutResult(TransactionStatus status) { | |
| for (Long vmId : vmIds) { | |
| final Set<String> lbVmIps = new HashSet<String>(newMap.get(vmId)); | |
| for (String vmIp: lbVmIps) { | |
| LoadBalancerVMMapVO map = new LoadBalancerVMMapVO(loadBalancer.getId(), vmId, vmIp, false); | |
| map = _lb2VmMapDao.persist(map); | |
| } | |
| } | |
| } | |
| }); | |
| if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(loadBalancerId)) { | |
| Network.Provider provider = getLoadBalancerServiceProvider(loadBalancer); | |
| if (Network.Provider.Netscaler.equals(provider)) { | |
| // For netscaler autoscale loadbalancer, the rules need not be applied, | |
| // meaning the call need not reach the resource layer. | |
| // We can consider the job done. | |
| return true; | |
| } | |
| } | |
| boolean success = false; | |
| FirewallRule.State backupState = loadBalancer.getState(); | |
| try { | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| applyLoadBalancerConfig(loadBalancerId); | |
| success = true; | |
| } catch (ResourceUnavailableException e) { | |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); | |
| success = false; | |
| } finally { | |
| if (!success) { | |
| final List<Long> vmInstanceIds = new ArrayList<Long>(); | |
| Transaction.execute(new TransactionCallbackNoReturn() { | |
| @Override | |
| public void doInTransactionWithoutResult(TransactionStatus status) { | |
| for (Long vmId : vmIds) { | |
| vmInstanceIds.add(vmId); | |
| } | |
| } | |
| }); | |
| if (!vmInstanceIds.isEmpty()) { | |
| _lb2VmMapDao.remove(loadBalancer.getId(), vmInstanceIds, null); | |
| logger.debug("LB Rollback rule: {} while attaching VM: {}", loadBalancer, vmInstanceIds); | |
| } | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| CloudRuntimeException ex = new CloudRuntimeException("Failed to add specified loadbalancerruleid for vms " | |
| + vmInstanceIds); | |
| ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId"); | |
| // TBD: Also pack in the instanceIds in the exception using the | |
| // right VO object or table name. | |
| throw ex; | |
| } | |
| } | |
| return success; | |
| } | |
| @Override | |
| public boolean assignSSLCertToLoadBalancerRule(Long lbId, String certName, String publicCert, String privateKey) { | |
| logger.error("Calling the manager for LB"); | |
| LoadBalancerVO loadBalancer = _lbDao.findById(lbId); | |
| return false; //TODO | |
| } | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_REMOVE_FROM_LOAD_BALANCER_RULE, eventDescription = "removing from load balancer", async = true) | |
| public boolean removeFromLoadBalancer(long loadBalancerId, List<Long> instanceIds, Map<Long, List<String>> vmIdIpsMap, boolean isAutoScaleVM) { | |
| return removeFromLoadBalancerInternal(loadBalancerId, instanceIds, true, vmIdIpsMap, isAutoScaleVM); | |
| } | |
| @Override | |
| public LbSslCert getLbSslCert(long lbRuleId) { | |
| LoadBalancerCertMapVO lbCertMap = _lbCertMapDao.findByLbRuleId(lbRuleId); | |
| if (lbCertMap == null) | |
| return null; | |
| SslCertVO certVO = _entityMgr.findById(SslCertVO.class, lbCertMap.getCertId()); | |
| if (certVO == null) { | |
| logger.warn("Cert rule with cert ID " + lbCertMap.getCertId() + " but Cert is not found"); | |
| return null; | |
| } | |
| return new LbSslCert(certVO.getCertificate(), certVO.getKey(), certVO.getPassword(), certVO.getChain(), certVO.getFingerPrint(), lbCertMap.isRevoke()); | |
| } | |
| @Override | |
| @DB | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_CERT_ASSIGN, eventDescription = "assigning certificate to load balancer", async = true) | |
| public boolean assignCertToLoadBalancer(long lbRuleId, Long certId) { | |
| CallContext caller = CallContext.current(); | |
| LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(lbRuleId)); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException("Invalid load balancer id: " + lbRuleId); | |
| } | |
| SslCertVO certVO = _entityMgr.findById(SslCertVO.class, certId); | |
| if (certVO == null) { | |
| throw new InvalidParameterValueException("Invalid certificate id: " + certId); | |
| } | |
| _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); | |
| // check if LB and Cert belong to the same account | |
| if (loadBalancer.getAccountId() != certVO.getAccountId()) { | |
| throw new InvalidParameterValueException("Access denied for account " + certVO.getAccountId()); | |
| } | |
| String capability = getLBCapability(loadBalancer.getNetworkId(), Capability.SslTermination.getName()); | |
| if (capability == null) { | |
| throw new InvalidParameterValueException("Ssl termination not supported by the loadbalancer"); | |
| } | |
| //check if the lb is already bound | |
| LoadBalancerCertMapVO certMapRule = _lbCertMapDao.findByLbRuleId(loadBalancer.getId()); | |
| if (certMapRule != null) | |
| throw new InvalidParameterValueException("Another certificate is already bound to the LB"); | |
| //check for correct port | |
| if (loadBalancer.getLbProtocol() == null || !(loadBalancer.getLbProtocol().equals(NetUtils.SSL_PROTO))) | |
| throw new InvalidParameterValueException("Bad LB protocol: Expected ssl got " + loadBalancer.getLbProtocol()); | |
| boolean success = false; | |
| FirewallRule.State backupState = loadBalancer.getState(); | |
| try { | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| LoadBalancerCertMapVO certMap = new LoadBalancerCertMapVO(lbRuleId, certId, false); | |
| _lbCertMapDao.persist(certMap); | |
| applyLoadBalancerConfig(loadBalancer.getId()); | |
| success = true; | |
| } catch (ResourceUnavailableException e) { | |
| if (isRollBackAllowedForProvider(loadBalancer)) { | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| LoadBalancerCertMapVO certMap = _lbCertMapDao.findByLbRuleId(lbRuleId); | |
| _lbCertMapDao.remove(certMap.getId()); | |
| logger.debug("LB Rollback rule: {} while adding cert", loadBalancer); | |
| } | |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); | |
| } | |
| return success; | |
| } | |
| @Override | |
| @DB | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_CERT_REMOVE, eventDescription = "removing certificate from load balancer", async = true) | |
| public boolean removeCertFromLoadBalancer(long lbRuleId) { | |
| CallContext caller = CallContext.current(); | |
| LoadBalancerVO loadBalancer = _lbDao.findById(lbRuleId); | |
| LoadBalancerCertMapVO lbCertMap = _lbCertMapDao.findByLbRuleId(lbRuleId); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException("Invalid load balancer value: " + lbRuleId); | |
| } | |
| if (lbCertMap == null) { | |
| throw new InvalidParameterValueException("No certificate is bound to lb with id: " + lbRuleId); | |
| } | |
| _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); | |
| boolean success = false; | |
| FirewallRule.State backupState = loadBalancer.getState(); | |
| try { | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| lbCertMap.setRevoke(true); | |
| _lbCertMapDao.persist(lbCertMap); | |
| if (!applyLoadBalancerConfig(lbRuleId)) { | |
| logger.warn("Failed to remove cert from load balancer rule {}", loadBalancer); | |
| CloudRuntimeException ex = new CloudRuntimeException(String.format("Failed to remove certificate load balancer rule %s", loadBalancer)); | |
| ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId"); | |
| throw ex; | |
| } | |
| success = true; | |
| } catch (ResourceUnavailableException e) { | |
| if (isRollBackAllowedForProvider(loadBalancer)) { | |
| lbCertMap.setRevoke(false); | |
| _lbCertMapDao.persist(lbCertMap); | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| logger.debug(String.format("Rolled back certificate removal lb %s", loadBalancer)); | |
| } | |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); | |
| if (!success) { | |
| CloudRuntimeException ex = new CloudRuntimeException(String.format("Failed to remove certificate from load balancer rule %s", loadBalancer)); | |
| ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId"); | |
| throw ex; | |
| } | |
| } | |
| return success; | |
| } | |
| private boolean removeFromLoadBalancerInternal(long loadBalancerId, List<Long> instanceIds, boolean rollBack, Map<Long, List<String>> vmIdIpMap, boolean isAutoScaleVM) { | |
| CallContext caller = CallContext.current(); | |
| LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(loadBalancerId)); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException("Invalid load balancer value: " + loadBalancerId); | |
| } | |
| _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); | |
| if (instanceIds == null && vmIdIpMap.isEmpty()) { | |
| throw new InvalidParameterValueException("Both instanceids and vmidipmap can't be null"); | |
| } | |
| // instanceIds and vmIdipmap is passed | |
| if (instanceIds != null && !vmIdIpMap.isEmpty()) { | |
| for(long instanceId: instanceIds) { | |
| if (!vmIdIpMap.containsKey(instanceId)) { | |
| vmIdIpMap.put(instanceId, null); | |
| } | |
| } | |
| } | |
| //only instanceids list passed | |
| if (instanceIds != null && vmIdIpMap.isEmpty()){ | |
| vmIdIpMap = new HashMap<Long, List<String>>(); | |
| for (long instanceId: instanceIds){ | |
| vmIdIpMap.put(instanceId, null); | |
| } | |
| } | |
| boolean success = false; | |
| FirewallRule.State backupState = loadBalancer.getState(); | |
| Set<Long> vmIds = vmIdIpMap.keySet(); | |
| if (!isAutoScaleVM) { | |
| for (long instanceId : vmIds) { | |
| autoScaleManager.checkIfVmActionAllowed(instanceId); | |
| } | |
| } | |
| try { | |
| loadBalancer.setState(FirewallRule.State.Add); | |
| _lbDao.persist(loadBalancer); | |
| for (long instanceId : vmIds) { | |
| List<String> lbVmIps = vmIdIpMap.get(instanceId); | |
| if (lbVmIps == null || lbVmIps.isEmpty()) { | |
| List<LoadBalancerVMMapVO> lbVms = _lb2VmMapDao.listByLoadBalancerIdAndVmId(loadBalancerId, instanceId); | |
| if (lbVms == null) { | |
| throw new InvalidParameterValueException("The instance id: "+ instanceId +" is not configured " | |
| + " for LB rule id " + loadBalancerId); | |
| } | |
| for (LoadBalancerVMMapVO lbvm: lbVms) { | |
| lbvm.setRevoke(true); | |
| _lb2VmMapDao.persist(lbvm); | |
| } | |
| logger.debug("Set load balancer rule for revoke: rule {}, vm {}", loadBalancer::toString, () -> _vmDao.findById(instanceId)); | |
| } else { | |
| for (String vmIp: lbVmIps) { | |
| LoadBalancerVMMapVO map = _lb2VmMapDao.findByLoadBalancerIdAndVmIdVmIp (loadBalancerId, instanceId, vmIp); | |
| if (map == null) { | |
| throw new InvalidParameterValueException(String.format("The instance id: %d is not configured for LB rule %s", instanceId, loadBalancer)); | |
| } | |
| map.setRevoke(true); | |
| _lb2VmMapDao.persist(map); | |
| logger.debug("Set load balancer rule for revoke: rule {}, vmId {}, vmip {}", loadBalancer::toString, () -> _vmDao.findById(instanceId), vmIp::toString); | |
| } | |
| } | |
| } | |
| if (!applyLoadBalancerConfig(loadBalancerId)) { | |
| logger.warn("Failed to remove load balancer rule {} for vms {}", loadBalancer, instanceIds); | |
| CloudRuntimeException ex = new CloudRuntimeException("Failed to remove specified load balancer rule id for vms " + instanceIds); | |
| ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId"); | |
| throw ex; | |
| } | |
| if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(loadBalancerId)) { | |
| List<Long> vmIdsList = new ArrayList<>(vmIdIpMap.keySet()); | |
| _lb2VmMapDao.remove(loadBalancer.getId(), vmIdsList, null); | |
| for (Long instanceId: vmIdsList){ | |
| autoScaleVmGroupVmMapDao.removeByVm(instanceId); | |
| } | |
| } | |
| success = true; | |
| } catch (ResourceUnavailableException e) { | |
| if (rollBack && isRollBackAllowedForProvider(loadBalancer)) { | |
| for (long instanceId : vmIds) { | |
| List<String> lbVmIps = vmIdIpMap.get(instanceId); | |
| if (lbVmIps == null || lbVmIps.isEmpty()) { | |
| LoadBalancerVMMapVO map = _lb2VmMapDao.findByLoadBalancerIdAndVmId(loadBalancerId, instanceId); | |
| map.setRevoke(false); | |
| _lb2VmMapDao.persist(map); | |
| logger.debug("LB Rollback rule: {},while removing vmId {}", loadBalancer, instanceId); | |
| }else { | |
| for (String vmIp: lbVmIps) { | |
| LoadBalancerVMMapVO map = _lb2VmMapDao.findByLoadBalancerIdAndVmIdVmIp (loadBalancerId, instanceId, vmIp); | |
| map.setRevoke(true); | |
| _lb2VmMapDao.persist(map); | |
| logger.debug("LB Rollback rule: {},while removing vmId {}, vmip {}", loadBalancer, instanceId, vmIp); | |
| } | |
| } | |
| } | |
| loadBalancer.setState(backupState); | |
| _lbDao.persist(loadBalancer); | |
| logger.debug("LB Rollback rule: {} while removing vm instances", loadBalancer); | |
| } | |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); | |
| } | |
| if (!success) { | |
| CloudRuntimeException ex = new CloudRuntimeException("Failed to remove specified load balancer rule id for vms " + vmIds); | |
| ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId"); | |
| throw ex; | |
| } | |
| return success; | |
| } | |
| @Override | |
| public boolean removeVmFromLoadBalancers(long instanceId) { | |
| boolean success = true; | |
| List<LoadBalancerVMMapVO> maps = _lb2VmMapDao.listByInstanceId(instanceId); | |
| if (maps == null || maps.isEmpty()) { | |
| return true; | |
| } | |
| Map<Long, List<Long>> lbsToReconfigure = new HashMap<Long, List<Long>>(); | |
| // first set all existing lb mappings with Revoke state | |
| for (LoadBalancerVMMapVO map : maps) { | |
| long lbId = map.getLoadBalancerId(); | |
| List<Long> instances = lbsToReconfigure.get(lbId); | |
| if (instances == null) { | |
| instances = new ArrayList<Long>(); | |
| } | |
| instances.add(map.getInstanceId()); | |
| lbsToReconfigure.put(lbId, instances); | |
| map.setRevoke(true); | |
| _lb2VmMapDao.persist(map); | |
| logger.debug("Set load balancer rule for revoke: rule {}, vm {}", () -> _lbDao.findById(map.getLoadBalancerId()), () -> _vmDao.findById(instanceId)); | |
| } | |
| // Reapply all lbs that had the vm assigned | |
| if (lbsToReconfigure != null) { | |
| for (Map.Entry<Long, List<Long>> lb : lbsToReconfigure.entrySet()) { | |
| if (!removeFromLoadBalancerInternal(lb.getKey(), lb.getValue(), false, new HashMap<>(), false)) { | |
| success = false; | |
| } | |
| } | |
| } | |
| return success; | |
| } | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_DELETE, eventDescription = "deleting load balancer", async = true) | |
| public boolean deleteLoadBalancerRule(long loadBalancerId, boolean apply) { | |
| CallContext ctx = CallContext.current(); | |
| Account caller = ctx.getCallingAccount(); | |
| LoadBalancerVO rule = _lbDao.findById(loadBalancerId); | |
| if (rule == null) { | |
| throw new InvalidParameterValueException("Unable to find load balancer rule " + loadBalancerId); | |
| } | |
| _accountMgr.checkAccess(caller, null, true, rule); | |
| boolean result = deleteLoadBalancerRule(loadBalancerId, apply, caller, ctx.getCallingUserId(), true); | |
| if (!result) { | |
| throw new CloudRuntimeException(String.format("Unable to remove load balancer rule %s", rule)); | |
| } | |
| return result; | |
| } | |
| @DB | |
| public boolean deleteLoadBalancerRule(final long loadBalancerId, boolean apply, Account caller, long callerUserId, boolean rollBack) { | |
| List<AutoScaleVmGroupVO> vmGroups = _autoScaleVmGroupDao.listByLoadBalancer(loadBalancerId); | |
| if (CollectionUtils.isNotEmpty(vmGroups)) { | |
| throw new CloudRuntimeException(String.format("Cannot delete load balancer rule %d because it is being used by %s Autoscale VM group.", loadBalancerId, vmGroups.size())); | |
| } | |
| final LoadBalancerVO lb = _lbDao.findById(loadBalancerId); | |
| FirewallRule.State backupState = lb.getState(); | |
| // remove any ssl certs associated with this LB rule before trying to delete it. | |
| LoadBalancerCertMapVO lbCertMap = _lbCertMapDao.findByLbRuleId(loadBalancerId); | |
| if (lbCertMap != null) { | |
| boolean removeResult = removeCertFromLoadBalancer(loadBalancerId); | |
| if (!removeResult) { | |
| throw new CloudRuntimeException(String.format("Unable to remove certificate from load balancer rule %s", lb)); | |
| } | |
| } | |
| List<LoadBalancerVMMapVO> backupMaps = Transaction.execute(new TransactionCallback<List<LoadBalancerVMMapVO>>() { | |
| @Override | |
| public List<LoadBalancerVMMapVO> doInTransaction(TransactionStatus status) { | |
| boolean generateUsageEvent = false; | |
| if (lb.getState() == FirewallRule.State.Staged) { | |
| if (logger.isDebugEnabled()) { | |
| logger.debug("Found a rule that is still in stage state so just removing it: " + lb); | |
| } | |
| generateUsageEvent = true; | |
| } else if (lb.getState() == FirewallRule.State.Add || lb.getState() == FirewallRule.State.Active) { | |
| lb.setState(FirewallRule.State.Revoke); | |
| _lbDao.persist(lb); | |
| generateUsageEvent = true; | |
| } | |
| List<LoadBalancerVMMapVO> backupMaps = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId); | |
| List<LoadBalancerVMMapVO> maps = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId); | |
| if (maps != null) { | |
| for (LoadBalancerVMMapVO map : maps) { | |
| map.setRevoke(true); | |
| _lb2VmMapDao.persist(map); | |
| logger.debug("Set load balancer rule for revoke: rule {}, vmId {}", lb::toString, () -> _vmDao.findById(map.getInstanceId())); | |
| } | |
| } | |
| List<LBHealthCheckPolicyVO> hcPolicies = _lb2healthcheckDao.listByLoadBalancerIdAndDisplayFlag(loadBalancerId, null); | |
| for (LBHealthCheckPolicyVO lbHealthCheck : hcPolicies) { | |
| lbHealthCheck.setRevoke(true); | |
| _lb2healthcheckDao.persist(lbHealthCheck); | |
| } | |
| if (generateUsageEvent) { | |
| // Generate usage event right after all rules were marked for revoke | |
| Network network = _networkModel.getNetwork(lb.getNetworkId()); | |
| UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), network.getDataCenterId(), lb.getId(), | |
| null, LoadBalancingRule.class.getName(), lb.getUuid()); | |
| } | |
| return backupMaps; | |
| } | |
| }); | |
| // gather external network usage stats for this lb rule | |
| NetworkVO network = _networkDao.findById(lb.getNetworkId()); | |
| if (network != null) { | |
| if (_networkModel.networkIsConfiguredForExternalNetworking(network.getDataCenterId(), network.getId())) { | |
| _externalDeviceUsageMgr.updateExternalLoadBalancerNetworkUsageStats(loadBalancerId); | |
| } | |
| } | |
| if (apply) { | |
| try { | |
| if (!applyLoadBalancerConfig(loadBalancerId)) { | |
| logger.warn("Unable to apply the load balancer config"); | |
| return false; | |
| } | |
| } catch (ResourceUnavailableException e) { | |
| if (rollBack && isRollBackAllowedForProvider(lb)) { | |
| if (backupMaps != null) { | |
| for (LoadBalancerVMMapVO map : backupMaps) { | |
| _lb2VmMapDao.persist(map); | |
| logger.debug("LB Rollback rule: {}, vmId {}", lb, map.getInstanceId()); | |
| } | |
| } | |
| lb.setState(backupState); | |
| _lbDao.persist(lb); | |
| logger.debug("LB Rollback rule: {} while deleting LB rule.", lb); | |
| } else { | |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); | |
| } | |
| return false; | |
| } | |
| } | |
| FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(lb.getId()); | |
| if (relatedRule != null) { | |
| logger.warn("Unable to remove firewall rule={} as it has related firewall rule={}; leaving it in Revoke state", lb, relatedRule); | |
| return false; | |
| } else { | |
| _firewallMgr.removeRule(lb); | |
| } | |
| // FIXME: breaking the dependency on ELB manager. This breaks | |
| // functionality of ELB using virtual router | |
| // Bug CS-15411 opened to document this | |
| // _elbMgr.handleDeleteLoadBalancerRule(lb, callerUserId, caller); | |
| logger.debug("Load balancer {} is removed successfully", lb); | |
| return true; | |
| } | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") | |
| public LoadBalancer createPublicLoadBalancerRule(String xId, String name, String description, int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, | |
| Long ipAddrId, String protocol, String algorithm, long networkId, long lbOwnerId, boolean openFirewall, String lbProtocol, Boolean forDisplay) throws NetworkRuleConflictException, | |
| InsufficientAddressCapacityException { | |
| return createPublicLoadBalancerRule(xId, name, description, srcPortStart, srcPortEnd, defPortStart, defPortEnd, ipAddrId, protocol, algorithm, networkId, lbOwnerId, openFirewall, lbProtocol, forDisplay, null); | |
| } | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") | |
| public LoadBalancer createPublicLoadBalancerRule(String xId, String name, String description, int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, | |
| Long ipAddrId, String protocol, String algorithm, long networkId, long lbOwnerId, boolean openFirewall, String lbProtocol, Boolean forDisplay, List<String> cidrList) throws NetworkRuleConflictException, | |
| InsufficientAddressCapacityException { | |
| Account lbOwner = _accountMgr.getAccount(lbOwnerId); | |
| if (srcPortStart != srcPortEnd) { | |
| throw new InvalidParameterValueException("Port ranges are not supported by the load balancer"); | |
| } | |
| IPAddressVO ipVO = null; | |
| if (ipAddrId != null) { | |
| ipVO = _ipAddressDao.findById(ipAddrId); | |
| } | |
| Network network = _networkModel.getNetwork(networkId); | |
| // FIXME: breaking the dependency on ELB manager. This breaks | |
| // functionality of ELB using virtual router | |
| // Bug CS-15411 opened to document this | |
| // LoadBalancer result = _elbMgr.handleCreateLoadBalancerRule(lb, | |
| // lbOwner, lb.getNetworkId()); | |
| LoadBalancer result = null; | |
| IpAddress systemIp = null; | |
| NetworkOffering off = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId()); | |
| if (srcPortStart == DNS_PORT && ipVO.isSourceNat()) { | |
| List<NetworkOfferingServiceMapVO> offeringServices = _networkOfferingServiceDao.listByNetworkOfferingId(network.getNetworkOfferingId()); | |
| for (NetworkOfferingServiceMapVO serviceMapVo: offeringServices) { | |
| if (serviceMapVo.getService().equals(Service.Dns.getName())) { | |
| throw new InvalidParameterValueException("Error adding load balancer rule, cannot add port 53 with network service offering having DNS service and Source NAT."); | |
| } | |
| } | |
| } | |
| if (off.isElasticLb() && ipVO == null && network.getVpcId() == null) { | |
| systemIp = _ipAddrMgr.assignSystemIp(networkId, lbOwner, true, false); | |
| if (systemIp != null) { | |
| ipVO = _ipAddressDao.findById(systemIp.getId()); | |
| } | |
| } | |
| // Validate ip address | |
| if (ipVO == null) { | |
| throw new InvalidParameterValueException("Unable to create load balance rule; can't find/allocate source IP"); | |
| } else if (ipVO.isOneToOneNat()) { | |
| throw new NetworkRuleConflictException("Can't do load balance on ip address: " + ipVO.getAddress()); | |
| } | |
| String cidrString = generateCidrString(cidrList); | |
| boolean performedIpAssoc = false; | |
| try { | |
| if (ipVO.getAssociatedWithNetworkId() == null) { | |
| boolean assignToVpcNtwk = network.getVpcId() != null && ipVO.getVpcId() != null && ipVO.getVpcId().longValue() == network.getVpcId(); | |
| if (assignToVpcNtwk) { | |
| // set networkId just for verification purposes | |
| _networkModel.checkIpForService(ipVO, Service.Lb, networkId); | |
| logger.debug("The ip is not associated with the VPC network={} so assigning", network); | |
| ipVO = _ipAddrMgr.associateIPToGuestNetwork(ipAddrId, networkId, false); | |
| performedIpAssoc = true; | |
| } | |
| } else { | |
| _networkModel.checkIpForService(ipVO, Service.Lb, null); | |
| } | |
| if (ipVO.getAssociatedWithNetworkId() == null) { | |
| throw new InvalidParameterValueException("Ip address " + ipVO + " is not assigned to the network " + network); | |
| } | |
| result = createPublicLoadBalancer(xId, name, description, srcPortStart, defPortStart, ipVO.getId(), protocol, algorithm, openFirewall, CallContext.current(), | |
| lbProtocol, forDisplay, cidrString); | |
| } catch (Exception ex) { | |
| logger.warn("Failed to create load balancer due to ", ex); | |
| if (ex instanceof NetworkRuleConflictException) { | |
| throw (NetworkRuleConflictException)ex; | |
| } | |
| if (ex instanceof InvalidParameterValueException) { | |
| throw (InvalidParameterValueException)ex; | |
| } | |
| } finally { | |
| if (result == null && systemIp != null) { | |
| logger.debug("Releasing system IP address " + systemIp + " as corresponding lb rule failed to create"); | |
| _ipAddrMgr.handleSystemIpRelease(systemIp); | |
| } | |
| // release ip address if ipassoc was perfored | |
| if (performedIpAssoc) { | |
| ipVO = _ipAddressDao.findById(ipVO.getId()); | |
| _vpcMgr.unassignIPFromVpcNetwork(ipVO, network); | |
| } | |
| } | |
| if (result == null) { | |
| throw new CloudRuntimeException("Failed to create load balancer rule: " + name); | |
| } | |
| return result; | |
| } | |
| /** | |
| * Transforms the cidrList from a List of Strings to a String which contains all the CIDRs from cidrList separated by whitespaces. This is used to facilitate both the persistence | |
| * in the DB and also later when building the configuration String in the getRulesForPool method of the HAProxyConfigurator class. | |
| */ | |
| protected String generateCidrString(List<String> cidrList) { | |
| if (cidrList == null) { | |
| logger.trace("The given CIDR list is null, therefore we will return null."); | |
| return null; | |
| } | |
| String cidrString; | |
| StringBuilder sb = new StringBuilder(); | |
| for (String cidr: cidrList) { | |
| cidr = validateCidr(cidr); | |
| sb.append(cidr).append(' '); | |
| } | |
| cidrString = sb.toString(); | |
| logger.trace(String.format("From the cidrList [%s] we generated the following CIDR String [%s].", cidrList, cidrString)); | |
| return StringUtils.trim(cidrString); | |
| } | |
| private String validateCidr(String cidr) { | |
| cidr = StringUtils.trim(cidr); | |
| boolean validCidr = NetUtils.isValidIp4Cidr(cidr) || NetUtils.isValidIp6Cidr(cidr); | |
| boolean validIp = NetUtils.isValidIp4(cidr) || NetUtils.isValidIp6(cidr); | |
| if (!validCidr && !validIp) { | |
| throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("CIDR [%s] is invalid.", cidr)); | |
| } | |
| return cidr; | |
| } | |
| @DB | |
| @Override | |
| public LoadBalancer createPublicLoadBalancer(final String xId, final String name, final String description, final int srcPort, final int destPort, final long sourceIpId, | |
| final String protocol, final String algorithm, final boolean openFirewall, final CallContext caller, final String lbProtocol, | |
| final Boolean forDisplay, String cidrList) throws NetworkRuleConflictException { | |
| if (!NetUtils.isValidPort(destPort)) { | |
| throw new InvalidParameterValueException("privatePort is an invalid value: " + destPort); | |
| } | |
| if ((algorithm == null) || !NetUtils.isValidAlgorithm(algorithm)) { | |
| throw new InvalidParameterValueException("Invalid algorithm: " + algorithm); | |
| } | |
| try { | |
| final IPAddressVO ipAddr = _ipAddressDao.acquireInLockTable(sourceIpId); | |
| // make sure ip address exists | |
| if (ipAddr == null || !ipAddr.readyToUse()) { | |
| InvalidParameterValueException ex = new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id specified"); | |
| if (ipAddr == null) { | |
| ex.addProxyObject(String.valueOf(sourceIpId), "sourceIpId"); | |
| } else { | |
| ex.addProxyObject(ipAddr.getUuid(), "sourceIpId"); | |
| } | |
| throw ex; | |
| } else if (ipAddr.isOneToOneNat()) { | |
| InvalidParameterValueException ex = new InvalidParameterValueException("Unable to create load balancer rule; specified sourceip id has static nat enabled"); | |
| ex.addProxyObject(ipAddr.getUuid(), "sourceIpId"); | |
| throw ex; | |
| } | |
| _accountMgr.checkAccess(caller.getCallingAccount(), null, true, ipAddr); | |
| final Long networkId = ipAddr.getAssociatedWithNetworkId(); | |
| if (networkId == null) { | |
| InvalidParameterValueException ex = | |
| new InvalidParameterValueException("Unable to create load balancer rule ; specified sourceip id is not associated with any network"); | |
| ex.addProxyObject(ipAddr.getUuid(), "sourceIpId"); | |
| throw ex; | |
| } | |
| // verify that lb service is supported by the network | |
| isLbServiceSupportedInNetwork(networkId, Scheme.Public); | |
| _firewallMgr.validateFirewallRule(caller.getCallingAccount(), ipAddr, srcPort, srcPort, protocol, Purpose.LoadBalancing, FirewallRuleType.User, networkId, null); | |
| return Transaction.execute((TransactionCallbackWithException<LoadBalancerVO, NetworkRuleConflictException>) status -> { | |
| LoadBalancerVO newRule = new LoadBalancerVO(xId, name, description, sourceIpId, srcPort, destPort, algorithm, networkId, ipAddr.getAllocatedToAccountId(), | |
| ipAddr.getAllocatedInDomainId(), lbProtocol, cidrList); | |
| if (forDisplay != null) { | |
| newRule.setDisplay(forDisplay); | |
| } | |
| // verify rule is supported by Lb provider of the network | |
| Ip sourceIp = getSourceIp(newRule); | |
| LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), sourceIp, null, lbProtocol); | |
| if (!validateLbRule(loadBalancing)) { | |
| throw new InvalidParameterValueException("LB service provider cannot support this rule"); | |
| } | |
| newRule = _lbDao.persist(newRule); | |
| //create rule for all CIDRs | |
| if (openFirewall) { | |
| _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCallingAccount(), srcPort, srcPort, protocol, null, null, newRule.getId(), networkId); | |
| } | |
| boolean success = true; | |
| try { | |
| _firewallMgr.detectRulesConflict(newRule); | |
| if (!_firewallDao.setStateToAdd(newRule)) { | |
| throw new CloudRuntimeException("Unable to update the state to add for " + newRule); | |
| } | |
| logger.debug("Load balancer {} for Ip address: {}, public port {}, private port {} is added successfully.", newRule, ipAddr, srcPort, destPort); | |
| CallContext.current().setEventDetails("Load balancer Id: " + newRule.getId()); | |
| UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), ipAddr.getDataCenterId(), newRule.getId(), | |
| null, LoadBalancingRule.class.getName(), newRule.getUuid()); | |
| return newRule; | |
| } catch (Exception e) { | |
| success = false; | |
| if (e instanceof NetworkRuleConflictException) { | |
| throw (NetworkRuleConflictException)e; | |
| } | |
| throw new CloudRuntimeException("Unable to add rule for ip address id=" + newRule.getSourceIpAddressId(), e); | |
| } finally { | |
| if (!success && newRule != null) { | |
| _firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false); | |
| removeLBRule(newRule); | |
| } | |
| } | |
| }); | |
| } finally { | |
| _ipAddressDao.releaseFromLockTable(sourceIpId); | |
| } | |
| } | |
| @Override | |
| public boolean applyLoadBalancerConfig(long lbRuleId) throws ResourceUnavailableException { | |
| LoadBalancerVO lb = _lbDao.findById(lbRuleId); | |
| List<LoadBalancerVO> lbs; | |
| if (isRollBackAllowedForProvider(lb)) { | |
| // this is for Netscalar type of devices. if their is failure the db | |
| // entries will be rollbacked. | |
| lbs = Arrays.asList(lb); | |
| } else { | |
| boolean onlyRulesInTransitionState = true; | |
| for (LoadBalancingServiceProvider lbElement : _lbProviders) { | |
| Provider provider = lbElement.getProvider(); | |
| boolean isLbProvider = _networkModel.isProviderSupportServiceInNetwork(lb.getNetworkId(), Service.Lb, provider); | |
| if (!isLbProvider) { | |
| continue; | |
| } | |
| onlyRulesInTransitionState = lbElement.handlesOnlyRulesInTransitionState(); | |
| break; | |
| } | |
| // get all rules in transition state | |
| if (onlyRulesInTransitionState) { | |
| lbs = _lbDao.listInTransitionStateByNetworkIdAndScheme(lb.getNetworkId(), lb.getScheme()); | |
| } else { | |
| lbs = _lbDao.listByNetworkIdAndScheme(lb.getNetworkId(), lb.getScheme()); | |
| } | |
| } | |
| return applyLoadBalancerRules(lbs, true); | |
| } | |
| @Override | |
| public boolean revokeLoadBalancersForNetwork(Network network, Scheme scheme) throws ResourceUnavailableException { | |
| List<LoadBalancerVO> lbs = _lbDao.listByNetworkIdAndScheme(network.getId(), scheme); | |
| if (logger.isDebugEnabled()) { | |
| logger.debug("Revoking {} {} load balancing rules for network {}", lbs.size(), scheme, network); | |
| } | |
| if (lbs != null) { | |
| for (LoadBalancerVO lb : lbs) { // called during restart, not persisting state in db | |
| lb.setState(FirewallRule.State.Revoke); | |
| } | |
| return applyLoadBalancerRules(lbs, false); // called during restart, not persisting state in db | |
| } else { | |
| logger.info("Network {} doesn't have load balancer rules, nothing to revoke", network); | |
| return true; | |
| } | |
| } | |
| @Override | |
| public boolean applyLoadBalancersForNetwork(Network network, Scheme scheme) throws ResourceUnavailableException { | |
| List<LoadBalancerVO> lbs = _lbDao.listByNetworkIdAndScheme(network.getId(), scheme); | |
| if (lbs != null) { | |
| logger.debug("Applying load balancer rules of scheme {} in network {}", scheme, network); | |
| return applyLoadBalancerRules(lbs, true); | |
| } else { | |
| logger.info("Network {} doesn't have load balancer rules of scheme {}, nothing to apply", network, scheme); | |
| return true; | |
| } | |
| } | |
| protected boolean applyLbRules(Network network, List<LoadBalancingRule> rules) throws ResourceUnavailableException { | |
| boolean handled = false; | |
| for (LoadBalancingServiceProvider lbElement : _lbProviders) { | |
| Provider provider = lbElement.getProvider(); | |
| boolean isLbProvider = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Lb, provider); | |
| if (!isLbProvider) { | |
| continue; | |
| } | |
| handled = lbElement.applyLBRules(network, rules); | |
| if (handled) | |
| break; | |
| } | |
| return handled; | |
| } | |
| private LoadBalancingRule getLoadBalancerRuleToApply(LoadBalancerVO lb) { | |
| List<LbStickinessPolicy> policyList = getStickinessPolicies(lb.getId()); | |
| Ip sourceIp = getSourceIp(lb); | |
| LbSslCert sslCert = getLbSslCert(lb.getId()); | |
| LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, null, policyList, null, sourceIp, sslCert, lb.getLbProtocol()); | |
| if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(lb.getId())) { | |
| // Get the associated VmGroup | |
| AutoScaleVmGroupVO vmGroup = _autoScaleVmGroupDao.listByAll(lb.getId(), null).get(0); | |
| LbAutoScaleVmGroup lbAutoScaleVmGroup = getLbAutoScaleVmGroup(vmGroup, vmGroup.getState(), lb); | |
| loadBalancing.setAutoScaleVmGroup(lbAutoScaleVmGroup); | |
| } else { | |
| List<LbDestination> dstList = getExistingDestinations(lb.getId()); | |
| loadBalancing.setDestinations(dstList); | |
| List<LbHealthCheckPolicy> hcPolicyList = getHealthCheckPolicies(lb.getId()); | |
| loadBalancing.setHealthCheckPolicies(hcPolicyList); | |
| } | |
| return loadBalancing; | |
| } | |
| @DB | |
| protected boolean applyLoadBalancerRules(List<LoadBalancerVO> lbs, boolean updateRulesInDB) throws ResourceUnavailableException { | |
| List<LoadBalancingRule> rules = new ArrayList<LoadBalancingRule>(); | |
| for (LoadBalancerVO lb : lbs) { | |
| rules.add(getLoadBalancerRuleToApply(lb)); | |
| } | |
| if (!applyLbRules(rules, false)) { | |
| logger.debug("LB rules are not completely applied"); | |
| return false; | |
| } | |
| if (updateRulesInDB) { | |
| for (final LoadBalancerVO lb : lbs) { | |
| boolean checkForReleaseElasticIp = Transaction.execute(new TransactionCallback<Boolean>() { | |
| @Override | |
| public Boolean doInTransaction(TransactionStatus status) { | |
| boolean checkForReleaseElasticIp = false; | |
| if (lb.getState() == FirewallRule.State.Revoke) { | |
| removeLBRule(lb); | |
| logger.debug("LB {} is successfully removed", lb); | |
| checkForReleaseElasticIp = true; | |
| } else if (lb.getState() == FirewallRule.State.Add) { | |
| lb.setState(FirewallRule.State.Active); | |
| logger.debug("LB rule {} state is set to Active", lb); | |
| _lbDao.persist(lb); | |
| } | |
| // remove LB-Vm mappings that were state to revoke | |
| List<LoadBalancerVMMapVO> lbVmMaps = _lb2VmMapDao.listByLoadBalancerId(lb.getId(), true); | |
| List<Long> instanceIds = new ArrayList<Long>(); | |
| for (LoadBalancerVMMapVO lbVmMap : lbVmMaps) { | |
| instanceIds.add(lbVmMap.getInstanceId()); | |
| _lb2VmMapDao.remove(lb.getId(), lbVmMap.getInstanceId(), lbVmMap.getInstanceIp(), null); | |
| logger.debug("Load balancer rule {} is removed for vm {} instance ip {}", | |
| lb, lbVmMap.getInstanceId(), lbVmMap.getInstanceIp());; | |
| } | |
| if (_lb2VmMapDao.listByLoadBalancerId(lb.getId()).isEmpty()) { | |
| lb.setState(FirewallRule.State.Add); | |
| _lbDao.persist(lb); | |
| logger.debug("LB rule {} state is set to Add as there are no more active LB-VM mappings", lb); | |
| } | |
| // remove LB-Stickiness policy mapping that were state to revoke | |
| List<LBStickinessPolicyVO> stickinesspolicies = _lb2stickinesspoliciesDao.listByLoadBalancerId(lb.getId(), true); | |
| if (!stickinesspolicies.isEmpty()) { | |
| _lb2stickinesspoliciesDao.remove(lb.getId(), true); | |
| logger.debug("Load balancer rule {} is removed stickiness policies", lb); | |
| } | |
| // remove LB-HealthCheck policy mapping that were state to | |
| // revoke | |
| List<LBHealthCheckPolicyVO> healthCheckpolicies = _lb2healthcheckDao.listByLoadBalancerId(lb.getId(), true); | |
| if (!healthCheckpolicies.isEmpty()) { | |
| _lb2healthcheckDao.remove(lb.getId(), true); | |
| logger.debug("Load balancer rule {} is removed health check monitors policies", lb); | |
| } | |
| LoadBalancerCertMapVO lbCertMap = _lbCertMapDao.findByLbRuleId(lb.getId()); | |
| if (lbCertMap != null && lbCertMap.isRevoke()) { | |
| _lbCertMapDao.remove(lbCertMap.getId()); | |
| logger.debug("Load balancer rule {} removed certificate mapping", lb); | |
| } | |
| return checkForReleaseElasticIp; | |
| } | |
| }); | |
| if (checkForReleaseElasticIp && lb.getSourceIpAddressId() != null) { | |
| boolean success = true; | |
| long count = _firewallDao.countRulesByIpId(lb.getSourceIpAddressId()); | |
| if (count == 0) { | |
| try { | |
| success = handleSystemLBIpRelease(lb); | |
| } catch (Exception ex) { | |
| logger.warn("Failed to release system ip as a part of lb rule " + lb + " deletion due to exception ", ex); | |
| success = false; | |
| } finally { | |
| if (!success) { | |
| logger.warn("Failed to release system ip as a part of lb rule " + lb + " deletion"); | |
| } | |
| } | |
| } | |
| } | |
| // if the rule is the last one for the ip address assigned to | |
| // VPC, unassign it from the network | |
| if (lb.getSourceIpAddressId() != null) { | |
| _vpcMgr.unassignIPFromVpcNetwork(lb.getSourceIpAddressId(), lb.getNetworkId()); | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| protected boolean handleSystemLBIpRelease(LoadBalancerVO lb) { | |
| IpAddress ip = _ipAddressDao.findById(lb.getSourceIpAddressId()); | |
| boolean success = true; | |
| if (ip.getSystem()) { | |
| logger.debug("Releasing system ip address {} as a part of delete lb rule", ip); | |
| if (!_ipAddrMgr.disassociatePublicIpAddress(ip, CallContext.current().getCallingUserId(), CallContext.current().getCallingAccount())) { | |
| logger.warn("Unable to release system ip address={} as a part of delete lb rule", ip); | |
| success = false; | |
| } else { | |
| logger.warn("Successfully released system ip address={} as a part of delete lb rule", ip); | |
| } | |
| } | |
| return success; | |
| } | |
| @Override | |
| public boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId) { | |
| //Included revoked rules to remove the rules of ips which are in revoke state | |
| List<FirewallRuleVO> rules = _firewallDao.listByIpAndPurpose(ipId, Purpose.LoadBalancing); | |
| if (rules != null) { | |
| logger.debug("Found " + rules.size() + " lb rules to cleanup"); | |
| for (FirewallRule rule : rules) { | |
| boolean result = deleteLoadBalancerRule(rule.getId(), true, caller, callerUserId, false); | |
| if (result == false) { | |
| logger.warn("Unable to remove load balancer rule {}", rule); | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| @Override | |
| public boolean removeAllLoadBalanacersForNetwork(long networkId, Account caller, long callerUserId) { | |
| List<FirewallRuleVO> rules = _firewallDao.listByNetworkAndPurposeAndNotRevoked(networkId, Purpose.LoadBalancing); | |
| if (rules != null) { | |
| logger.debug("Found " + rules.size() + " lb rules to cleanup"); | |
| for (FirewallRule rule : rules) { | |
| boolean result = deleteLoadBalancerRule(rule.getId(), true, caller, callerUserId, false); | |
| if (result == false) { | |
| logger.warn("Unable to remove load balancer rule {}", rule); | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| @Override | |
| public List<LbStickinessPolicy> getStickinessPolicies(long lbId) { | |
| List<LbStickinessPolicy> stickinessPolicies = new ArrayList<LbStickinessPolicy>(); | |
| List<LBStickinessPolicyVO> sDbpolicies = _lb2stickinesspoliciesDao.listByLoadBalancerId(lbId, false); | |
| for (LBStickinessPolicyVO sDbPolicy : sDbpolicies) { | |
| LbStickinessPolicy sPolicy = new LbStickinessPolicy(sDbPolicy.getMethodName(), sDbPolicy.getParams(), sDbPolicy.isRevoke()); | |
| stickinessPolicies.add(sPolicy); | |
| } | |
| return stickinessPolicies; | |
| } | |
| @Override | |
| public List<LbHealthCheckPolicy> getHealthCheckPolicies(long lbId) { | |
| List<LbHealthCheckPolicy> healthCheckPolicies = new ArrayList<LbHealthCheckPolicy>(); | |
| List<LBHealthCheckPolicyVO> hcDbpolicies = _lb2healthcheckDao.listByLoadBalancerIdAndDisplayFlag(lbId, null); | |
| for (LBHealthCheckPolicyVO policy : hcDbpolicies) { | |
| String pingpath = policy.getpingpath(); | |
| LbHealthCheckPolicy hDbPolicy = | |
| new LbHealthCheckPolicy(pingpath, policy.getDescription(), policy.getResponseTime(), policy.getHealthcheckInterval(), policy.getHealthcheckThresshold(), | |
| policy.getUnhealthThresshold(), policy.isRevoke()); | |
| healthCheckPolicies.add(hDbPolicy); | |
| } | |
| return healthCheckPolicies; | |
| } | |
| @Override | |
| public List<LbDestination> getExistingDestinations(long lbId) { | |
| List<LbDestination> dstList = new ArrayList<LbDestination>(); | |
| List<LoadBalancerVMMapVO> lbVmMaps = _lb2VmMapDao.listByLoadBalancerId(lbId); | |
| LoadBalancerVO lb = _lbDao.findById(lbId); | |
| String dstIp = null; | |
| for (LoadBalancerVMMapVO lbVmMap : lbVmMaps) { | |
| UserVm vm = _vmDao.findById(lbVmMap.getInstanceId()); | |
| Nic nic = _nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(lb.getNetworkId(), vm.getId()); | |
| dstIp = lbVmMap.getInstanceIp() == null ? nic.getIPv4Address(): lbVmMap.getInstanceIp(); | |
| LbDestination lbDst = new LbDestination(lb.getDefaultPortStart(), lb.getDefaultPortEnd(), dstIp, lbVmMap.isRevoke()); | |
| dstList.add(lbDst); | |
| } | |
| return dstList; | |
| } | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_UPDATE, eventDescription = "updating load balancer", async = true) | |
| public LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd) { | |
| Account caller = CallContext.current().getCallingAccount(); | |
| Long lbRuleId = cmd.getId(); | |
| String name = cmd.getLoadBalancerName(); | |
| String description = cmd.getDescription(); | |
| String algorithm = cmd.getAlgorithm(); | |
| LoadBalancerVO lb = _lbDao.findById(lbRuleId); | |
| LoadBalancerVO lbBackup = _lbDao.findById(lbRuleId); | |
| String customId = cmd.getCustomId(); | |
| Boolean forDisplay = cmd.getDisplay(); | |
| String lbProtocol = cmd.getLbProtocol(); | |
| if (lb == null) { | |
| throw new InvalidParameterValueException("Unable to find lb rule by id=" + lbRuleId); | |
| } | |
| // check permissions | |
| _accountMgr.checkAccess(caller, null, true, lb); | |
| if (name != null) { | |
| lb.setName(name); | |
| } | |
| if (description != null) { | |
| lb.setDescription(description); | |
| } | |
| if (algorithm != null) { | |
| lb.setAlgorithm(algorithm); | |
| } | |
| if (customId != null) { | |
| lb.setUuid(customId); | |
| } | |
| if (forDisplay != null) { | |
| lb.setDisplay(forDisplay); | |
| } | |
| if (StringUtils.isNotBlank(lbProtocol)) { | |
| lb.setLbProtocol(lbProtocol); | |
| } | |
| // Validate rule in LB provider | |
| LoadBalancingRule rule = getLoadBalancerRuleToApply(lb); | |
| if (!validateLbRule(rule)) { | |
| throw new InvalidParameterValueException(String.format("Modifications in lb rule %s are not supported.", lb)); | |
| } | |
| LoadBalancerVO tmplbVo = _lbDao.findById(lbRuleId); | |
| boolean success = _lbDao.update(lbRuleId, lb); | |
| // If algorithm is changed, have to reapply the lb config | |
| if ((algorithm != null) && (tmplbVo.getAlgorithm().compareTo(algorithm) != 0)){ | |
| try { | |
| lb.setState(FirewallRule.State.Add); | |
| _lbDao.persist(lb); | |
| applyLoadBalancerConfig(lbRuleId); | |
| } catch (ResourceUnavailableException e) { | |
| if (isRollBackAllowedForProvider(lb)) { | |
| /* | |
| * NOTE : We use lb object to update db instead of lbBackup | |
| * object since db layer will fail to update if there is no | |
| * change in the object. | |
| */ | |
| if (lbBackup.getName() != null) { | |
| lb.setName(lbBackup.getName()); | |
| } | |
| if (lbBackup.getDescription() != null) { | |
| lb.setDescription(lbBackup.getDescription()); | |
| } | |
| if (lbBackup.getAlgorithm() != null) { | |
| lb.setAlgorithm(lbBackup.getAlgorithm()); | |
| } | |
| lb.setState(lbBackup.getState()); | |
| _lbDao.update(lb.getId(), lb); | |
| _lbDao.persist(lb); | |
| logger.debug("LB Rollback rule: {} while updating LB rule.", lb); | |
| } | |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); | |
| success = false; | |
| } | |
| } | |
| if (!success) { | |
| throw new CloudRuntimeException(String.format("Failed to update load balancer rule: %s", lb)); | |
| } | |
| return lb; | |
| } | |
| @Override | |
| public Pair<List<? extends UserVm>, List<String>> listLoadBalancerInstances(ListLoadBalancerRuleInstancesCmd cmd) throws PermissionDeniedException { | |
| Account caller = CallContext.current().getCallingAccount(); | |
| Long loadBalancerId = cmd.getId(); | |
| Boolean applied = cmd.isApplied(); | |
| if (applied == null) { | |
| logger.info(String.format("The [%s] parameter was not passed. Using the default value [%s].", ApiConstants.APPLIED, Boolean.TRUE)); | |
| applied = Boolean.TRUE; | |
| } | |
| LoadBalancerVO loadBalancer = _lbDao.findById(loadBalancerId); | |
| if (loadBalancer == null) { | |
| String msg = String.format("Unable to find the load balancer with ID [%s].", cmd.getId()); | |
| logger.error(msg); | |
| throw new CloudRuntimeException(msg); | |
| } | |
| String loadBalancerAsString = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(loadBalancer, "uuid", "name"); | |
| _accountMgr.checkAccess(caller, null, true, loadBalancer); | |
| List<UserVmVO> loadBalancerInstances = new ArrayList<>(); | |
| List<String> serviceStates = new ArrayList<>(); | |
| List<LoadBalancerVMMapVO> vmLoadBalancerMappings = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId); | |
| if (vmLoadBalancerMappings == null) { | |
| String msg = String.format("Unable to find map of VMs related to load balancer [%s].", loadBalancerAsString); | |
| logger.error(msg); | |
| throw new CloudRuntimeException(msg); | |
| } | |
| Map<Long, String> vmServiceState = new HashMap<>(vmLoadBalancerMappings.size()); | |
| List<Long> appliedInstanceIdList = new ArrayList<>(); | |
| for (LoadBalancerVMMapVO vmLoadBalancerMapping : vmLoadBalancerMappings) { | |
| appliedInstanceIdList.add(vmLoadBalancerMapping.getInstanceId()); | |
| vmServiceState.put(vmLoadBalancerMapping.getInstanceId(), vmLoadBalancerMapping.getState()); | |
| } | |
| List<UserVmVO> userVms = _vmDao.listByIds(appliedInstanceIdList); | |
| for (UserVmVO userVm : userVms) { | |
| // if the VM is destroyed, being expunged, in an error state, or in | |
| // an unknown state, skip it | |
| switch (userVm.getState()) { | |
| case Destroyed: | |
| case Expunging: | |
| case Error: | |
| case Unknown: | |
| continue; | |
| } | |
| String userVmAsString = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(userVm, "uuid", "name"); | |
| boolean isApplied = appliedInstanceIdList.contains(userVm.getId()); | |
| String isAppliedMsg = isApplied ? "is applied" : "is not applied"; | |
| logger.debug(String.format("The user VM [%s] %s to a rule of the load balancer [%s].", userVmAsString, isAppliedMsg, loadBalancerAsString)); | |
| if (isApplied != applied) { | |
| logger.debug(String.format("Skipping adding service state from the user VM [%s] to the service state list. This happens because the VM %s to the load " | |
| + "balancer rule and the [%s] parameter was passed as [%s].", userVmAsString, isAppliedMsg, ApiConstants.APPLIED, applied)); | |
| continue; | |
| } | |
| loadBalancerInstances.add(userVm); | |
| String serviceState = vmServiceState.get(userVm.getId()); | |
| logger.debug(String.format("Adding the service state [%s] from the user VM [%s] to the service state list.", serviceState, userVmAsString)); | |
| serviceStates.add(serviceState); | |
| } | |
| return new Pair<>(loadBalancerInstances, serviceStates); | |
| } | |
| @Override | |
| public List<String> listLbVmIpAddress (long id, long vmId) { | |
| List <LoadBalancerVMMapVO> listLbvmMapVo = _lb2VmMapDao.listByLoadBalancerIdAndVmId(id, vmId); | |
| List <String> vmIps = new ArrayList<String>(); | |
| for (LoadBalancerVMMapVO lbVmVo : listLbvmMapVo) { | |
| vmIps.add(lbVmVo.getInstanceIp()); | |
| } | |
| return vmIps; | |
| } | |
| @Override | |
| public List<LbStickinessMethod> getStickinessMethods(long networkid) { | |
| String capability = getLBCapability(networkid, Capability.SupportedStickinessMethods.getName()); | |
| if (capability == null) { | |
| return null; | |
| } | |
| Gson gson = new Gson(); | |
| java.lang.reflect.Type listType = new TypeToken<List<LbStickinessMethod>>() { | |
| }.getType(); | |
| List<LbStickinessMethod> result = gson.fromJson(capability, listType); | |
| return result; | |
| } | |
| @Override | |
| public List<LBStickinessPolicyVO> searchForLBStickinessPolicies(ListLBStickinessPoliciesCmd cmd) throws PermissionDeniedException { | |
| Account caller = CallContext.current().getCallingAccount(); | |
| Long loadBalancerId = cmd.getLbRuleId(); | |
| Long stickinessId = cmd.getId(); | |
| boolean forDisplay = cmd.getDisplay(); | |
| LoadBalancerVO loadBalancer = null; | |
| if (loadBalancerId == null) { | |
| loadBalancer = findLbByStickinessId(stickinessId); | |
| } else { | |
| loadBalancer = _lbDao.findById(loadBalancerId); | |
| } | |
| if (loadBalancer == null) { | |
| return null; | |
| } | |
| _accountMgr.checkAccess(caller, null, true, loadBalancer); | |
| List<LBStickinessPolicyVO> sDbpolicies = _lb2stickinesspoliciesDao.listByLoadBalancerIdAndDisplayFlag(loadBalancer.getId(), forDisplay); | |
| return sDbpolicies; | |
| } | |
| @Override | |
| public List<LBHealthCheckPolicyVO> searchForLBHealthCheckPolicies(ListLBHealthCheckPoliciesCmd cmd) throws PermissionDeniedException { | |
| Account caller = CallContext.current().getCallingAccount(); | |
| Long loadBalancerId = cmd.getLbRuleId(); | |
| Long policyId = cmd.getId(); | |
| boolean forDisplay = cmd.getDisplay(); | |
| if(loadBalancerId == null) { | |
| loadBalancerId = findLBIdByHealtCheckPolicyId(policyId); | |
| } | |
| LoadBalancerVO loadBalancer = _lbDao.findById(loadBalancerId); | |
| if (loadBalancer == null) { | |
| return null; | |
| } | |
| _accountMgr.checkAccess(caller, null, true, loadBalancer); | |
| List<LBHealthCheckPolicyVO> hcDbpolicies = _lb2healthcheckDao.listByLoadBalancerIdAndDisplayFlag(loadBalancerId, forDisplay); | |
| return hcDbpolicies; | |
| } | |
| @Override | |
| public Pair<List<? extends LoadBalancer>, Integer> searchForLoadBalancers(ListLoadBalancerRulesCmd cmd) { | |
| Long ipId = cmd.getPublicIpId(); | |
| Long zoneId = cmd.getZoneId(); | |
| Long id = cmd.getId(); | |
| String name = cmd.getLoadBalancerRuleName(); | |
| String keyword = cmd.getKeyword(); | |
| Long instanceId = cmd.getVirtualMachineId(); | |
| Long networkId = cmd.getNetworkId(); | |
| Map<String, String> tags = cmd.getTags(); | |
| Boolean forDisplay = cmd.getDisplay(); | |
| Account caller = CallContext.current().getCallingAccount(); | |
| List<Long> permittedAccounts = new ArrayList<Long>(); | |
| Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>( | |
| cmd.getDomainId(), cmd.isRecursive(), null); | |
| _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, | |
| domainIdRecursiveListProject, cmd.listAll(), false); | |
| Long domainId = domainIdRecursiveListProject.first(); | |
| Boolean isRecursive = domainIdRecursiveListProject.second(); | |
| ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); | |
| Filter searchFilter = new Filter(LoadBalancerVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); | |
| SearchBuilder<LoadBalancerVO> sb = _lbDao.createSearchBuilder(); | |
| _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); | |
| sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); | |
| sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); | |
| sb.and("sourceIpAddress", sb.entity().getSourceIpAddressId(), SearchCriteria.Op.EQ); | |
| sb.and("networkId", sb.entity().getNetworkId(), SearchCriteria.Op.EQ); | |
| sb.and("scheme", sb.entity().getScheme(), SearchCriteria.Op.EQ); | |
| sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ); | |
| if (instanceId != null) { | |
| SearchBuilder<LoadBalancerVMMapVO> lbVMSearch = _lb2VmMapDao.createSearchBuilder(); | |
| lbVMSearch.and("instanceId", lbVMSearch.entity().getInstanceId(), SearchCriteria.Op.EQ); | |
| sb.join("lbVMSearch", lbVMSearch, sb.entity().getId(), lbVMSearch.entity().getLoadBalancerId(), JoinBuilder.JoinType.INNER); | |
| } | |
| if (zoneId != null) { | |
| SearchBuilder<IPAddressVO> ipSearch = _ipAddressDao.createSearchBuilder(); | |
| ipSearch.and("zoneId", ipSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); | |
| sb.join("ipSearch", ipSearch, sb.entity().getSourceIpAddressId(), ipSearch.entity().getId(), JoinBuilder.JoinType.INNER); | |
| } | |
| if (tags != null && !tags.isEmpty()) { | |
| SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder(); | |
| for (int count = 0; count < tags.size(); count++) { | |
| tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); | |
| tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); | |
| tagSearch.cp(); | |
| } | |
| tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); | |
| sb.groupBy(sb.entity().getId()); | |
| sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); | |
| } | |
| SearchCriteria<LoadBalancerVO> sc = sb.create(); | |
| _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); | |
| if (keyword != null) { | |
| SearchCriteria<LoadBalancerVO> ssc = _lbDao.createSearchCriteria(); | |
| ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); | |
| ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword + "%"); | |
| sc.addAnd("name", SearchCriteria.Op.SC, ssc); | |
| } | |
| if (name != null) { | |
| sc.setParameters("name", name); | |
| } | |
| if (id != null) { | |
| sc.setParameters("id", id); | |
| } | |
| if (ipId != null) { | |
| sc.setParameters("sourceIpAddress", ipId); | |
| } | |
| if (instanceId != null) { | |
| sc.setJoinParameters("lbVMSearch", "instanceId", instanceId); | |
| } | |
| if (zoneId != null) { | |
| sc.setJoinParameters("ipSearch", "zoneId", zoneId); | |
| } | |
| if (networkId != null) { | |
| sc.setParameters("networkId", networkId); | |
| } | |
| if (tags != null && !tags.isEmpty()) { | |
| int count = 0; | |
| sc.setJoinParameters("tagSearch", "resourceType", ResourceObjectType.LoadBalancer.toString()); | |
| for (String key : tags.keySet()) { | |
| sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key); | |
| sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key)); | |
| count++; | |
| } | |
| } | |
| if (forDisplay != null) { | |
| sc.setParameters("display", forDisplay); | |
| } | |
| //list only Public load balancers using this command | |
| sc.setParameters("scheme", Scheme.Public); | |
| Pair<List<LoadBalancerVO>, Integer> result = _lbDao.searchAndCount(sc, searchFilter); | |
| return new Pair<List<? extends LoadBalancer>, Integer>(result.first(), result.second()); | |
| } | |
| @Override | |
| public LoadBalancerVO findById(long lbId) { | |
| return _lbDao.findById(lbId); | |
| } | |
| @Override | |
| public LoadBalancerVO findLbByStickinessId(long stickinessPolicyId) { | |
| LBStickinessPolicyVO stickinessPolicy = _lb2stickinesspoliciesDao.findById(stickinessPolicyId); | |
| if (stickinessPolicy == null) { | |
| return null; | |
| } | |
| return _lbDao.findById(stickinessPolicy.getLoadBalancerId()); | |
| } | |
| @Override | |
| public void removeLBRule(LoadBalancer rule) { | |
| // remove the rule | |
| _lbDao.remove(rule.getId()); | |
| } | |
| public boolean applyLbRules(List<LoadBalancingRule> rules, boolean continueOnError) throws ResourceUnavailableException { | |
| if (rules == null || rules.size() == 0) { | |
| logger.debug("There are no Load Balancing Rules to forward to the network elements"); | |
| return true; | |
| } | |
| boolean success = true; | |
| Network network = _networkModel.getNetwork(rules.get(0).getNetworkId()); | |
| List<PublicIp> publicIps = new ArrayList<PublicIp>(); | |
| // get the list of public ip's owned by the network | |
| List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null); | |
| if (userIps != null && !userIps.isEmpty()) { | |
| for (IPAddressVO userIp : userIps) { | |
| PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); | |
| publicIps.add(publicIp); | |
| } | |
| } | |
| // rules can not programmed unless IP is associated with network | |
| // service provider, so run IP assoication for | |
| // the network so as to ensure IP is associated before applying | |
| // rules (in add state) | |
| _ipAddrMgr.applyIpAssociations(network, false, continueOnError, publicIps); | |
| try { | |
| applyLbRules(network, rules); | |
| } catch (ResourceUnavailableException e) { | |
| if (!continueOnError) { | |
| throw e; | |
| } | |
| logger.warn("Problems with applying load balancing rules but pushing on", e); | |
| success = false; | |
| } | |
| // if all the rules configured on public IP are revoked then | |
| // dis-associate IP with network service provider | |
| _ipAddrMgr.applyIpAssociations(network, true, continueOnError, publicIps); | |
| return success; | |
| } | |
| @Override | |
| public Map<Ip, UserVm> getLbInstances(long lbId) { | |
| Map<Ip, UserVm> dstList = new HashMap<Ip, UserVm>(); | |
| List<LoadBalancerVMMapVO> lbVmMaps = _lb2VmMapDao.listByLoadBalancerId(lbId); | |
| LoadBalancerVO lb = _lbDao.findById(lbId); | |
| for (LoadBalancerVMMapVO lbVmMap : lbVmMaps) { | |
| UserVm vm = _vmDao.findById(lbVmMap.getInstanceId()); | |
| Nic nic = _nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(lb.getNetworkId(), vm.getId()); | |
| Ip ip = new Ip(nic.getIPv4Address()); | |
| dstList.put(ip, vm); | |
| } | |
| return dstList; | |
| } | |
| @Override | |
| public boolean isLbRuleMappedToVmGuestIp(String vmSecondaryIp) { | |
| List<LoadBalancerVMMapVO> lbVmMap = _lb2VmMapDao.listByInstanceIp(vmSecondaryIp); | |
| if (lbVmMap == null || lbVmMap.isEmpty()) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| @Override | |
| public void isLbServiceSupportedInNetwork(long networkId, Scheme scheme) { | |
| Network network = _networkDao.findById(networkId); | |
| //1) Check if the LB service is supported | |
| if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { | |
| InvalidParameterValueException ex = new InvalidParameterValueException("LB service is not supported in specified network id"); | |
| ex.addProxyObject(network.getUuid(), "networkId"); | |
| throw ex; | |
| } | |
| //2) Check if the Scheme is supported\ | |
| NetworkOffering off = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId()); | |
| if (scheme == Scheme.Public) { | |
| if (!off.isPublicLb()) { | |
| throw new InvalidParameterValueException("Scheme " + scheme + " is not supported by the network offering " + off); | |
| } | |
| } else { | |
| if (!off.isInternalLb()) { | |
| throw new InvalidParameterValueException("Scheme " + scheme + " is not supported by the network offering " + off); | |
| } | |
| } | |
| //3) Check if the provider supports the scheme | |
| LoadBalancingServiceProvider lbProvider = _networkMgr.getLoadBalancingProviderForNetwork(network, scheme); | |
| if (lbProvider == null) { | |
| throw new InvalidParameterValueException("Lb rule with scheme " + scheme.toString() + " is not supported by lb providers in network " + network); | |
| } | |
| } | |
| public List<LoadBalancingServiceProvider> getLbProviders() { | |
| return _lbProviders; | |
| } | |
| @Inject | |
| public void setLbProviders(List<LoadBalancingServiceProvider> lbProviders) { | |
| this._lbProviders = lbProviders; | |
| } | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_STICKINESSPOLICY_UPDATE, eventDescription = "updating lb stickiness policy", async = true) | |
| public StickinessPolicy updateLBStickinessPolicy(long id, String customId, Boolean forDisplay) { | |
| LBStickinessPolicyVO policy = _lb2stickinesspoliciesDao.findById(id); | |
| if (policy == null) { | |
| throw new InvalidParameterValueException("Fail to find stickiness policy with " + id); | |
| } | |
| LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(policy.getLoadBalancerId())); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException(String.format("Invalid Load balancer: %d for Stickiness policy: %s", policy.getLoadBalancerId(), policy)); | |
| } | |
| _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, loadBalancer); | |
| if (customId != null) { | |
| policy.setUuid(customId); | |
| } | |
| if (forDisplay != null) { | |
| policy.setDisplay(forDisplay); | |
| } | |
| _lb2stickinesspoliciesDao.update(id, policy); | |
| return _lb2stickinesspoliciesDao.findById(id); | |
| } | |
| @Override | |
| @ActionEvent(eventType = EventTypes.EVENT_LB_HEALTHCHECKPOLICY_UPDATE, eventDescription = "updating lb healthcheck policy", async = true) | |
| public HealthCheckPolicy updateLBHealthCheckPolicy(long id, String customId, Boolean forDisplay) { | |
| LBHealthCheckPolicyVO policy = _lb2healthcheckDao.findById(id); | |
| if (policy == null) { | |
| throw new InvalidParameterValueException("Fail to find stickiness policy with " + id); | |
| } | |
| LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(policy.getLoadBalancerId())); | |
| if (loadBalancer == null) { | |
| throw new InvalidParameterValueException(String.format("Invalid Load balancer : %d for Stickiness policy: %s", policy.getLoadBalancerId(), policy)); | |
| } | |
| _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, loadBalancer); | |
| if (customId != null) { | |
| policy.setUuid(customId); | |
| } | |
| if (forDisplay != null) { | |
| policy.setDisplay(forDisplay); | |
| } | |
| _lb2healthcheckDao.update(id, policy); | |
| return _lb2healthcheckDao.findById(id); | |
| } | |
| @Override | |
| public Long findLBIdByHealtCheckPolicyId(long lbHealthCheckPolicy) { | |
| LBHealthCheckPolicyVO policy= _lb2healthcheckDao.findById(lbHealthCheckPolicy); | |
| if(policy != null) { | |
| return policy.getLoadBalancerId(); | |
| } | |
| return null; | |
| } | |
| } |