| // 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.security.InvalidParameterException; |
| 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.getName(), counter.getSource(), "" + counter.getValue(), counter.getProvider()); |
| Condition condition = lbCondition.getCondition(); |
| LoadBalancerTO.ConditionTO conditionTO = new LoadBalancerTO.ConditionTO(condition.getId(), condition.getThreshold(), condition.getRelationalOperator(), counterTO); |
| conditionTOs.add(conditionTO); |
| } |
| AutoScalePolicy autoScalePolicy = lbAutoScalePolicy.getPolicy(); |
| autoScalePolicyTOs.add(new LoadBalancerTO.AutoScalePolicyTO(autoScalePolicy.getId(), 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 with id: %s ", network.getId())); |
| } |
| 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: " + loadBalancer.getId() + " because resource is unavailable:", e); |
| if (isRollBackAllowedForProvider(loadBalancer)) { |
| loadBalancer.setState(backupState); |
| _lbDao.persist(loadBalancer); |
| logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " lb state rolback while creating AutoscaleVmGroup"); |
| } |
| throw e; |
| } finally { |
| if (!success) { |
| logger.warn("Failed to configure LB Auto Scale Vm Group with Id:" + vmGroupid); |
| } |
| } |
| |
| 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 " + loadBalancer.getId() + " state is set to Active"); |
| _lbDao.persist(loadBalancer); |
| vmGroup.setState(AutoScaleVmGroup.State.ENABLED); |
| _autoScaleVmGroupDao.persist(vmGroup); |
| logger.debug("LB Auto Scale Vm Group with Id: " + vmGroupid + " is set to Enabled state."); |
| } |
| }); |
| } |
| logger.info("Successfully configured LB Autoscale Vm Group with Id: " + vmGroupid); |
| } |
| 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("Failed: LB rule id: " + cmd.getLbRuleId() + " is in deleting state: "); |
| } |
| |
| /* Generic validations */ |
| if (!genericValidator(cmd)) { |
| throw new InvalidParameterValueException("Failed to create Stickiness policy: Validation Failed " + cmd.getLbRuleId()); |
| } |
| |
| /* |
| * 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("Failed to create Stickiness policy: Validation Failed " + cmd.getLbRuleId()); |
| } |
| |
| /* 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("Failed: LB rule id: " + cmd.getLbRuleId() + " is in deleting state: "); |
| } |
| |
| /* |
| * Validate Whether LB Provider has the capabilities to support Health |
| * Checks |
| */ |
| if (!validateHealthCheck(cmd)) { |
| throw new InvalidParameterValueException( |
| "Failed to create HealthCheck policy: Validation Failed (HealthCheck Policy is not supported by LB Provider for the LB rule id :" + cmd.getLbRuleId() + ")"); |
| } |
| |
| /* 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("Failed to create HealthCheck policy: Already policy attached for the LB Rule id :" + cmd.getLbRuleId()); |
| } |
| /* |
| * 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 InvalidParameterException("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: " + cmd.getLbRuleId() + " because resource is unavailable:", e); |
| if (isRollBackAllowedForProvider(loadBalancer)) { |
| loadBalancer.setState(backupState); |
| _lbDao.persist(loadBalancer); |
| deleteLBStickinessPolicy(cmd.getEntityId(), false); |
| logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " lb state rolback while creating sticky policy"); |
| } 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 InvalidParameterException("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: " + cmd.getLbRuleId() + " because resource is unavailable:", e); |
| if (isRollBackAllowedForProvider(loadBalancer)) { |
| loadBalancer.setState(backupState); |
| _lbDao.persist(loadBalancer); |
| logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " lb state rolback while creating healthcheck policy"); |
| } |
| 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 InvalidParameterException("Invalid Stickiness policy id value: " + stickinessPolicyId); |
| } |
| LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(stickinessPolicy.getLoadBalancerId())); |
| if (loadBalancer == null) { |
| throw new InvalidParameterException("Invalid Load balancer : " + stickinessPolicy.getLoadBalancerId() + " for Stickiness policy id: " + stickinessPolicyId); |
| } |
| 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 id " + loadBalancerId + ", stickinesspolicyID " + stickinessPolicyId); |
| |
| try { |
| if (!applyLoadBalancerConfig(loadBalancerId)) { |
| logger.warn("Failed to remove load balancer rule id " + loadBalancerId + " for stickinesspolicyID " + stickinessPolicyId); |
| throw new CloudRuntimeException("Failed to remove load balancer rule id " + loadBalancerId + " for stickinesspolicyID " + stickinessPolicyId); |
| } |
| } catch (ResourceUnavailableException e) { |
| if (isRollBackAllowedForProvider(loadBalancer)) { |
| stickinessPolicy.setRevoke(backupStickyState); |
| _lb2stickinesspoliciesDao.persist(stickinessPolicy); |
| loadBalancer.setState(backupState); |
| _lbDao.persist(loadBalancer); |
| logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " while deleting sticky policy: " + stickinessPolicyId); |
| } |
| 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 InvalidParameterException("Invalid HealthCheck policy id value: " + healthCheckPolicyId); |
| } |
| LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(healthCheckPolicy.getLoadBalancerId())); |
| if (loadBalancer == null) { |
| throw new InvalidParameterException("Invalid Load balancer : " + healthCheckPolicy.getLoadBalancerId() + " for HealthCheck policy id: " + healthCheckPolicyId); |
| } |
| 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 id : " + loadBalancerId + ", healthCheckpolicyID " + healthCheckPolicyId); |
| |
| // 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 id : " + loadBalancerId); |
| for (LoadBalancerVMMapVO map : maps) { |
| map.setState(null); |
| _lb2VmMapDao.persist(map); |
| } |
| } |
| }); |
| } |
| |
| try { |
| if (!applyLoadBalancerConfig(loadBalancerId)) { |
| logger.warn("Failed to remove load balancer rule id " + loadBalancerId + " for healthCheckpolicyID " + healthCheckPolicyId); |
| throw new CloudRuntimeException("Failed to remove load balancer rule id " + loadBalancerId + " for healthCheckpolicyID " + healthCheckPolicyId); |
| } |
| } catch (ResourceUnavailableException e) { |
| if (isRollBackAllowedForProvider(loadBalancer)) { |
| healthCheckPolicy.setRevoke(backupStickyState); |
| _lb2healthcheckDao.persist(healthCheckPolicy); |
| loadBalancer.setState(backupState); |
| _lbDao.persist(loadBalancer); |
| logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " while deleting healthcheck policy: " + healthCheckPolicyId); |
| } |
| 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("Failed to assign to load balancer " + loadBalancerId + " because it is being used by an Autoscale VM group."); |
| } |
| |
| 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 id: " + loadBalancer.getId() + " while attaching VM: " + 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 InvalidParameterException("Invalid load balancer id: " + lbRuleId); |
| } |
| |
| SslCertVO certVO = _entityMgr.findById(SslCertVO.class, certId); |
| if (certVO == null) { |
| throw new InvalidParameterException("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 id: " + loadBalancer.getId() + " while adding cert"); |
| } |
| 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 InvalidParameterException("Invalid load balancer value: " + lbRuleId); |
| } |
| |
| if (lbCertMap == null) { |
| throw new InvalidParameterException("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 id " + lbRuleId); |
| CloudRuntimeException ex = new CloudRuntimeException("Failed to remove certificate load balancer rule id " + lbRuleId); |
| 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("Rolled back certificate removal lb id " + lbRuleId); |
| } |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); |
| if (!success) { |
| CloudRuntimeException ex = new CloudRuntimeException("Failed to remove certificate from load balancer rule id " + lbRuleId); |
| 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 InvalidParameterException("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 id " + loadBalancerId + ", vmId " + instanceId); |
| |
| } else { |
| for (String vmIp: lbVmIps) { |
| LoadBalancerVMMapVO map = _lb2VmMapDao.findByLoadBalancerIdAndVmIdVmIp (loadBalancerId, instanceId, vmIp); |
| if (map == null) { |
| throw new InvalidParameterValueException("The instance id: "+ instanceId +" is not configured " |
| + " for LB rule id " + loadBalancerId); |
| } |
| map.setRevoke(true); |
| _lb2VmMapDao.persist(map); |
| logger.debug("Set load balancer rule for revoke: rule id " + loadBalancerId + ", vmId " + |
| instanceId + ", vmip " + vmIp); |
| } |
| } |
| } |
| |
| if (!applyLoadBalancerConfig(loadBalancerId)) { |
| logger.warn("Failed to remove load balancer rule id " + loadBalancerId + " for vms " + 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 id: " + loadBalancerId + ",while removing vmId " + instanceId); |
| }else { |
| for (String vmIp: lbVmIps) { |
| LoadBalancerVMMapVO map = _lb2VmMapDao.findByLoadBalancerIdAndVmIdVmIp (loadBalancerId, instanceId, vmIp); |
| map.setRevoke(true); |
| _lb2VmMapDao.persist(map); |
| logger.debug("LB Rollback rule id: " + loadBalancerId + ",while removing vmId " + |
| instanceId + ", vmip " + vmIp); |
| } |
| } |
| } |
| |
| loadBalancer.setState(backupState); |
| _lbDao.persist(loadBalancer); |
| logger.debug("LB Rollback rule id: " + loadBalancerId + " while removing vm instances"); |
| } |
| 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 id " + map.getLoadBalancerId() + ", vmId " + 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("Unable to remove load balancer rule " + loadBalancerId); |
| } |
| 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("Unable to remove certificate from load balancer rule " + loadBalancerId); |
| } |
| } |
| |
| 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 id " + loadBalancerId + ", vmId " + 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 id: " + loadBalancerId + ", vmId " + map.getInstanceId()); |
| } |
| } |
| lb.setState(backupState); |
| _lbDao.persist(lb); |
| logger.debug("LB Rollback rule id: " + loadBalancerId + " while deleting LB rule."); |
| } 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 id=" + lb.getId() + " as it has related firewall rule id=" + relatedRule.getId() + |
| "; leaving it in Revoke state"); |
| 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 with id " + lb.getId() + " is removed successfully"); |
| |
| 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 id=" + networkId + " so assigning"); |
| 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.getId(), networkId); |
| } |
| } |
| |
| 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); |
| } |
| |
| final IPAddressVO ipAddr = _ipAddressDao.findById(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); |
| |
| LoadBalancerVO newRule = |
| new LoadBalancerVO(xId, name, description, sourceIpId, srcPort, destPort, algorithm, networkId, ipAddr.getAllocatedToAccountId(), |
| ipAddr.getAllocatedInDomainId(), lbProtocol, cidrList); |
| |
| // verify rule is supported by Lb provider of the network |
| Ip sourceIp = getSourceIp(newRule); |
| LoadBalancingRule loadBalancing = |
| new LoadBalancingRule(newRule, new ArrayList<LbDestination>(), new ArrayList<LbStickinessPolicy>(), new ArrayList<LbHealthCheckPolicy>(), sourceIp, null, |
| lbProtocol); |
| if (!validateLbRule(loadBalancing)) { |
| throw new InvalidParameterValueException("LB service provider cannot support this rule"); |
| } |
| |
| return Transaction.execute(new TransactionCallbackWithException<LoadBalancerVO, NetworkRuleConflictException>() { |
| @Override |
| public LoadBalancerVO doInTransaction(TransactionStatus status) throws NetworkRuleConflictException { |
| 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<LbDestination>(), new ArrayList<LbStickinessPolicy>(), new ArrayList<LbHealthCheckPolicy>(), 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 " + newRule.getId() + " for Ip address id=" + sourceIpId + ", public port " + srcPort + ", private port " + destPort + |
| " is added successfully."); |
| 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); |
| } |
| } |
| } |
| }); |
| |
| } |
| |
| @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(long networkId, Scheme scheme) throws ResourceUnavailableException { |
| List<LoadBalancerVO> lbs = _lbDao.listByNetworkIdAndScheme(networkId, scheme); |
| if (logger.isDebugEnabled()) { |
| logger.debug("Revoking " + lbs.size() + " " + scheme + " load balancing rules for network id=" + networkId); |
| } |
| 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 id=" + networkId + " doesn't have load balancer rules, nothing to revoke"); |
| return true; |
| } |
| } |
| |
| @Override |
| public boolean applyLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException { |
| List<LoadBalancerVO> lbs = _lbDao.listByNetworkIdAndScheme(networkId, scheme); |
| if (lbs != null) { |
| logger.debug("Applying load balancer rules of scheme " + scheme + " in network id=" + networkId); |
| return applyLoadBalancerRules(lbs, true); |
| } else { |
| logger.info("Network id=" + networkId + " doesn't have load balancer rules of scheme " + scheme + ", nothing to apply"); |
| 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 " + lb.getId() + " is successfully removed"); |
| checkForReleaseElasticIp = true; |
| } else if (lb.getState() == FirewallRule.State.Add) { |
| lb.setState(FirewallRule.State.Active); |
| logger.debug("LB rule " + lb.getId() + " state is set to Active"); |
| _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 id " + lb.getId() + " is removed for vm " + |
| lbVmMap.getInstanceId() + " instance ip " + lbVmMap.getInstanceIp()); |
| } |
| |
| |
| if (_lb2VmMapDao.listByLoadBalancerId(lb.getId()).isEmpty()) { |
| lb.setState(FirewallRule.State.Add); |
| _lbDao.persist(lb); |
| logger.debug("LB rule " + lb.getId() + " state is set to Add as there are no more active LB-VM mappings"); |
| } |
| |
| // 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 id " + lb.getId() + " is removed stickiness policies"); |
| } |
| |
| // 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 id " + lb.getId() + " is removed health check monitors policies"); |
| } |
| |
| LoadBalancerCertMapVO lbCertMap = _lbCertMapDao.findByLbRuleId(lb.getId()); |
| if (lbCertMap != null && lbCertMap.isRevoke()) { |
| _lbCertMapDao.remove(lbCertMap.getId()); |
| logger.debug("Load balancer rule id " + lb.getId() + " removed certificate mapping"); |
| } |
| |
| 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) { |
| IpAddress ip = _ipAddressDao.findById(lb.getSourceIpAddressId()); |
| _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), 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 " + lb.getSourceIpAddressId() + " as a part of delete lb rule"); |
| if (!_ipAddrMgr.disassociatePublicIpAddress(lb.getSourceIpAddressId(), CallContext.current().getCallingUserId(), CallContext.current().getCallingAccount())) { |
| logger.warn("Unable to release system ip address id=" + lb.getSourceIpAddressId() + " as a part of delete lb rule"); |
| success = false; |
| } else { |
| logger.warn("Successfully released system ip address id=" + lb.getSourceIpAddressId() + " as a part of delete lb rule"); |
| } |
| } |
| 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.getId()); |
| 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.getId()); |
| 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("Modifications in lb rule " + lbRuleId + " are not supported."); |
| } |
| |
| 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 id: " + lbRuleId + " while updating LB rule."); |
| } |
| logger.warn("Unable to apply the load balancer config because resource is unavailable.", e); |
| success = false; |
| } |
| } |
| |
| if (!success) { |
| throw new CloudRuntimeException("Failed to update load balancer rule: " + lbRuleId); |
| } |
| |
| 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 InvalidParameterException("Invalid Load balancer : " + policy.getLoadBalancerId() + " for Stickiness policy id: " + id); |
| } |
| |
| _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 InvalidParameterException("Invalid Load balancer : " + policy.getLoadBalancerId() + " for Stickiness policy id: " + id); |
| } |
| |
| _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; |
| } |
| |
| } |