cloudstack/server/src/com/cloud/network/lb/LoadBalancingRulesManagerIm...

810 lines
32 KiB
Java
Executable File

/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.network.lb;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.api.commands.CreateLoadBalancerRuleCmd;
import com.cloud.api.commands.ListLoadBalancerRuleInstancesCmd;
import com.cloud.api.commands.ListLoadBalancerRulesCmd;
import com.cloud.api.commands.UpdateLoadBalancerRuleCmd;
import com.cloud.dc.dao.VlanDao;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventVO;
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.IPAddressVO;
import com.cloud.network.LoadBalancerVMMapVO;
import com.cloud.network.LoadBalancerVO;
import com.cloud.network.Network.Service;
import com.cloud.network.NetworkManager;
import com.cloud.network.NetworkVO;
import com.cloud.network.dao.FirewallRulesCidrsDao;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.LoadBalancerDao;
import com.cloud.network.dao.LoadBalancerVMMapDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.lb.LoadBalancingRule.LbDestination;
import com.cloud.network.rules.FirewallManager;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.FirewallRule.Purpose;
import com.cloud.network.rules.FirewallRuleVO;
import com.cloud.network.rules.LoadBalancer;
import com.cloud.network.rules.RulesManager;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.DomainService;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Inject;
import com.cloud.utils.component.Manager;
import com.cloud.utils.db.DB;
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.exception.CloudRuntimeException;
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.UserVmDao;
@Local(value = { LoadBalancingRulesManager.class, LoadBalancingRulesService.class })
public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, LoadBalancingRulesService, Manager {
private static final Logger s_logger = Logger.getLogger(LoadBalancingRulesManagerImpl.class);
String _name;
@Inject
NetworkManager _networkMgr;
@Inject
RulesManager _rulesMgr;
@Inject
AccountManager _accountMgr;
@Inject
IPAddressDao _ipAddressDao;
@Inject
LoadBalancerDao _lbDao;
@Inject
VlanDao _vlanDao;
@Inject
EventDao _eventDao;
@Inject
LoadBalancerVMMapDao _lb2VmMapDao;
@Inject
UserVmDao _vmDao;
@Inject
AccountDao _accountDao;
@Inject
DomainDao _domainDao;
@Inject
NicDao _nicDao;
@Inject
UsageEventDao _usageEventDao;
@Inject
FirewallRulesCidrsDao _firewallCidrsDao;
@Inject
FirewallManager _firewallMgr;
@Inject
ElasticLoadBalancerManager _elbMgr;
@Inject
NetworkDao _networkDao;
@Inject
FirewallRulesDao _firewallDao;
@Inject
DomainService _domainMgr;
@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) {
UserContext ctx = UserContext.current();
Account caller = ctx.getCaller();
LoadBalancerVO loadBalancer = _lbDao.findById(loadBalancerId);
if (loadBalancer == null) {
throw new InvalidParameterValueException("Failed to assign to load balancer " + loadBalancerId + ", the load balancer was not found.");
}
List<LoadBalancerVMMapVO> mappedInstances = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId, false);
Set<Long> mappedInstanceIds = new HashSet<Long>();
for (LoadBalancerVMMapVO mappedInstance : mappedInstances) {
mappedInstanceIds.add(Long.valueOf(mappedInstance.getInstanceId()));
}
List<UserVm> vmsToAdd = new ArrayList<UserVm>();
for (Long instanceId : instanceIds) {
if (mappedInstanceIds.contains(instanceId)) {
throw new InvalidParameterValueException("VM " + instanceId + " is already mapped to load balancer.");
}
UserVm vm = _vmDao.findById(instanceId);
if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging) {
throw new InvalidParameterValueException("Invalid instance id: " + instanceId);
}
_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 = _networkMgr.getNics(vm.getId());
Nic nicInSameNetwork = null;
for (Nic nic : nics) {
if (nic.getNetworkId() == loadBalancer.getNetworkId()) {
nicInSameNetwork = nic;
break;
}
}
if (nicInSameNetwork == null) {
throw new InvalidParameterValueException("VM " + instanceId + " cannot be added because it doesn't belong in the same network.");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Adding " + vm + " to the load balancer pool");
}
vmsToAdd.add(vm);
}
Transaction txn = Transaction.currentTxn();
txn.start();
for (UserVm vm : vmsToAdd) {
LoadBalancerVMMapVO map = new LoadBalancerVMMapVO(loadBalancer.getId(), vm.getId(), false);
map = _lb2VmMapDao.persist(map);
}
txn.commit();
try {
loadBalancer.setState(FirewallRule.State.Add);
_lbDao.persist(loadBalancer);
applyLoadBalancerConfig(loadBalancerId);
} catch (ResourceUnavailableException e) {
s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", e);
return false;
}
return true;
}
@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) {
return removeFromLoadBalancerInternal(loadBalancerId, instanceIds);
}
private boolean removeFromLoadBalancerInternal(long loadBalancerId, List<Long> instanceIds) {
UserContext caller = UserContext.current();
LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(loadBalancerId));
if (loadBalancer == null) {
throw new InvalidParameterException("Invalid load balancer value: " + loadBalancerId);
}
_accountMgr.checkAccess(caller.getCaller(), null, loadBalancer);
try {
loadBalancer.setState(FirewallRule.State.Add);
_lbDao.persist(loadBalancer);
for (long instanceId : instanceIds) {
LoadBalancerVMMapVO map = _lb2VmMapDao.findByLoadBalancerIdAndVmId(loadBalancerId, instanceId);
map.setRevoke(true);
_lb2VmMapDao.persist(map);
s_logger.debug("Set load balancer rule for revoke: rule id " + loadBalancerId + ", vmId " + instanceId);
}
if (!applyLoadBalancerConfig(loadBalancerId)) {
s_logger.warn("Failed to remove load balancer rule id " + loadBalancerId + " for vms " + instanceIds);
throw new CloudRuntimeException("Failed to remove load balancer rule id " + loadBalancerId + " for vms " + instanceIds);
}
} catch (ResourceUnavailableException e) {
s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", e);
return false;
}
return true;
}
@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())) {
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) {
UserContext ctx = UserContext.current();
Account caller = ctx.getCaller();
LoadBalancerVO rule = _lbDao.findById(loadBalancerId);
if (rule == null) {
throw new InvalidParameterValueException("Unable to find load balancer rule " + loadBalancerId);
}
_accountMgr.checkAccess(caller, null, rule);
return deleteLoadBalancerRule(loadBalancerId, apply, caller, ctx.getCallerUserId());
}
@DB
public boolean deleteLoadBalancerRule(long loadBalancerId, boolean apply, Account caller, long callerUserId) {
LoadBalancerVO lb = _lbDao.findById(loadBalancerId);
Transaction txn = Transaction.currentTxn();
boolean generateUsageEvent = false;
boolean success = true;
txn.start();
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> 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());
}
}
if (generateUsageEvent) {
// Generate usage event right after all rules were marked for revoke
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), 0, lb.getId(), null);
_usageEventDao.persist(usageEvent);
}
txn.commit();
if (apply) {
try {
if (!applyLoadBalancerConfig(loadBalancerId)) {
s_logger.warn("Unable to apply the load balancer config");
return false;
}
} catch (ResourceUnavailableException e) {
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");
success = false;
} else {
_firewallDao.remove(lb.getId());
}
_elbMgr.handleDeleteLoadBalancerRule(lb, callerUserId, caller);
if (success) {
s_logger.debug("Load balancer with id " + lb.getId() + " is removed successfully");
}
return success;
}
@Override @DB
@ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer")
public LoadBalancer createLoadBalancerRule(CreateLoadBalancerRuleCmd lb, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException {
UserContext caller = UserContext.current();
int defPortStart = lb.getDefaultPortStart();
int defPortEnd = lb.getDefaultPortEnd();
if (!NetUtils.isValidPort(defPortEnd)) {
throw new InvalidParameterValueException("privatePort is an invalid value: " + defPortEnd);
}
if (defPortStart > defPortEnd) {
throw new InvalidParameterValueException("private port range is invalid: " + defPortStart + "-" + defPortEnd);
}
if ((lb.getAlgorithm() == null) || !NetUtils.isValidAlgorithm(lb.getAlgorithm())) {
throw new InvalidParameterValueException("Invalid algorithm: " + lb.getAlgorithm());
}
LoadBalancer result = _elbMgr.handleCreateLoadBalancerRule(lb, caller.getCaller());
if (result == null){
result = createLoadBalancer(lb, openFirewall);
}
return result;
}
@DB
public LoadBalancer createLoadBalancer(CreateLoadBalancerRuleCmd lb, boolean openFirewall) throws NetworkRuleConflictException {
long ipId = lb.getSourceIpAddressId();
UserContext caller = UserContext.current();
int srcPortStart = lb.getSourcePortStart();
int defPortStart = lb.getDefaultPortStart();
int srcPortEnd = lb.getSourcePortEnd();
IPAddressVO ipAddr = _ipAddressDao.findById(lb.getSourceIpAddressId());
Long networkId = ipAddr.getSourceNetworkId();
// make sure ip address exists
if (ipAddr == null || !ipAddr.readyToUse()) {
throw new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id" + ipId);
}
_firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(), Purpose.LoadBalancing);
networkId = ipAddr.getAssociatedWithNetworkId();
if (networkId == null) {
throw new InvalidParameterValueException("Unable to create load balancer rule ; ip id=" + ipId + " is not associated with any network");
}
NetworkVO network = _networkDao.findById(networkId);
_accountMgr.checkAccess(caller.getCaller(), null, ipAddr);
// verify that lb service is supported by the network
if (!_networkMgr.isServiceSupported(network.getNetworkOfferingId(), Service.Lb)) {
throw new InvalidParameterValueException("LB service is not supported in network id= " + networkId);
}
Transaction txn = Transaction.currentTxn();
txn.start();
LoadBalancerVO newRule = new LoadBalancerVO(lb.getXid(), lb.getName(), lb.getDescription(), lb.getSourceIpAddressId(), lb.getSourcePortEnd(), lb.getDefaultPortStart(),
lb.getAlgorithm(), network.getId(), ipAddr.getAccountId(), ipAddr.getDomainId());
newRule = _lbDao.persist(newRule);
if (openFirewall) {
_firewallMgr.createRuleForAllCidrs(ipId, caller.getCaller(), lb.getSourcePortStart(), lb.getSourcePortEnd(), lb.getProtocol(), null, null, newRule.getId());
}
boolean success = true;
try {
_firewallMgr.detectRulesConflict(newRule, ipAddr);
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=" + ipId + ", public port " + srcPortStart + ", private port " + defPortStart + " is added successfully.");
UserContext.current().setEventDetails("Load balancer Id: " + newRule.getId());
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), ipAddr.getDataCenterId(), newRule.getId(), null);
_usageEventDao.persist(usageEvent);
txn.commit();
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) {
txn.start();
_firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false);
_lbDao.remove(newRule.getId());
txn.commit();
}
}
}
@Override
public boolean applyLoadBalancerConfig(long lbRuleId) throws ResourceUnavailableException {
List<LoadBalancerVO> lbs = new ArrayList<LoadBalancerVO>(1);
lbs.add(_lbDao.findById(lbRuleId));
return applyLoadBalancerRules(lbs);
}
@Override
public boolean applyLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException {
List<LoadBalancerVO> lbs = _lbDao.listByNetworkId(networkId);
if (lbs != null) {
return applyLoadBalancerRules(lbs);
} else {
s_logger.info("Network id=" + networkId + " doesn't have load balancer rules, nothing to apply");
return true;
}
}
@DB
protected boolean applyLoadBalancerRules(List<LoadBalancerVO> lbs) throws ResourceUnavailableException {
Transaction txn = Transaction.currentTxn();
List<LoadBalancingRule> rules = new ArrayList<LoadBalancingRule>();
for (LoadBalancerVO lb : lbs) {
List<LbDestination> dstList = getExistingDestinations(lb.getId());
LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList);
rules.add(loadBalancing);
}
if (!_networkMgr.applyRules(rules, false)) {
s_logger.debug("LB rules are not completely applied");
return false;
}
for (LoadBalancerVO lb : lbs) {
txn.start();
if (lb.getState() == FirewallRule.State.Revoke) {
_lbDao.remove(lb.getId());
s_logger.warn("LB " + lb.getId() + " is successfully removed");
} else if (lb.getState() == FirewallRule.State.Add) {
lb.setState(FirewallRule.State.Active);
s_logger.warn("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());
}
if (!instanceIds.isEmpty()) {
_lb2VmMapDao.remove(lb.getId(), instanceIds, null);
s_logger.debug("Load balancer rule id " + lb.getId() + " is removed for vms " + instanceIds);
}
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");
}
txn.commit();
}
return true;
}
@Override
public boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId) {
List<FirewallRuleVO> rules = _firewallDao.listByIpAndPurposeAndNotRevoked(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);
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);
if (result == false) {
s_logger.warn("Unable to remove load balancer rule " + rule.getId());
return false;
}
}
return true;
}
@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 = nic.getIp4Address();
LbDestination lbDst = new LbDestination(lb.getDefaultPortStart(), lb.getDefaultPortEnd(), dstIp, lbVmMap.isRevoke());
dstList.add(lbDst);
}
return dstList;
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
_name = name;
return true;
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public String getName() {
return _name;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_UPDATE, eventDescription = "updating load balancer", async = true)
public LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd) {
Long lbRuleId = cmd.getId();
String name = cmd.getLoadBalancerName();
String description = cmd.getDescription();
String algorithm = cmd.getAlgorithm();
LoadBalancerVO lb = _lbDao.findById(lbRuleId);
if (name != null) {
lb.setName(name);
}
if (description != null) {
lb.setDescription(description);
}
if (algorithm != null) {
lb.setAlgorithm(algorithm);
}
_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) {
s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", e);
}
}
return lb;
}
@Override
public List<UserVmVO> listLoadBalancerInstances(ListLoadBalancerRuleInstancesCmd cmd) throws PermissionDeniedException {
Account caller = UserContext.current().getCaller();
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, loadBalancer);
List<UserVmVO> loadBalancerInstances = new ArrayList<UserVmVO>();
List<LoadBalancerVMMapVO> vmLoadBalancerMappings = null;
vmLoadBalancerMappings = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId);
List<Long> appliedInstanceIdList = new ArrayList<Long>();
if ((vmLoadBalancerMappings != null) && !vmLoadBalancerMappings.isEmpty()) {
for (LoadBalancerVMMapVO vmLoadBalancerMapping : vmLoadBalancerMappings) {
appliedInstanceIdList.add(vmLoadBalancerMapping.getInstanceId());
}
}
IPAddressVO addr = _ipAddressDao.findById(loadBalancer.getSourceIpAddressId());
List<UserVmVO> userVms = _vmDao.listVirtualNetworkInstancesByAcctAndZone(loadBalancer.getAccountId(), addr.getDataCenterId(), 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);
}
}
return loadBalancerInstances;
}
@Override
public List<LoadBalancerVO> searchForLoadBalancers(ListLoadBalancerRulesCmd cmd) {
Account caller = UserContext.current().getCaller();
Long ipId = cmd.getPublicIpId();
Long zoneId = cmd.getZoneId();
String path = null;
Pair<String, Long> accountDomainPair = _accountMgr.finalizeAccountDomainForList(caller, cmd.getAccountName(), cmd.getDomainId());
String accountName = accountDomainPair.first();
Long domainId = accountDomainPair.second();
if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) {
Domain domain = _domainMgr.getDomain(caller.getDomainId());
path = domain.getPath();
}
Filter searchFilter = new Filter(LoadBalancerVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
Object id = cmd.getId();
Object name = cmd.getLoadBalancerRuleName();
Object keyword = cmd.getKeyword();
Object instanceId = cmd.getVirtualMachineId();
SearchBuilder<LoadBalancerVO> sb = _lbDao.createSearchBuilder();
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("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
sb.and("domainId", sb.entity().getDomainId(), 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 (path != null) {
// for domain admin we should show only subdomains information
SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
sb.join("domainSearch", domainSearch, sb.entity().getDomainId(), domainSearch.entity().getId(), 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);
}
SearchCriteria<LoadBalancerVO> sc = sb.create();
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 (domainId != null) {
sc.setParameters("domainId", domainId);
if (accountName != null) {
Account account = _accountMgr.getActiveAccountByName(accountName, domainId);
sc.setParameters("accountId", account.getId());
}
}
if (path != null) {
sc.setJoinParameters("domainSearch", "path", path + "%");
}
if (zoneId != null) {
sc.setJoinParameters("ipSearch", "zoneId", zoneId);
}
return _lbDao.search(sc, searchFilter);
}
@Override
public List<LoadBalancingRule> listByNetworkId(long networkId) {
List<LoadBalancerVO> lbs = _lbDao.listByNetworkId(networkId);
List<LoadBalancingRule> lbRules = new ArrayList<LoadBalancingRule>();
for (LoadBalancerVO lb : lbs) {
List<LbDestination> dstList = getExistingDestinations(lb.getId());
LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList);
lbRules.add(loadBalancing);
}
return lbRules;
}
@Override
public LoadBalancerVO findById(long lbId) {
return _lbDao.findById(lbId);
}
}