From fae6fa790c1fe7826826f9a50d9be3bfc5b36bff Mon Sep 17 00:00:00 2001 From: Chiradeep Vittal Date: Thu, 28 Jul 2011 00:15:16 -0700 Subject: [PATCH] ELB VM: implement delete LB by deleting ELB vm in the future we will manage a pool of vms more intelligently --- .../com/cloud/network/ElasticLbVmMapVO.java | 3 +- .../element/ElasticLoadBalancerElement.java | 9 -- .../lb/ElasticLoadBalancerManagerImpl.java | 90 +++++++++++++------ .../lb/LoadBalancingRulesManagerImpl.java | 5 +- .../network/lb/dao/ElasticLbVmMapDao.java | 2 + .../network/lb/dao/ElasticLbVmMapDaoImpl.java | 26 +++++- .../cloud/network/dao/ElbVmMapDaoTest.java | 15 +++- setup/db/create-schema.sql | 2 +- 8 files changed, 107 insertions(+), 45 deletions(-) diff --git a/server/src/com/cloud/network/ElasticLbVmMapVO.java b/server/src/com/cloud/network/ElasticLbVmMapVO.java index 394f3ac2793..2c71309868e 100644 --- a/server/src/com/cloud/network/ElasticLbVmMapVO.java +++ b/server/src/com/cloud/network/ElasticLbVmMapVO.java @@ -62,9 +62,10 @@ public class ElasticLbVmMapVO { public ElasticLbVmMapVO() { } - public ElasticLbVmMapVO(long ipId, long elbVmId) { + public ElasticLbVmMapVO(long ipId, long elbVmId, long lbId) { this.ipAddressId = ipId; this.elbVmId = elbVmId; + this.lbId = lbId; } public Long getId() { diff --git a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java index 40deb28930f..8b5a702f02a 100644 --- a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java @@ -26,33 +26,24 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; -import com.cloud.api.commands.CreateLoadBalancerRuleCmd; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; -import com.cloud.network.NetworkVO; import com.cloud.network.Network.Capability; -import com.cloud.network.Network.GuestIpType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.NetworkManager; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PublicIpAddress; -import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.NetworkDao; import com.cloud.network.lb.ElasticLoadBalancerManager; -import com.cloud.network.lb.LoadBalancerElement; import com.cloud.network.rules.FirewallRule; import com.cloud.offering.NetworkOffering; -import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; -import com.cloud.user.Account; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Inject; import com.cloud.vm.NicProfile; diff --git a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index 7ab5fc76fdf..04d75e41fd2 100644 --- a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -21,6 +21,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import javax.ejb.Local; import javax.naming.ConfigurationException; @@ -30,17 +33,14 @@ import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.api.Answer; -import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.routing.NetworkElementCommand; -import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.manager.Commands; import com.cloud.api.commands.CreateLoadBalancerRuleCmd; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; import com.cloud.dc.Pod; import com.cloud.dc.PodVlanMapVO; import com.cloud.dc.Vlan.VlanType; @@ -65,9 +65,9 @@ import com.cloud.network.IPAddressVO; import com.cloud.network.LoadBalancerVO; import com.cloud.network.Network; import com.cloud.network.Network.GuestIpType; -import com.cloud.network.Networks.TrafficType; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkVO; +import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.LoadBalancerDao; @@ -80,6 +80,7 @@ import com.cloud.network.router.VirtualRouter.Role; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.security.SecurityGroupManagerImpl.WorkerThread; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -96,11 +97,12 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.Inject; import com.cloud.utils.component.Manager; +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; 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.vm.DomainRouterVO; import com.cloud.vm.NicProfile; import com.cloud.vm.VirtualMachine; @@ -173,6 +175,7 @@ public class ElasticLoadBalancerManagerImpl implements Account _systemAcct; ServiceOfferingVO _elasticLbVmOffering; + ScheduledExecutorService _gcThreadPool; int _elasticLbVmRamSize; int _elasticLbvmCpuMHz; @@ -247,7 +250,6 @@ public class ElasticLoadBalancerManagerImpl implements private void createApplyLoadBalancingRulesCommands( List rules, DomainRouterVO router, Commands cmds) { - String elbIp = ""; LoadBalancerTO[] lbs = new LoadBalancerTO[rules.size()]; int i = 0; @@ -257,7 +259,7 @@ public class ElasticLoadBalancerManagerImpl implements String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); - elbIp = _networkMgr.getIp(rule.getSourceIpAddressId()).getAddress() + String elbIp = _networkMgr.getIp(rule.getSourceIpAddressId()).getAddress() .addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); @@ -366,6 +368,8 @@ public class ElasticLoadBalancerManagerImpl implements _frontendTrafficType = TrafficType.Public; } else throw new ConfigurationException("Traffic type for front end of load balancer has to be guest or public; found : " + traffType); + _gcThreadPool = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ELBVM-GC")); + _gcThreadPool.scheduleAtFixedRate(new CleanupThread(), 30, 30, TimeUnit.SECONDS); } @@ -470,6 +474,20 @@ public class ElasticLoadBalancerManagerImpl implements } } + + private DomainRouterVO stop(DomainRouterVO elbVm, boolean forced, User user, Account caller) throws ConcurrentOperationException, ResourceUnavailableException { + s_logger.debug("Stopping elb vm " + elbVm); + try { + if (_itMgr.advanceStop( elbVm, forced, user, caller)) { + return _routerDao.findById(elbVm.getId()); + } else { + return null; + } + } catch (OperationTimedoutException e) { + throw new CloudRuntimeException("Unable to stop " + elbVm, e); + } + } + protected List findExistingLoadBalancers(String lbName, Long ipId, Long accountId, Long domainId, Integer publicPort) { SearchBuilder sb = _lbDao.createSearchBuilder(); sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); @@ -583,6 +601,7 @@ public class ElasticLoadBalancerManagerImpl implements if (newIp) { releaseIp(ipId, UserContext.current().getCallerUserId(), account); } + throw e; } DomainRouterVO elbVm = null; @@ -614,7 +633,7 @@ public class ElasticLoadBalancerManagerImpl implements return null; } - ElasticLbVmMapVO mapping = new ElasticLbVmMapVO(ipId, elbVm.getId()); + ElasticLbVmMapVO mapping = new ElasticLbVmMapVO(ipId, elbVm.getId(), result.getId()); _elbVmMapDao.persist(mapping); return result; @@ -626,25 +645,42 @@ public class ElasticLoadBalancerManagerImpl implements } - private void createAssociateIPCommand(final DomainRouterVO router, final Network network, final PublicIp ip, Commands cmds) { - - - IpAddressTO[] ipsToSend = new IpAddressTO[1]; - - IpAddressTO ipTO = new IpAddressTO(ip.getAddress().addr(), true, false, false, ip.getVlanTag(), ip.getVlanGateway(), ip.getVlanNetmask(), ip.getMacAddress(), null, 0); - ipTO.setTrafficType(network.getTrafficType()); - ipTO.setNetworkTags(network.getTags()); - ipsToSend[0] = ipTO; - - IpAssocCommand cmd = new IpAssocCommand(ipsToSend); - cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); - cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, router.getGuestIpAddress()); - cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); - DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); - cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); - - cmds.addCommand("IPAssocCommand", cmd); - + void garbageCollectUnusedElbVms() { + List unusedElbVms = _elbVmMapDao.listUnusedElbVms(); + if (unusedElbVms != null && unusedElbVms.size() > 0) + s_logger.info("Found " + unusedElbVms.size() + " unused ELB vms"); + else + return; + User user = _accountService.getSystemUser(); + for (DomainRouterVO elbVm : unusedElbVms) { + try { + s_logger.info("Attempting to stop ELB VM: " + elbVm); + stop(elbVm, true, user, _systemAcct); + } catch (ConcurrentOperationException e) { + s_logger.warn("Unable to stop unused elb vm " + elbVm + " due to ", e); + continue; + } catch (ResourceUnavailableException e) { + s_logger.warn("Unable to stop unused elb vm " + elbVm + " due to ", e); + continue; + } + try { + s_logger.info("Attempting to destroy ELB VM: " + elbVm); + _itMgr.expunge(elbVm, user, _systemAcct); + } catch (ResourceUnavailableException e) { + s_logger.warn("Unable to destroy unused elb vm " + elbVm + " due to ", e); + } + } } + + public class CleanupThread implements Runnable { + @Override + public void run() { + garbageCollectUnusedElbVms(); + + } + CleanupThread() { + + } + } } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 68e1f9c2e7d..0cf659d0a11 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -51,8 +51,6 @@ 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; -import com.cloud.network.Network.GuestIpType; import com.cloud.network.Network.Service; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkVO; @@ -61,7 +59,6 @@ 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.element.NetworkElement; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; @@ -335,7 +332,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, } txn.commit(); - + if (apply) { try { if (!applyLoadBalancerConfig(loadBalancerId)) { diff --git a/server/src/com/cloud/network/lb/dao/ElasticLbVmMapDao.java b/server/src/com/cloud/network/lb/dao/ElasticLbVmMapDao.java index 50729f5647c..9a8921cb0f7 100644 --- a/server/src/com/cloud/network/lb/dao/ElasticLbVmMapDao.java +++ b/server/src/com/cloud/network/lb/dao/ElasticLbVmMapDao.java @@ -22,6 +22,7 @@ import java.util.List; import com.cloud.network.ElasticLbVmMapVO; import com.cloud.utils.db.GenericDao; +import com.cloud.vm.DomainRouterVO; public interface ElasticLbVmMapDao extends GenericDao { ElasticLbVmMapVO findOneByLbIdAndElbVmId(long lbId, long elbVmId); @@ -31,5 +32,6 @@ public interface ElasticLbVmMapDao extends GenericDao { List listByElbVmId(long elbVmId); List listByLbId(long lbId); int deleteLB(long lbId); + List listUnusedElbVms(); } diff --git a/server/src/com/cloud/network/lb/dao/ElasticLbVmMapDaoImpl.java b/server/src/com/cloud/network/lb/dao/ElasticLbVmMapDaoImpl.java index 71a5d4b5663..bd06aa7e017 100644 --- a/server/src/com/cloud/network/lb/dao/ElasticLbVmMapDaoImpl.java +++ b/server/src/com/cloud/network/lb/dao/ElasticLbVmMapDaoImpl.java @@ -23,13 +23,23 @@ import java.util.List; import javax.ejb.Local; import com.cloud.network.ElasticLbVmMapVO; +import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.DomainRouterDaoImpl; @Local(value={ElasticLbVmMapDao.class}) public class ElasticLbVmMapDaoImpl extends GenericDaoBase implements ElasticLbVmMapDao { - private SearchBuilder AllFieldsSearch; + protected final DomainRouterDao _routerDao = ComponentLocator.inject(DomainRouterDaoImpl.class); + + protected final SearchBuilder AllFieldsSearch; + protected final SearchBuilder UnusedVmSearch; + + protected final SearchBuilder ElbVmSearch; protected ElasticLbVmMapDaoImpl() { AllFieldsSearch = createSearchBuilder(); @@ -37,7 +47,15 @@ public class ElasticLbVmMapDaoImpl extends GenericDaoBase listUnusedElbVms() { + SearchCriteria sc = ElbVmSearch.create(); + return _routerDao.search(sc, null); + } } diff --git a/server/test/com/cloud/network/dao/ElbVmMapDaoTest.java b/server/test/com/cloud/network/dao/ElbVmMapDaoTest.java index 50dd7aefcf3..ff1b3ec5f60 100644 --- a/server/test/com/cloud/network/dao/ElbVmMapDaoTest.java +++ b/server/test/com/cloud/network/dao/ElbVmMapDaoTest.java @@ -1,13 +1,16 @@ package com.cloud.network.dao; +import java.util.List; + import junit.framework.TestCase; import com.cloud.network.ElasticLbVmMapVO; import com.cloud.network.lb.dao.ElasticLbVmMapDaoImpl; import com.cloud.utils.component.ComponentLocator; +import com.cloud.vm.DomainRouterVO; public class ElbVmMapDaoTest extends TestCase { - public void testTags() { + public void testFindByIp() { ElasticLbVmMapDaoImpl dao = ComponentLocator.inject(ElasticLbVmMapDaoImpl.class); ElasticLbVmMapVO map = dao.findOneByIp(3); @@ -17,4 +20,14 @@ public class ElbVmMapDaoTest extends TestCase { System.out.println("Found"); } } + public void testFindUnused() { + ElasticLbVmMapDaoImpl dao = ComponentLocator.inject(ElasticLbVmMapDaoImpl.class); + + List map = dao.listUnusedElbVms(); + if (map == null) { + System.out.println("Not Found"); + } else { + System.out.println("Found"); + } + } } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 329edd072bb..1d6c9aadfb5 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -1550,7 +1550,7 @@ CREATE TABLE `cloud`.`elastic_lb_vm_map` ( PRIMARY KEY (`id`), CONSTRAINT `fk_elastic_lb_vm_map__ip_id` FOREIGN KEY `fk_elastic_lb_vm_map__ip_id` (`ip_addr_id`) REFERENCES `user_ip_address` (`id`) ON DELETE CASCADE, CONSTRAINT `fk_elastic_lb_vm_map__elb_vm_id` FOREIGN KEY `fk_elastic_lb_vm_map__elb_vm_id` (`elb_vm_id`) REFERENCES `domain_router` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_elastic_lb_vm_map__lb_id` FOREIGN KEY `fk_elastic_lb_vm_map__lb_id` (`lb_id`) REFERENCES `load_balancing_rules` (`id`) + CONSTRAINT `fk_elastic_lb_vm_map__lb_id` FOREIGN KEY `fk_elastic_lb_vm_map__lb_id` (`lb_id`) REFERENCES `load_balancing_rules` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; SET foreign_key_checks = 1;