// 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 org.apache.cloudstack.api.ApiConstants; 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.log4j.Logger; 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.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.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 { private static final Logger s_logger = Logger.getLogger(LoadBalancingRulesManagerImpl.class); @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 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 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; // 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, String 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()); Long autoscaleUserId = autoScaleVmProfile.getAutoScaleUserId(); User user = _userDao.findByIdIncludingRemoved(autoscaleUserId); String apiKey = user.getApiKey(); String secretKey = user.getSecretKey(); String csUrl = ApiServiceConfiguration.ApiServletPath.value(); 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 s_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(); } } if (apiKey == null) { throw new InvalidParameterValueException("apiKey for user: " + user.getUsername() + " is empty. Please generate it"); } if (secretKey == null) { throw new InvalidParameterValueException("secretKey for user: " + user.getUsername() + " is empty. Please generate it"); } if (csUrl == null || csUrl.contains("localhost")) { throw new InvalidParameterValueException("Global setting endpointe.url has to be set to the Management Server's API end point"); } LbAutoScaleVmProfile lbAutoScaleVmProfile = new LbAutoScaleVmProfile(autoScaleVmProfile, apiKey, secretKey, csUrl, zoneId, domainId, serviceOfferingId, templateId, vmName, lbNetworkUuid); return new LbAutoScaleVmGroup(vmGroup, autoScalePolicies, lbAutoScaleVmProfile, currentState); } private boolean applyAutoScaleConfig(LoadBalancerVO lb, AutoScaleVmGroupVO vmGroup, String 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(rules, false)) { s_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, String 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.setState(FirewallRule.State.Add); _lbDao.persist(loadBalancer); } else if (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) { s_logger.warn("Unable to configure AutoScaleVmGroup to the lb rule: " + loadBalancer.getId() + " because resource is unavaliable:", e); if (isRollBackAllowedForProvider(loadBalancer)) { loadBalancer.setState(backupState); _lbDao.persist(loadBalancer); s_logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " lb state rolback while creating AutoscaleVmGroup"); } throw e; } finally { if (!success) { s_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); s_logger.debug("LB rule " + loadBalancer.getId() + " state is set to Active"); _lbDao.persist(loadBalancer); vmGroup.setState(AutoScaleVmGroup.State_Enabled); _autoScaleVmGroupDao.persist(vmGroup); s_logger.debug("LB Auto Scale Vm Group with Id: " + vmGroupid + " is set to Enabled state."); } }); } s_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) { s_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()); } 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) { s_logger.warn("Unable to apply Stickiness policy to the lb rule: " + cmd.getLbRuleId() + " because resource is unavaliable:", e); if (isRollBackAllowedForProvider(loadBalancer)) { loadBalancer.setState(backupState); _lbDao.persist(loadBalancer); deleteLBStickinessPolicy(cmd.getEntityId(), false); s_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) { s_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()); } FirewallRule.State backupState = loadBalancer.getState(); loadBalancer.setState(FirewallRule.State.Add); _lbDao.persist(loadBalancer); try { applyLoadBalancerConfig(cmd.getLbRuleId()); } catch (ResourceUnavailableException e) { s_logger.warn("Unable to apply healthcheck policy to the lb rule: " + cmd.getLbRuleId() + " because resource is unavaliable:", e); if (isRollBackAllowedForProvider(loadBalancer)) { loadBalancer.setState(backupState); _lbDao.persist(loadBalancer); s_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); s_logger.debug("Set load balancer rule for revoke: rule id " + loadBalancerId + ", stickinesspolicyID " + stickinessPolicyId); try { if (!applyLoadBalancerConfig(loadBalancerId)) { s_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); s_logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " while deleting sticky policy: " + stickinessPolicyId); } s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", 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); s_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) { s_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)) { s_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); s_logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " while deleting healthcheck policy: " + healthCheckPolicyId); } s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", 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")) { /* * s_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()); // adding to lbrules list only if the LB rule // hashealtChecks if (hcPolicyList != null && hcPolicyList.size() > 0) { 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); s_logger.debug("Updating the LB VM Map table with the service state"); } } } } isHandled = true; } if (isHandled) { break; } } } } } else { // s_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) { 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) { 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 (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); if (vm.getAccountId() != loadBalancer.getAccountId()) { throw new PermissionDeniedException("Cannot add virtual machines that do not belong to the same owner."); } // 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 (s_logger.isDebugEnabled()) { s_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)) { // For autoscaled 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) { s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", 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); s_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) { s_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) { return removeFromLoadBalancerInternal(loadBalancerId, instanceIds, true, vmIdIpsMap); } @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) { s_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()); s_logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " while adding cert"); } s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", 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)) { s_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); s_logger.debug("Rolled back certificate removal lb id " + lbRuleId); } s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", 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) { 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(); 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); } s_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); s_logger.debug("Set load balancer rule for revoke: rule id " + loadBalancerId + ", vmId " + instanceId + ", vmip " + vmIp); } } } if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(loadBalancerId)) { // For autoscaled loadbalancer, the rules need not be applied, // meaning the call need not reach the resource layer. // We can consider the job done and only need to remove the // rules in DB _lb2VmMapDao.remove(loadBalancer.getId(), instanceIds, null); return true; } if (!applyLoadBalancerConfig(loadBalancerId)) { s_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; } 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); s_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); s_logger.debug("LB Rollback rule id: " + loadBalancerId + ",while removing vmId " + instanceId + ", vmip " + vmIp); } } } loadBalancer.setState(backupState); _lbDao.persist(loadBalancer); s_logger.debug("LB Rollback rule id: " + loadBalancerId + " while removing vm instances"); } s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", 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); s_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<Long, List<String>>())) { 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) { 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 (s_logger.isDebugEnabled()) { s_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); s_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)) { s_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); s_logger.debug("LB Rollback rule id: " + loadBalancerId + ", vmId " + map.getInstanceId()); } } lb.setState(backupState); _lbDao.persist(lb); s_logger.debug("LB Rollback rule id: " + loadBalancerId + " while deleting LB rule."); } else { s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", e); } return false; } } FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(lb.getId()); if (relatedRule != null) { s_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); s_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 { 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; if (result == null) { IpAddress systemIp = null; NetworkOffering off = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId()); if (off.getElasticLb() && 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()); } 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); s_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); } catch (Exception ex) { s_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) { s_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; } @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) 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); // 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); 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); } s_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 (s_logger.isDebugEnabled()) { s_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 { s_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) { s_logger.debug("Applying load balancer rules of scheme " + scheme + " in network id=" + networkId); return applyLoadBalancerRules(lbs, true); } else { s_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)) { s_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); s_logger.debug("LB " + lb.getId() + " is successfully removed"); checkForReleaseElasticIp = true; } else if (lb.getState() == FirewallRule.State.Add) { lb.setState(FirewallRule.State.Active); s_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); s_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); s_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); s_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); s_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()); s_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) { s_logger.warn("Failed to release system ip as a part of lb rule " + lb + " deletion due to exception ", ex); success = false; } finally { if (!success) { s_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()) { s_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())) { s_logger.warn("Unable to release system ip address id=" + lb.getSourceIpAddressId() + " as a part of delete lb rule"); success = false; } else { s_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) { s_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) { s_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) { s_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) { s_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(); 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); } // Validate rule in LB provider LoadBalancingRule rule = getLoadBalancerRuleToApply(lb); if (!validateLbRule(rule)) { throw new InvalidParameterValueException("Modifications in lb rule " + lbRuleId + " are not supported."); } boolean success = _lbDao.update(lbRuleId, lb); // If algorithm is changed, have to reapply the lb config if (algorithm != null) { 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); s_logger.debug("LB Rollback rule id: " + lbRuleId + " while updating LB rule."); } s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", 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) { applied = Boolean.TRUE; } LoadBalancerVO loadBalancer = _lbDao.findById(loadBalancerId); if (loadBalancer == null) { return null; } _accountMgr.checkAccess(caller, null, true, loadBalancer); List<UserVmVO> loadBalancerInstances = new ArrayList<UserVmVO>(); List<String> serviceStates = new ArrayList<String>(); List<LoadBalancerVMMapVO> vmLoadBalancerMappings = null; vmLoadBalancerMappings = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId); if(vmLoadBalancerMappings == null) { String msg = "no VM Loadbalancer Mapping found"; s_logger.error(msg); throw new CloudRuntimeException(msg); } Map<Long, String> vmServiceState = new HashMap<Long, String>(vmLoadBalancerMappings.size()); List<Long> appliedInstanceIdList = new ArrayList<Long>(); if ((vmLoadBalancerMappings != null) && !vmLoadBalancerMappings.isEmpty()) { for (LoadBalancerVMMapVO vmLoadBalancerMapping : vmLoadBalancerMappings) { appliedInstanceIdList.add(vmLoadBalancerMapping.getInstanceId()); vmServiceState.put(vmLoadBalancerMapping.getInstanceId(), vmLoadBalancerMapping.getState()); } } List<UserVmVO> userVms = _vmDao.listVirtualNetworkInstancesByAcctAndNetwork(loadBalancer.getAccountId(), loadBalancer.getNetworkId()); 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; } boolean isApplied = appliedInstanceIdList.contains(userVm.getId()); if ((isApplied && applied) || (!isApplied && !applied)) { loadBalancerInstances.add(userVm); serviceStates.add(vmServiceState.get(userVm.getId())); } } return new Pair<List<? extends UserVm>, List<String>>(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.LIKE); 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) { s_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; } s_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.getPublicLb()) { throw new InvalidParameterValueException("Scheme " + scheme + " is not supported by the network offering " + off); } } else { if (!off.getInternalLb()) { 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; } }