diff --git a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java
index fe5a2838be1..1e44db06aeb 100644
--- a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java
+++ b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java
@@ -189,5 +189,13 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd {
@Override
public AsyncJob.Type getInstanceType() {
return AsyncJob.Type.IpAddress;
+ }
+
+ public AssociateIPAddrCmd(String accountName, Long domainId, Long zoneId, Long networkId) {
+ super();
+ this.accountName = accountName;
+ this.domainId = domainId;
+ this.zoneId = zoneId;
+ this.networkId = networkId;
}
}
diff --git a/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java b/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java
index 45bd5d7ed46..78fd2dc823f 100644
--- a/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java
+++ b/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java
@@ -18,6 +18,8 @@
package com.cloud.api.commands;
+import java.util.List;
+
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
@@ -26,10 +28,16 @@ import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.LoadBalancerResponse;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.IpAddress;
import com.cloud.network.rules.LoadBalancer;
+import com.cloud.user.Account;
+import com.cloud.user.UserContext;
import com.cloud.utils.net.NetUtils;
@Implementation(description="Creates a load balancer rule", responseObject=LoadBalancerResponse.class)
@@ -54,13 +62,21 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer
@Parameter(name=ApiConstants.PRIVATE_PORT, type=CommandType.INTEGER, required=true, description="the private port of the private ip address/virtual machine where the network traffic will be load balanced to")
private Integer privatePort;
- @Parameter(name=ApiConstants.PUBLIC_IP_ID, type=CommandType.LONG, required=true, description="public ip address id from where the network traffic will be load balanced from")
+ @Parameter(name=ApiConstants.PUBLIC_IP_ID, type=CommandType.LONG, required=false, description="public ip address id from where the network traffic will be load balanced from")
private Long publicIpId;
+
+ @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required=false, description="public ip address id from where the network traffic will be load balanced from")
+ private Long zoneId;
@Parameter(name=ApiConstants.PUBLIC_PORT, type=CommandType.INTEGER, required=true, description="the public port from where the network traffic will be load balanced from")
private Integer publicPort;
+ @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="the account associated with the load balancer. Must be used with the domainId parameter.")
+ private String accountName;
+ @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="the domain ID associated with the load balancer")
+ private Long domainId;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -86,7 +102,7 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer
public Long getPublicIpId() {
IpAddress ipAddr = _networkService.getIp(publicIpId);
if (ipAddr == null || !ipAddr.readyToUse()) {
- throw new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id" + ipAddr.getId());
+ throw new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id " + ipAddr.getId());
}
return publicIpId;
@@ -109,10 +125,51 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer
return s_name;
}
+ protected LoadBalancer findExistingLB() {
+ List extends LoadBalancer> lbs = _lbService.searchForLoadBalancers(new ListLoadBalancerRulesCmd(getAccountName(), getDomainId(), null, getName(), publicIpId, null, getZoneId()) );
+ if (lbs != null && lbs.size() > 0) {
+ return lbs.get(0);
+ }
+ return null;
+ }
+
+ protected void allocateIp() throws ResourceAllocationException, ResourceUnavailableException {
+ AssociateIPAddrCmd allocIpCmd = new AssociateIPAddrCmd(getAccountName(), getDomainId(), getZoneId(), null);
+ try {
+ IpAddress ip = _networkService.allocateIP(allocIpCmd);
+ if (ip != null) {
+ this.setPublicIpId(ip.getId());
+ allocIpCmd.setEntityId(ip.getId());
+ } else {
+ throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to allocate ip address");
+ }
+ //UserContext.current().setEventDetails("Ip Id: "+ ip.getId());
+ //IpAddress result = _networkService.associateIP(allocIpCmd);
+ } catch (ConcurrentOperationException ex) {
+ s_logger.warn("Exception: ", ex);
+ throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage());
+ } catch (InsufficientAddressCapacityException ex) {
+ s_logger.info(ex);
+ s_logger.trace(ex);
+ throw new ServerApiException(BaseCmd.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
+ }
+ }
+
@Override
- public void execute() {
+ public void execute() throws ResourceAllocationException, ResourceUnavailableException {
LoadBalancer result = null;
try {
+ if (publicIpId == null) {
+ if (getZoneId() == null ) {
+ throw new InvalidParameterValueException("Either zone id or public ip id needs to be specified");
+ }
+ LoadBalancer existing = findExistingLB();
+ if (existing == null) {
+ allocateIp();
+ } else {
+ this.setPublicIpId(existing.getSourceIpAddressId());
+ }
+ }
result = _lbService.createLoadBalancerRule(this);
} catch (NetworkRuleConflictException e) {
s_logger.warn("Exception: ", e);
@@ -171,12 +228,33 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer
@Override
public long getAccountId() {
- return _networkService.getIp(getPublicIpId()).getAccountId();
+ if (publicIpId != null)
+ return _networkService.getIp(getPublicIpId()).getAccountId();
+ Account account = UserContext.current().getCaller();
+ if ((account == null) ) {
+ if ((domainId != null) && (accountName != null)) {
+ Account userAccount = _responseGenerator.findAccountByNameDomain(accountName, domainId);
+ if (userAccount != null) {
+ return userAccount.getId();
+ }
+ }
+ }
+
+ if (account != null) {
+ return account.getId();
+ }
+
+ return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public long getDomainId() {
- return _networkService.getIp(getPublicIpId()).getDomainId();
+ if (publicIpId != null)
+ return _networkService.getIp(getPublicIpId()).getDomainId();
+ if (domainId != null) {
+ return domainId;
+ }
+ return UserContext.current().getCaller().getDomainId();
}
@Override
@@ -192,5 +270,18 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer
@Override
public long getEntityOwnerId() {
return getAccountId();
- }
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ public void setPublicIpId(Long publicIpId) {
+ this.publicIpId = publicIpId;
+ }
+
}
diff --git a/api/src/com/cloud/api/commands/ListLoadBalancerRulesCmd.java b/api/src/com/cloud/api/commands/ListLoadBalancerRulesCmd.java
index 9bded66ae8b..1ceda4854ac 100644
--- a/api/src/com/cloud/api/commands/ListLoadBalancerRulesCmd.java
+++ b/api/src/com/cloud/api/commands/ListLoadBalancerRulesCmd.java
@@ -119,4 +119,15 @@ public class ListLoadBalancerRulesCmd extends BaseListCmd {
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
+
+ public ListLoadBalancerRulesCmd(String accountName, Long domainId, Long id, String loadBalancerRuleName, Long publicIpId, Long virtualMachineId, Long zoneId) {
+ super();
+ this.accountName = accountName;
+ this.domainId = domainId;
+ this.id = id;
+ this.loadBalancerRuleName = loadBalancerRuleName;
+ this.publicIpId = publicIpId;
+ this.virtualMachineId = virtualMachineId;
+ this.zoneId = zoneId;
+ }
}
diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java
index 3287369ce53..9630d48e732 100644
--- a/api/src/com/cloud/network/Network.java
+++ b/api/src/com/cloud/network/Network.java
@@ -93,6 +93,8 @@ public interface Network extends ControlledEntity {
public static final Provider F5BigIp = new Provider("F5BigIp");
public static final Provider ExternalDhcpServer = new Provider("ExternalDhcpServer");
public static final Provider ExternalGateWay = new Provider("ExternalGateWay");
+ public static final Provider ElasticLoadBalancerVm = new Provider("ElasticLoadBalancerVm");
+
public static final Provider None = new Provider("None");
private String name;
diff --git a/api/src/com/cloud/network/router/VirtualRouter.java b/api/src/com/cloud/network/router/VirtualRouter.java
index 32009620c88..624bd928e4c 100755
--- a/api/src/com/cloud/network/router/VirtualRouter.java
+++ b/api/src/com/cloud/network/router/VirtualRouter.java
@@ -26,7 +26,7 @@ import com.cloud.vm.VirtualMachine;
public interface VirtualRouter extends VirtualMachine {
public enum Role {
DHCP_FIREWALL_LB_PASSWD_USERDATA,
- DHCP_USERDATA
+ DHCP_USERDATA, LB
}
Role getRole();
-}
+}
\ No newline at end of file
diff --git a/api/src/com/cloud/network/rules/LoadBalancer.java b/api/src/com/cloud/network/rules/LoadBalancer.java
index 5cee5b7cfe6..40fdc7e34c2 100644
--- a/api/src/com/cloud/network/rules/LoadBalancer.java
+++ b/api/src/com/cloud/network/rules/LoadBalancer.java
@@ -32,5 +32,5 @@ public interface LoadBalancer extends FirewallRule {
int getDefaultPortEnd();
String getAlgorithm();
-
+
}
diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java
index 82b09762016..69fec11a219 100755
--- a/api/src/com/cloud/vm/VirtualMachine.java
+++ b/api/src/com/cloud/vm/VirtualMachine.java
@@ -151,6 +151,8 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, StateObject
DomainRouter,
ConsoleProxy,
SecondaryStorageVm,
+ ElasticIpVm,
+ ElasticLoadBalancerVm,
/*
* UserBareMetal is only used for selecting VirtualMachineGuru, there is no
diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in
index 7d3e1772bca..b83b8df2beb 100755
--- a/client/tomcatconf/components.xml.in
+++ b/client/tomcatconf/components.xml.in
@@ -89,6 +89,8 @@
+
+
diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java
index be2c399bf51..b2259a0e226 100644
--- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java
+++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java
@@ -79,6 +79,7 @@ import com.cloud.network.dao.LoadBalancerVMMapDaoImpl;
import com.cloud.network.dao.NetworkDaoImpl;
import com.cloud.network.dao.NetworkDomainDaoImpl;
import com.cloud.network.dao.NetworkRuleConfigDaoImpl;
+import com.cloud.network.lb.ElasticLoadBalancerManagerImpl;
import com.cloud.network.lb.LoadBalancingRulesManagerImpl;
import com.cloud.network.ovs.OvsNetworkManagerImpl;
import com.cloud.network.ovs.OvsTunnelManagerImpl;
@@ -315,6 +316,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
ComponentInfo extends Manager> info = addManager("ConsoleProxyManager", ConsoleProxyManagerImpl.class);
info.addParameter("consoleproxy.sslEnabled", "true");
addManager("ClusteredAgentManager", ClusteredAgentManagerImpl.class);
+ addManager("ElasticLoadBalancerManager", ElasticLoadBalancerManagerImpl.class);
}
@Override
diff --git a/server/src/com/cloud/dc/DataCenterVO.java b/server/src/com/cloud/dc/DataCenterVO.java
index 301f90b7f60..d8900b9460d 100644
--- a/server/src/com/cloud/dc/DataCenterVO.java
+++ b/server/src/com/cloud/dc/DataCenterVO.java
@@ -205,6 +205,7 @@ public class DataCenterVO implements DataCenter {
dhcpProvider = Provider.DhcpServer.getName();
dnsProvider = Provider.DhcpServer.getName();
userDataProvider = Provider.DhcpServer.getName();
+ loadBalancerProvider = Provider.ElasticLoadBalancerVm.getName();
}
this.zoneToken = zoneToken;
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index 5a64dcba743..6d188b79c7e 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -559,6 +559,16 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
if (zone.getNetworkType() != NetworkType.Basic && network.getAccountId() != ipOwner.getId()) {
throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
}
+ VlanType vlanType = VlanType.VirtualNetwork;
+ boolean assign = false;
+ //For basic zone, if there isn't a public network outside of the guest network, specify the vlan type to be direct attached
+ if (zone.getNetworkType() == NetworkType.Basic) {
+ if (network.getTrafficType() == TrafficType.Guest){
+ vlanType = VlanType.DirectAttached;
+ assign = true;
+ }
+
+ }
PublicIp ip = null;
@@ -601,7 +611,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
}
}
- ip = fetchNewPublicIp(zoneId, null, null, ipOwner, VlanType.VirtualNetwork, network.getId(), isSourceNat, false, null);
+ ip = fetchNewPublicIp(zoneId, null, null, ipOwner, vlanType, network.getId(), isSourceNat, assign, null);
if (ip == null) {
throw new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zoneId);
@@ -754,8 +764,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
defaultGuestNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultGuestNetworkOffering);
NetworkOfferingVO defaultGuestDirectNetworkOffering = new NetworkOfferingVO(NetworkOffering.DefaultDirectNetworkOffering, "Direct", TrafficType.Guest, false, true, null, null, null, true,
Availability.Optional,
- // services - all true except for firewall/lb/vpn and gateway services
- true, true, true, false, false, false, false, GuestIpType.Direct);
+ // services - all true except for firewall/vpn and gateway services
+ true, true, true, false, false, true, false, GuestIpType.Direct);
defaultGuestDirectNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultGuestDirectNetworkOffering);
AccountsUsingNetworkSearch = _accountDao.createSearchBuilder();
diff --git a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java
new file mode 100644
index 00000000000..551a78a9de5
--- /dev/null
+++ b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java
@@ -0,0 +1,144 @@
+/**
+ * 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 .
+ *
+ */
+package com.cloud.network.element;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.configuration.ConfigurationManager;
+import com.cloud.dc.DataCenter;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkManager;
+import com.cloud.network.Network.Capability;
+import com.cloud.network.Network.Provider;
+import com.cloud.network.Network.Service;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.PublicIpAddress;
+import com.cloud.network.lb.ElasticLoadBalancerManager;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.component.Inject;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+
+
+@Local(value=NetworkElement.class)
+public class ElasticLoadBalancerElement extends AdapterBase implements NetworkElement{
+ private static final Logger s_logger = Logger.getLogger(ElasticLoadBalancerElement.class);
+ private static final Map> capabilities = setCapabilities();
+ @Inject ConfigurationManager _configMgr;
+ @Inject NetworkManager _networkManager;
+ @Inject ElasticLoadBalancerManager _lbMgr;
+
+ private boolean canHandle(Network config) {
+ DataCenter zone = _configMgr.getZone(config.getDataCenterId());
+ if (config.getGuestType() != Network.GuestIpType.Virtual || config.getTrafficType() != TrafficType.Guest) {
+ s_logger.trace("Not handling network with guest Type " + config.getGuestType() + " and traffic type " + config.getTrafficType());
+ return false;
+ }
+
+ return (_networkManager.zoneIsConfiguredForExternalNetworking(zone.getId()) &&
+ zone.getLoadBalancerProvider() != null && zone.getLoadBalancerProvider().equals(Network.Provider.F5BigIp.getName()));
+ }
+
+ @Override
+ public Provider getProvider() {
+ return Provider.ElasticLoadBalancerVm;
+ }
+
+ @Override
+ public Map> getCapabilities() {
+ return capabilities;
+ }
+
+ private static Map> setCapabilities() {
+ Map> capabilities = new HashMap>();
+
+ Map lbCapabilities = new HashMap();
+ lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn,source");
+ lbCapabilities.put(Capability.SupportedProtocols, "tcp, udp");
+
+ capabilities.put(Service.Lb, lbCapabilities);
+ return capabilities;
+ }
+
+ @Override
+ public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException,
+ InsufficientCapacityException {
+
+ return true;
+ }
+
+ @Override
+ public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile extends VirtualMachine> vm, DeployDestination dest, ReservationContext context)
+ throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+
+ return true;
+ }
+
+ @Override
+ public boolean release(Network network, NicProfile nic, VirtualMachineProfile extends VirtualMachine> vm, ReservationContext context) throws ConcurrentOperationException,
+ ResourceUnavailableException {
+
+ return true;
+ }
+
+ @Override
+ public boolean shutdown(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
+ // TODO kill all loadbalancer vms by calling the ElasticLoadBalancerManager
+ return false;
+ }
+
+ @Override
+ public boolean restart(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+ // TODO restart all loadbalancer vms by calling the ElasticLoadBalancerManager
+ return false;
+ }
+
+ @Override
+ public boolean destroy(Network network) throws ConcurrentOperationException, ResourceUnavailableException {
+ // TODO kill all loadbalancer vms by calling the ElasticLoadBalancerManager
+ return false;
+ }
+
+ @Override
+ public boolean applyIps(Network network, List extends PublicIpAddress> ipAddress) throws ResourceUnavailableException {
+ return true;
+ }
+
+ @Override
+ public boolean applyRules(Network network, List extends FirewallRule> rules) throws ResourceUnavailableException {
+ if (!canHandle(network)) {
+ return false;
+ }
+
+ return _lbMgr.applyLoadBalancerRules(network, rules);
+ }
+}
diff --git a/server/src/com/cloud/network/lb/ElasticLoadBalancerManager.java b/server/src/com/cloud/network/lb/ElasticLoadBalancerManager.java
new file mode 100644
index 00000000000..4c26d33c87e
--- /dev/null
+++ b/server/src/com/cloud/network/lb/ElasticLoadBalancerManager.java
@@ -0,0 +1,39 @@
+/**
+ * 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 .
+ *
+ */
+package com.cloud.network.lb;
+
+import java.util.List;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.network.lb.LoadBalancingRule.LbDestination;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.user.Account;
+
+public interface ElasticLoadBalancerManager {
+ public static final int DEFAULT_ELB_VM_RAMSIZE = 512; // 512 MB
+ public static final int DEFAULT_ELB_VM_CPU_MHZ = 500; // 500 MHz
+ public long deployLoadBalancerVM(Long networkId, Long accountId);
+
+ public boolean applyLoadBalancerRules(Network network,
+ List extends FirewallRule> rules)
+ throws ResourceUnavailableException;;
+
+}
diff --git a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java
new file mode 100644
index 00000000000..4b9c1520c7b
--- /dev/null
+++ b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java
@@ -0,0 +1,428 @@
+/**
+ * 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 .
+ *
+ */
+package com.cloud.network.lb;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+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.LoadBalancerConfigCommand;
+import com.cloud.agent.api.routing.NetworkElementCommand;
+import com.cloud.agent.api.to.LoadBalancerTO;
+import com.cloud.agent.manager.Commands;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.HostPodVO;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.OperationTimedoutException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.StorageUnavailableException;
+import com.cloud.network.IPAddressVO;
+import com.cloud.network.LoadBalancerVO;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkManager;
+import com.cloud.network.NetworkVO;
+import com.cloud.network.Networks.BroadcastDomainType;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.LoadBalancerDao;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.lb.LoadBalancingRule.LbDestination;
+import com.cloud.network.router.VirtualNetworkApplianceManager;
+import com.cloud.network.router.VirtualRouter;
+import com.cloud.network.router.VirtualRouter.Role;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRule.Purpose;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.org.Cluster;
+import com.cloud.service.ServiceOfferingVO;
+import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import com.cloud.user.User;
+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.db.DB;
+import com.cloud.vm.DomainRouterVO;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.VirtualMachineManager;
+import com.cloud.vm.VirtualMachineName;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.VirtualMachineProfile.Param;
+import com.cloud.vm.dao.DomainRouterDao;
+
+@Local(value = { ElasticLoadBalancerManager.class })
+public class ElasticLoadBalancerManagerImpl implements
+ ElasticLoadBalancerManager, Manager {
+ private static final Logger s_logger = Logger
+ .getLogger(ElasticLoadBalancerManagerImpl.class);
+
+ @Inject
+ IPAddressDao _ipAddressDao;
+ @Inject
+ AgentManager _agentMgr;
+ @Inject
+ NetworkManager _networkMgr;
+ @Inject
+ LoadBalancerDao _loadBalancerDao = null;
+ @Inject
+ LoadBalancingRulesManager _lbMgr;
+ @Inject
+ VirtualNetworkApplianceManager _routerMgr;
+ @Inject
+ DomainRouterDao _routerDao = null;
+ @Inject
+ protected HostPodDao _podDao = null;
+ @Inject
+ protected ClusterDao _clusterDao;
+ @Inject
+ DataCenterDao _dcDao = null;
+ @Inject
+ protected NetworkDao _networkDao;
+ @Inject
+ protected NetworkOfferingDao _networkOfferingDao;
+ @Inject
+ VMTemplateDao _templateDao = null;
+ @Inject
+ VirtualMachineManager _itMgr;
+ @Inject
+ ConfigurationDao _configDao;
+ @Inject
+ ServiceOfferingDao _serviceOfferingDao = null;
+ @Inject
+ AccountService _accountService;
+
+
+ String _name;
+ String _instance;
+
+ Account _systemAcct;
+ ServiceOfferingVO _elasticLbVmOffering;
+
+ int _elasticLbVmRamSize;
+ int _elasticLbvmCpuMHz;
+
+
+
+
+ public long deployLoadBalancerVM(Long networkId, Long accountId) { /* ELB_TODO :need to remove hardcoded network id,account id,pod id , cluster id */
+ NetworkVO network = _networkDao.findById(networkId);
+
+ DataCenter dc = _dcDao.findById(network.getDataCenterId());
+
+ Map params = new HashMap(
+ 1);
+ params.put(VirtualMachineProfile.Param.RestartNetwork, true);
+ Account owner = _accountService.getActiveAccount("system", new Long(1));
+ DeployDestination dest = new DeployDestination(dc, null, null, null);
+
+ s_logger.debug("About to deploy elastic LB vm if necessary");
+
+ try {
+ VirtualRouter elbVm = deployELBVm(network, dest, owner, params);
+
+ s_logger.debug("ELB vm = " + elbVm);
+ if (elbVm == null) {
+ throw new InvalidParameterValueException("No VM with id '"
+ + elbVm + "' found.");
+ }
+ DomainRouterVO elbRouterVm = _routerDao.findById(elbVm.getId());
+ String publicIp = elbRouterVm.getGuestIpAddress();
+ IPAddressVO ipvo = _ipAddressDao.findByIpAndSourceNetworkId(networkId, publicIp);
+ ipvo.setAssociatedWithNetworkId(networkId);
+ _ipAddressDao.update(ipvo.getId(), ipvo);
+ return ipvo.getId();
+ } catch (Throwable t) {
+ String errorMsg = "Error while deploying Loadbalancer VM: " + t;
+ s_logger.warn(errorMsg);
+ return 0;
+ }
+
+ }
+
+ private boolean sendCommandsToRouter(final DomainRouterVO router,
+ Commands cmds) throws AgentUnavailableException {
+ Answer[] answers = null;
+ try {
+ answers = _agentMgr.send(router.getHostId(), cmds);
+ } catch (OperationTimedoutException e) {
+ s_logger.warn("Timed Out", e);
+ throw new AgentUnavailableException(
+ "Unable to send commands to virtual router ",
+ router.getHostId(), e);
+ }
+
+ if (answers == null) {
+ return false;
+ }
+
+ if (answers.length != cmds.size()) {
+ return false;
+ }
+
+ // FIXME: Have to return state for individual command in the future
+ if (answers.length > 0) {
+ Answer ans = answers[0];
+ return ans.getResult();
+ }
+ return true;
+ }
+
+ private void createApplyLoadBalancingRulesCommands(
+ List rules, DomainRouterVO router, Commands cmds) {
+
+ String elbIp = "";
+
+ LoadBalancerTO[] lbs = new LoadBalancerTO[rules.size()];
+ int i = 0;
+ for (LoadBalancingRule rule : rules) {
+ boolean revoked = (rule.getState()
+ .equals(FirewallRule.State.Revoke));
+ String protocol = rule.getProtocol();
+ String algorithm = rule.getAlgorithm();
+
+ elbIp = _networkMgr.getIp(rule.getSourceIpAddressId()).getAddress()
+ .addr();
+ int srcPort = rule.getSourcePortStart();
+ List destinations = rule.getDestinations();
+ LoadBalancerTO lb = new LoadBalancerTO(elbIp, srcPort, protocol,
+ algorithm, revoked, false, destinations);
+ lbs[i++] = lb;
+ }
+
+ LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs);
+ cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP,
+ router.getPrivateIpAddress());
+ cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME,
+ router.getInstanceName());
+ cmds.addCommand(cmd);
+
+ }
+
+ protected boolean applyLBRules(DomainRouterVO router,
+ List rules) throws ResourceUnavailableException {
+ Commands cmds = new Commands(OnError.Continue);
+ createApplyLoadBalancingRulesCommands(rules, router, cmds);
+ // Send commands to router
+ return sendCommandsToRouter(router, cmds);
+ }
+
+ public boolean applyLoadBalancerRules(Network network,
+ List extends FirewallRule> rules)
+ throws ResourceUnavailableException {
+ DomainRouterVO router = _routerDao.findByNetwork(network.getId());/* ELB_TODO :may have multiple LB's , need to get the correct LB based on network id and account id */
+
+ if (router == null) {
+ s_logger.warn("Unable to apply lb rules, virtual router doesn't exist in the network "
+ + network.getId());
+ throw new ResourceUnavailableException("Unable to apply lb rules",
+ DataCenter.class, network.getDataCenterId());
+ }
+
+ if (router.getState() == State.Running) {
+ if (rules != null && !rules.isEmpty()) {
+ if (rules.get(0).getPurpose() == Purpose.LoadBalancing) {
+ // for elastic load balancer we have to resend all lb rules
+ // belonging to same sourceIpAddressId for the network
+ List lbs = _loadBalancerDao
+ .listByNetworkId(network.getId());
+ List lbRules = new ArrayList();
+ for (LoadBalancerVO lb : lbs) {
+ if (lb.getSourceIpAddressId() == rules.get(0)
+ .getSourceIpAddressId()) {
+ List dstList = _lbMgr
+ .getExistingDestinations(lb.getId());
+ LoadBalancingRule loadBalancing = new LoadBalancingRule(
+ lb, dstList);
+ lbRules.add(loadBalancing);
+ }
+ }
+
+ return applyLBRules(router, lbRules);
+ } else {
+ s_logger.warn("Unable to apply rules of purpose: "
+ + rules.get(0).getPurpose());
+ return false;
+ }
+ } else {
+ return true;
+ }
+ } else if (router.getState() == State.Stopped
+ || router.getState() == State.Stopping) {
+ s_logger.debug("Router is in "
+ + router.getState()
+ + ", so not sending apply firewall rules commands to the backend");
+ return true;
+ } else {
+ s_logger.warn("Unable to apply firewall rules, virtual router is not in the right state "
+ + router.getState());
+ throw new ResourceUnavailableException(
+ "Unable to apply firewall rules, virtual router is not in the right state",
+ VirtualRouter.class, router.getId());
+ }
+ }
+
+ @Override
+ public boolean configure(String name, Map params)
+ throws ConfigurationException {
+ _name = name;
+ final Map configs = _configDao.getConfiguration("AgentManager", params);
+ _systemAcct = _accountService.getSystemAccount();
+ _instance = configs.get("instance.name");
+ if (_instance == null) {
+ _instance = "VM";
+ }
+ boolean useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));
+
+ _elasticLbVmRamSize = NumbersUtil.parseInt(configs.get("elastic.lb.vm.ram.size"), DEFAULT_ELB_VM_RAMSIZE);
+ _elasticLbvmCpuMHz = NumbersUtil.parseInt(configs.get("elastic.lb.vm.cpu.mhz"), DEFAULT_ELB_VM_CPU_MHZ);
+ _elasticLbVmOffering = new ServiceOfferingVO("System Offering For Elastic LB VM", 1, _elasticLbVmRamSize, _elasticLbvmCpuMHz, 0, 0, true, null, useLocalStorage, true, null, true, VirtualMachine.Type.ElasticLoadBalancerVm, true);
+ _elasticLbVmOffering.setUniqueName("Cloud.Com-ElasticLBVm");
+ _elasticLbVmOffering = _serviceOfferingDao.persistSystemServiceOffering(_elasticLbVmOffering);
+
+
+ return true;
+ }
+
+ @Override
+ public boolean start() {
+ return true;
+ }
+
+ @Override
+ public boolean stop() {
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return _name;
+ }
+
+
+ @DB
+ public DomainRouterVO deployELBVm(Network guestNetwork, DeployDestination dest, Account owner, Map params) throws
+ ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+ long dcId = dest.getDataCenter().getId();
+
+ // lock guest network
+ Long guestNetworkId = guestNetwork.getId();
+ guestNetwork = _networkDao.acquireInLockTable(guestNetworkId);
+
+ if (guestNetwork == null) {
+ throw new ConcurrentOperationException("Unable to acquire network configuration: " + guestNetworkId);
+ }
+
+ try {
+
+ NetworkOffering offering = _networkOfferingDao.findByIdIncludingRemoved(guestNetwork.getNetworkOfferingId());
+ if (offering.isSystemOnly() || guestNetwork.getIsShared()) {
+ owner = _accountService.getSystemAccount();
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Starting a elastic ip vm for network configurations: " + guestNetwork + " in " + dest);
+ }
+ assert guestNetwork.getState() == Network.State.Implemented
+ || guestNetwork.getState() == Network.State.Setup
+ || guestNetwork.getState() == Network.State.Implementing
+ : "Network is not yet fully implemented: "+ guestNetwork;
+
+ DataCenterDeployment plan = null;
+ DomainRouterVO router = null;
+
+ //router = _routerDao.findByNetworkAndPodAndRole(guestNetwork.getId(), podId, Role.LB);
+ plan = new DataCenterDeployment(dcId, null, null, null, null);
+
+ // } else {
+ // s_logger.debug("Not deploying elastic ip vm");
+ // return null;
+ // }
+
+ if (router == null) {
+ long id = _routerDao.getNextInSequence(Long.class, "id");
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Creating the elastic LB vm " + id);
+ }
+
+ List offerings = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemControlNetwork);
+ NetworkOfferingVO controlOffering = offerings.get(0);
+ NetworkVO controlConfig = _networkMgr.setupNetwork(_systemAcct, controlOffering, plan, null, null, false, false).get(0);
+
+ List> networks = new ArrayList>(2);
+ NicProfile guestNic = new NicProfile();
+ networks.add(new Pair((NetworkVO) guestNetwork, guestNic));
+ networks.add(new Pair(controlConfig, null));
+
+ VMTemplateVO template = _templateDao.findSystemVMTemplate(dcId);
+
+
+ router = new DomainRouterVO(id, _elasticLbVmOffering.getId(), VirtualMachineName.getRouterName(id, _instance), template.getId(), template.getHypervisorType(), template.getGuestOSId(),
+ owner.getDomainId(), owner.getId(), guestNetwork.getId(), _elasticLbVmOffering.getOfferHA());
+ router.setRole(Role.LB);
+ router = _itMgr.allocate(router, template, _elasticLbVmOffering, networks, plan, null, owner);
+ }
+
+ State state = router.getState();
+ if (state != State.Running) {
+ router = this.start(router, _accountService.getSystemUser(), _accountService.getSystemAccount(), params);
+ }
+
+
+ return router;
+ } finally {
+ _networkDao.releaseFromLockTable(guestNetworkId);
+ }
+ }
+
+ private DomainRouterVO start(DomainRouterVO router, User user, Account caller, Map params) throws StorageUnavailableException, InsufficientCapacityException,
+ ConcurrentOperationException, ResourceUnavailableException {
+ s_logger.debug("Starting router " + router);
+ if (_itMgr.start(router, params, user, caller) != null) {
+ return _routerDao.findById(router.getId());
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
index 760a06fe657..d69adb008fa 100755
--- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
+++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
@@ -50,12 +50,15 @@ 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;
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.FirewallRule;
import com.cloud.network.rules.FirewallRule.Purpose;
@@ -118,6 +121,10 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager,
NicDao _nicDao;
@Inject
UsageEventDao _usageEventDao;
+ @Inject
+ ElasticLoadBalancerManager _elbMgr;
+ @Inject
+ NetworkDao _networkDao;
@Override
@DB
@@ -346,9 +353,25 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager,
UserContext caller = UserContext.current();
long ipId = lb.getSourceIpAddressId();
-
- // make sure ip address exists
IPAddressVO ipAddr = _ipAddressDao.findById(ipId);
+ Long networkId= ipAddr.getSourceNetworkId();
+ NetworkVO network=_networkDao.findById(networkId);
+
+ if (network.getGuestType() == GuestIpType.Direct) {
+ LoadBalancerVO lbvo;
+ Account account = caller.getCaller();
+ lbvo = _lbDao.findByAccountAndName(account.getId(), lb.getName());
+ if (lbvo == null) {
+ _elbMgr.deployLoadBalancerVM(networkId, account.getId());
+ IPAddressVO ipvo = _ipAddressDao.findById(ipId);
+ ipvo.setAssociatedWithNetworkId(networkId);
+ _ipAddressDao.update(ipvo.getId(), ipvo);
+ ipAddr.setAssociatedWithNetworkId(networkId);
+ } else {
+
+ }
+ }
+ // make sure ip address exists
if (ipAddr == null || !ipAddr.readyToUse()) {
throw new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id" + ipId);
}
@@ -380,7 +403,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager,
throw new InvalidParameterValueException("Invalid algorithm: " + lb.getAlgorithm());
}
- Long networkId = ipAddr.getAssociatedWithNetworkId();
+ networkId = ipAddr.getAssociatedWithNetworkId();
if (networkId == null) {
throw new InvalidParameterValueException("Unable to create load balancer rule ; ip id=" + ipId + " is not associated with any network");
@@ -389,9 +412,8 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager,
_accountMgr.checkAccess(caller.getCaller(), ipAddr);
// verify that lb service is supported by the network
- Network network = _networkMgr.getNetwork(networkId);
if (!_networkMgr.isServiceSupported(network.getNetworkOfferingId(), Service.Lb)) {
- throw new InvalidParameterValueException("LB service is not supported in network id=" + networkId);
+ throw new InvalidParameterValueException("LB service is not supported in network id= " + networkId);
}
LoadBalancerVO newRule = new LoadBalancerVO(lb.getXid(), lb.getName(), lb.getDescription(), lb.getSourceIpAddressId(), lb.getSourcePortEnd(), lb.getDefaultPortStart(), lb.getAlgorithm(),
diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java
index 89ba2ed7f90..ef74240961c 100644
--- a/server/src/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/com/cloud/server/ConfigurationServerImpl.java
@@ -809,7 +809,7 @@ public class ConfigurationServerImpl implements ConfigurationServer {
true, false, null, null, null, true,
Availability.Required,
true, true, true, //services - all true except for lb/vpn and gateway
- false, true, false, false, GuestIpType.Direct);
+ false, true, true, false, GuestIpType.Direct);
guestNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(guestNetworkOffering);
@@ -829,7 +829,7 @@ public class ConfigurationServerImpl implements ConfigurationServer {
false, true, null, null, null, true,
Availability.Optional,
true, true, true, //services - all true except for firewall/lb/vpn and gateway
- false, false, false, false, GuestIpType.Direct);
+ false, false, true, false, GuestIpType.Direct);
defaultGuestNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultGuestDirectNetworkOffering);
}