merge ELB / nectarine branch

This commit is contained in:
Chiradeep Vittal 2011-08-08 15:20:56 -07:00
commit 8277584b8a
45 changed files with 3374 additions and 1131 deletions

View File

@ -249,5 +249,6 @@ public class ApiConstants {
public static final String SNAPSHOT_RESERVATION = "snapshotreservation";
public static final String IP_NETWORK_LIST = "iptonetworklist";
public static final String REDUNDANT_ROUTER = "redundantrouter";
public static final String FOR_LOAD_BALANCING = "forloadbalancing";
public static final String KEYBOARD="keyboard";
}

View File

@ -190,4 +190,12 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd {
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;
}
}

View File

@ -23,20 +23,27 @@ import java.util.List;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseAsyncCmd;
import com.cloud.api.BaseCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.BaseCmd.CommandType;
import com.cloud.api.response.LoadBalancerResponse;
import com.cloud.event.EventTypes;
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)
public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer {
public class CreateLoadBalancerRuleCmd extends BaseAsyncCmd /*implements LoadBalancer */{
public static final Logger s_logger = Logger.getLogger(CreateLoadBalancerRuleCmd.class.getName());
private static final String s_name = "createloadbalancerruleresponse";
@ -57,26 +64,31 @@ 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.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from")
private List<String> cidrlist;
@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 ///////////////////////
/////////////////////////////////////////////////////
@Override
public String getAlgorithm() {
return algorithm;
}
@Override
public String getDescription() {
return description;
}
@ -92,7 +104,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;
@ -120,7 +132,7 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer
}
@Override
public void execute() {
public void execute() throws ResourceAllocationException, ResourceUnavailableException {
if (cidrlist != null){
for (String cidr: cidrlist){
if (!NetUtils.isValidCIDR(cidr)){
@ -135,74 +147,68 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer
} catch (NetworkRuleConflictException e) {
s_logger.warn("Exception: ", e);
throw new ServerApiException(BaseCmd.NETWORK_RULE_CONFLICT_ERROR, e.getMessage());
} catch (InsufficientAddressCapacityException e) {
s_logger.warn("Exception: ", e);
throw new ServerApiException(BaseCmd.INSUFFICIENT_CAPACITY_ERROR, e.getMessage());
}
LoadBalancerResponse response = _responseGenerator.createLoadBalancerResponse(result);
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
@Override
public long getId() {
throw new UnsupportedOperationException("not supported");
}
@Override
public String getXid() {
// FIXME: Should fix this.
return null;
}
@Override
public long getSourceIpAddressId() {
public Long getSourceIpAddressId() {
return publicIpId;
}
@Override
public int getSourcePortStart() {
return publicPort.intValue();
}
@Override
public int getSourcePortEnd() {
return publicPort.intValue();
}
@Override
public String getProtocol() {
return NetUtils.TCP_PROTO;
}
@Override
public Purpose getPurpose() {
return Purpose.LoadBalancing;
}
@Override
public State getState() {
throw new UnsupportedOperationException("not supported");
}
@Override
public long getNetworkId() {
return -1;
}
@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
public int getDefaultPortStart() {
return privatePort.intValue();
}
@Override
public int getDefaultPortEnd() {
return privatePort.intValue();
}
@ -211,4 +217,37 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer
public long getEntityOwnerId() {
return getAccountId();
}
public String getAccountName() {
return accountName;
}
public Long getZoneId() {
return zoneId;
}
public void setPublicIpId(Long publicIpId) {
this.publicIpId = publicIpId;
}
@Override
public String getEventType() {
return EventTypes.EVENT_LOAD_BALANCER_CREATE;
}
@Override
public String getEventDescription() {
return "creating load balancer: " + getName() + " account: " + getAccountName();
}
public String getXid() {
/*FIXME*/
return null;
}
public void setSourceIpAddressId(Long ipId) {
this.publicIpId = ipId;
}
}

View File

@ -99,6 +99,10 @@ public class DeleteLoadBalancerRuleCmd extends BaseAsyncCmd {
@Override
public Long getSyncObjId() {
return _lbService.findById(id).getNetworkId();
LoadBalancer lb = _lbService.findById(id);
if (lb == null) {
return null;
}
return lb.getNetworkId();
}
}

View File

@ -49,6 +49,7 @@ public class ListCapabilitiesCmd extends BaseCmd {
response.setSecurityGroupsEnabled((Boolean)capabilities.get("securityGroupsEnabled"));
response.setCloudStackVersion((String)capabilities.get("cloudStackVersion"));
response.setUserPublicTemplateEnabled((Boolean)capabilities.get("userPublicTemplateEnabled"));
response.setSupportELB((String)capabilities.get("supportELB"));
response.setObjectName("capability");
response.setResponseName(getCommandName());
this.setResponseObject(response);

View File

@ -119,4 +119,17 @@ 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;
}
*/
}

View File

@ -66,6 +66,9 @@ public class ListPublicIpAddressesCmd extends BaseListCmd {
@Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="lists all public IP addresses by Zone ID")
private Long zoneId;
@Parameter(name=ApiConstants.FOR_LOAD_BALANCING, type=CommandType.BOOLEAN, description="list only ips used for load balancing")
private Boolean forLoadBalancing;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -129,4 +132,33 @@ public class ListPublicIpAddressesCmd extends BaseListCmd {
public AsyncJob.Type getInstanceType() {
return AsyncJob.Type.IpAddress;
}
public Boolean isForLoadBalancing() {
return forLoadBalancing;
}
public Boolean getAllocatedOnly() {
return allocatedOnly;
}
public void setAllocatedOnly(Boolean allocatedOnly) {
this.allocatedOnly = allocatedOnly;
}
public Boolean getForVirtualNetwork() {
return forVirtualNetwork;
}
public void setForVirtualNetwork(Boolean forVirtualNetwork) {
this.forVirtualNetwork = forVirtualNetwork;
}
public Boolean getForLoadBalancing() {
return forLoadBalancing;
}
public void setForLoadBalancing(Boolean forLoadBalancing) {
this.forLoadBalancing = forLoadBalancing;
}
}

View File

@ -31,6 +31,10 @@ public class CapabilitiesResponse extends BaseResponse {
@SerializedName("userpublictemplateenabled") @Param(description="true if user and domain admins can set templates to be shared, false otherwise")
private boolean userPublicTemplateEnabled;
@SerializedName("supportELB") @Param(description="true if region supports elastic load balancer on basic zones")
private String supportELB;
public boolean getSecurityGroupsEnabled() {
return securityGroupsEnabled;
}
@ -54,4 +58,12 @@ public class CapabilitiesResponse extends BaseResponse {
public void setUserPublicTemplateEnabled(boolean userPublicTemplateEnabled) {
this.userPublicTemplateEnabled = userPublicTemplateEnabled;
}
public void setSupportELB(String supportELB) {
this.supportELB = supportELB;
}
public String getSupportELB() {
return supportELB;
}
}

View File

@ -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;

View File

@ -19,9 +19,11 @@ package com.cloud.network.lb;
import java.util.List;
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.exception.InsufficientAddressCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.rules.LoadBalancer;
@ -32,8 +34,9 @@ public interface LoadBalancingRulesService {
* Create a load balancer rule from the given ipAddress/port to the given private port
* @param cmd the command specifying the ip address, public port, protocol, private port, and algorithm
* @return the newly created LoadBalancerVO if successful, null otherwise
* @throws InsufficientAddressCapacityException
*/
LoadBalancer createLoadBalancerRule(LoadBalancer lb) throws NetworkRuleConflictException;
LoadBalancer createLoadBalancerRule(CreateLoadBalancerRuleCmd lb) throws NetworkRuleConflictException, InsufficientAddressCapacityException;
LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd);

View File

@ -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();
boolean getIsRedundantRouter();

View File

@ -176,6 +176,8 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, StateObject
DomainRouter,
ConsoleProxy,
SecondaryStorageVm,
ElasticIpVm,
ElasticLoadBalancerVm,
/*
* UserBareMetal is only used for selecting VirtualMachineGuru, there is no

View File

@ -95,6 +95,8 @@
<adapter name="DomainRouter" class="com.cloud.network.element.VirtualRouterElement"/>
<adapter name="Dhcp" class="com.cloud.network.element.DhcpElement"/>
<adapter name="Ovs" class="com.cloud.network.element.OvsElement"/>
<adapter name="ElasticLoadBalancer" class="com.cloud.network.element.ElasticLoadBalancerElement"/>
</adapters>
<adapters key="com.cloud.acl.SecurityChecker">
<adapter name="DomainChecker" class="com.cloud.acl.DomainChecker"/>

View File

@ -85,6 +85,21 @@ public class DomainRouterVO extends VMInstanceVO implements VirtualRouter {
this.redundantState = redundantState;
}
public DomainRouterVO(long id,
long serviceOfferingId,
String name,
long templateId,
HypervisorType hypervisorType,
long guestOSId,
long domainId,
long accountId,
long networkId,
boolean haEnabled,
VirtualMachine.Type vmType) {
super(id, serviceOfferingId, name, name, vmType, templateId, hypervisorType, guestOSId, domainId, accountId, haEnabled);
this.networkId = networkId;
}
public void setPublicIpAddress(String publicIpAddress) {
this.publicIpAddress = publicIpAddress;
}

View File

@ -457,6 +457,33 @@ setup_console_proxy() {
chkconfig nfs-common off
}
setup_elbvm() {
log_it "Setting up Elastic Load Balancer system vm"
local hyp=$1
setup_common eth0 eth1
sed -i /gateway/d /etc/hosts
public_ip=$ETH2_IP
[ "$ETH2_IP" == "0.0.0.0" ] || [ "$ETH2_IP" == "" ] && public_ip=$ETH0_IP
echo "$public_ip $NAME" >> /etc/hosts
if [ "$SSHONGUEST" == "true" ]
then
sed '/3922/s/eth1/eth0/'
setup_sshd $ETH0_IP
else
cp /etc/iptables/iptables-elbvm /etc/iptables/rules
setup_sshd $ETH1_IP
fi
enable_fwding 0
enable_svc haproxy 0
enable_svc dnsmasq 0
enable_svc cloud-passwd-srvr 0
enable_svc cloud 0
chkconfig nfs-common off
chkconfig portmap off
}
setup_default() {
cat > /etc/network/interfaces << EOF
auto lo eth0
@ -491,6 +518,10 @@ start() {
[ "$NAME" == "" ] && NAME=consoleproxy
setup_console_proxy $hyp;
;;
elbvm)
[ "$NAME" == "" ] && NAME=elb
setup_elbvm
;;
unknown)
[ "$NAME" == "" ] && NAME=systemvm
setup_default;

View File

@ -0,0 +1,17 @@
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i eth2 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -p tcp -m state --state NEW --dport 3922 -j ACCEPT
COMMIT

View File

@ -100,6 +100,16 @@ dhcpsrvr_svcs() {
echo "cloud nfs-common haproxy portmap" > /var/cache/cloud/disabled_svcs
}
elbvm_svcs() {
chkconfig cloud off
chkconfig haproxy on ;
chkconfig ssh on
chkconfig nfs-common off
chkconfig portmap off
echo "ssh haproxy" > /var/cache/cloud/enabled_svcs
echo "cloud cloud-passwd-srvr dnsmasq apache2 nfs-common portmap" > /var/cache/cloud/disabled_svcs
}
enable_pcihotplug() {
sed -i -e "/acpiphp/d" /etc/modules
sed -i -e "/pci_hotplug/d" /etc/modules
@ -198,4 +208,14 @@ then
fi
fi
if [ "$TYPE" == "elbvm" ]
then
elbvm_svcs
if [ $? -gt 0 ]
then
printf "Failed to execute elbvm svcs\n" >$logfile
exit 9
fi
fi
exit $?

View File

@ -27,48 +27,15 @@
# @VERSION@
usage() {
printf "Usage: %s: -i <domR eth1 ip> -a <added public ip address> -d <removed> -f <load balancer config> -s <stats guest ip address> \n" $(basename $0) >&2
printf "Usage: %s: -i <domR eth1 ip> -a <added public ip address> -d <removed> -f <load balancer config> \n" $(basename $0) >&2
}
# set -x
# check if gateway domain is up and running
check_gw() {
ping -c 1 -n -q $1 > /dev/null
if [ $? -gt 0 ]
then
sleep 1
ping -c 1 -n -q $1 > /dev/null
fi
return $?;
}
fw_remove_backup() {
for vif in $VIF_LIST; do
iptables -F back_load_balancer_$vif 2> /dev/null
iptables -D INPUT -i $vif -p tcp -j back_load_balancer_$vif 2> /dev/null
iptables -X back_load_balancer_$vif 2> /dev/null
done
iptables -F back_lb_stats 2> /dev/null
iptables -D INPUT -i $STAT_IF -p tcp -j back_lb_stats 2> /dev/null
iptables -X back_lb_stats 2> /dev/null
}
fw_restore() {
for vif in $VIF_LIST; do
iptables -F load_balancer_$vif 2> /dev/null
iptables -D INPUT -i $vif -p tcp -j load_balancer_$vif 2> /dev/null
iptables -X load_balancer_$vif 2> /dev/null
iptables -E back_load_balancer_$vif load_balancer_$vif 2> /dev/null
done
iptables -F lb_stats 2> /dev/null
iptables -D INPUT -i $STAT_IF -p tcp -j lb_stats 2> /dev/null
iptables -X lb_stats 2> /dev/null
iptables -E back_lb_stats lb_stats 2> /dev/null
}
# firewall entry to ensure that haproxy can receive on specified port
fw_entry() {
# ensure that the nic has the public ip we are load balancing on
ip_entry() {
local added=$1
local removed=$2
local stats=$3
if [ "$added" == "none" ]
then
@ -83,24 +50,56 @@ fw_entry() {
local a=$(echo $added | cut -d, -f1- --output-delimiter=" ")
local r=$(echo $removed | cut -d, -f1- --output-delimiter=" ")
# back up the iptable rules by renaming before creating new.
for vif in $VIF_LIST; do
iptables -E load_balancer_$vif back_load_balancer_$vif 2> /dev/null
iptables -N load_balancer_$vif 2> /dev/null
iptables -A INPUT -i $vif -p tcp -j load_balancer_$vif
for i in $a
do
local pubIp=$(echo $i | cut -d: -f1)
logger -t cloud "Adding public ip $pubIp for load balancing"
for vif in $VIF_LIST; do
sudo ip addr add dev $vif $pubIp/32
#ignore error since it is because the ip is already there
done
done
iptables -E lb_stats back_lb_stats 2> /dev/null
iptables -N lb_stats 2> /dev/null
iptables -A INPUT -i $STAT_IF -p tcp -j lb_stats
for i in $r
do
logger -t cloud "Removing public ips for deleted loadbalancers"
local pubIp=$(echo $i | cut -d: -f1)
logger -t cloud "Removing public ip $pubIp for deleted loadbalancers"
for vif in $VIF_LIST; do
sudo ip addr del $pubIp/32 dev $vif
done
done
return 0
}
# firewall entry to ensure that haproxy can receive on specified port
fw_entry() {
local added=$1
local removed=$2
if [ "$added" == "none" ]
then
added=""
fi
if [ "$removed" == "none" ]
then
removed=""
fi
local a=$(echo $added | cut -d, -f1- --output-delimiter=" ")
local r=$(echo $removed | cut -d, -f1- --output-delimiter=" ")
for i in $a
do
local pubIp=$(echo $i | cut -d: -f1)
local dport=$(echo $i | cut -d: -f2)
local cidrs=$(echo $i | cut -d: -f3 | sed 's/-/,/')
logger -t cloud "Opening up firewall $pubIp:$dport (INPUT chain) for load balancing"
for vif in $VIF_LIST; do
iptables -A load_balancer_$vif -s $cidrs -p tcp -d $pubIp --dport $dport -j ACCEPT
sudo iptables -D INPUT -i $vif -p tcp -d $pubIp --dport $dport -j ACCEPT 2> /dev/null
sudo iptables -A INPUT -i $vif -p tcp -d $pubIp --dport $dport -j ACCEPT
if [ $? -gt 0 ]
then
@ -108,10 +107,17 @@ fw_entry() {
fi
done
done
local pubIp=$(echo $stats | cut -d: -f1)
local dport=$(echo $stats | cut -d: -f2)
local cidrs=$(echo $stats | cut -d: -f3 | sed 's/-/,/')
iptables -A lb_stats -s $cidrs -p tcp -m state --state NEW -d $pubIp --dport $dport -j ACCEPT
for i in $r
do
local pubIp=$(echo $i | cut -d: -f1)
local dport=$(echo $i | cut -d: -f2)
logger -t cloud "Closing up firewall (INPUT chain) $pubIp:$dport for deleted load balancers"
for vif in $VIF_LIST; do
sudo iptables -D INPUT -i $vif -p tcp -d $pubIp --dport $dport -j ACCEPT
done
done
return 0
}
@ -124,6 +130,7 @@ reconfig_lb() {
# Restore the HA Proxy to its previous state, and revert iptables rules on DomR
restore_lb() {
logger -t cloud "Restoring HA Proxy to previous state"
# Copy the old version of haproxy.cfg into the file that reconfigLB.sh uses
cp /etc/haproxy/haproxy.cfg.old /etc/haproxy/haproxy.cfg.new
@ -143,7 +150,12 @@ get_vif_list() {
vif_list="$vif_list $vif";
fi
done
if [ "$vif_list" == "" ]
then
vif_list="eth0"
fi
logger -t cloud "Loadbalancer public interfaces = $vif_list"
echo $vif_list
}
@ -152,9 +164,8 @@ iflag=
aflag=
dflag=
fflag=
sflag=
while getopts 'i:a:d:f:s:' OPTION
while getopts 'i:a:d:f:' OPTION
do
case $OPTION in
i) iflag=1
@ -169,28 +180,12 @@ do
f) fflag=1
cfgfile="$OPTARG"
;;
s) sflag=1
statsIp="$OPTARG"
;;
?) usage
exit 2
;;
esac
done
VIF_LIST=$(get_vif_list)
# TODO make the stat interface generic
STAT_IF="eth0"
# hot reconfigure haproxy
reconfig_lb $cfgfile
if [ $? -gt 0 ]
then
printf "Reconfiguring loadbalancer failed\n"
exit 1
fi
if [ "$addedIps" == "" ]
then
addedIps="none"
@ -201,21 +196,61 @@ then
removedIps="none"
fi
# iptables entry to ensure that haproxy receives traffic
fw_entry $addedIps $removedIps $statsIp
VIF_LIST=$(get_vif_list)
if [ "$addedIps" == "" ]
then
addedIps="none"
fi
if [ "$removedIps" == "" ]
then
removedIps="none"
fi
#FIXME: make this explicit via check on vm type or passed in flag
if [ "$VIF_LIST" == "eth0" ]
then
ip_entry $addedIps $removedIps
fi
# hot reconfigure haproxy
reconfig_lb $cfgfile
if [ $? -gt 0 ]
then
logger -t cloud "Reconfiguring loadbalancer failed"
#FIXME: make this explicit via check on vm type or passed in flag
if [ "$VIF_LIST" == "eth0" ]
then
ip_entry $removedIps $addedIps
fi
exit 1
fi
# iptables entry to ensure that haproxy receives traffic
fw_entry $addedIps $removedIps
if [ $? -gt 0 ]
then
logger -t cloud "Failed to apply firewall rules for load balancing, reverting HA Proxy config"
# Restore the LB
restore_lb
# Revert iptables rules on DomR
fw_restore
logger -t cloud "Reverting firewall config"
# Revert iptables rules on DomR, with addedIps and removedIps swapped
fw_entry $removedIps $addedIps
#FIXME: make this explicit via check on vm type or passed in flag
if [ "$VIF_LIST" == "eth0" ]
then
logger -t cloud "Reverting ip address changes to eth0"
ip_entry $removedIps $addedIps
fi
exit 1
else
# Remove backedup iptable rules
fw_remove_backup
fi
exit 0

View File

@ -362,11 +362,10 @@ def chain_name(vm_name):
if vm_name.startswith('i-') or vm_name.startswith('r-'):
if vm_name.endswith('untagged'):
return '-'.join(vm_name.split('-')[:-1])
return '-'.join(vm_name.split('-'))
return vm_name
def chain_name_def(vm_name):
if vm_name.startswith('i-') or vm_name.startswith('r-'):
if vm_name.startswith('i-'):
if vm_name.endswith('untagged'):
return '-'.join(vm_name.split('-')[:-2]) + "-def"
return '-'.join(vm_name.split('-')[:-1]) + "-def"
@ -392,7 +391,7 @@ def can_bridge_firewall(session, args):
util.pread2(['iptables', '-A', 'FORWARD', '-j', 'DROP'])
except:
result = 'false'
allow_egress_traffic(session)
if not os.path.exists('/var/run/cloud'):
os.makedirs('/var/run/cloud')
@ -401,6 +400,28 @@ def can_bridge_firewall(session, args):
return result
@echo
def allow_egress_traffic(session):
devs = []
for pif in session.xenapi.PIF.get_all():
pif_rec = session.xenapi.PIF.get_record(pif)
vlan = pif_rec.get('VLAN')
dev = pif_rec.get('device')
if vlan == '-1':
devs.append(dev)
else:
devs.append(dev + "." + vlan)
for d in devs:
try:
util.pread2(['/bin/bash', '-c', "iptables -n -L FORWARD | grep '%s '" % d])
except:
try:
util.pread2(['iptables', '-I', 'FORWARD', '2', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', d, '-j', 'ACCEPT'])
except:
util.SMlog("Failed to add FORWARD rule through to %s" % d)
return 'false'
return 'true'
def ipset(ipsetname, proto, start, end, ips):
try:
@ -434,7 +455,7 @@ def destroy_network_rules_for_vm(session, args):
vmchain_default = chain_name_def(vm_name)
delete_rules_for_vm_in_bridge_firewall_chain(vm_name)
if vm_name.startswith('i-') or vm_name.startswith('r-'):
if vm_name.startswith('i-') or vm_name.startswith('r-') or vm_name.startswith('l-'):
try:
util.pread2(['iptables', '-F', vmchain_default])
util.pread2(['iptables', '-X', vmchain_default])
@ -453,7 +474,7 @@ def destroy_network_rules_for_vm(session, args):
remove_rule_log_for_vm(vm_name)
if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-'] ]:
if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-', 'l-'] ]:
return 'true'
try:
@ -573,15 +594,18 @@ def default_network_rules_systemvm(session, args):
except:
util.pread2(['iptables', '-F', vmchain])
allow_egress_traffic(session)
for vif in vifs:
try:
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', vif, '-j', vmchain])
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', vif, '-j', vmchain])
util.pread2(['iptables', '-I', 'BRIDGE-FIREWALL', '2', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', vif, '-j', vmchain])
util.pread2(['iptables', '-I', vmchain, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', vif, '-j', 'RETURN'])
except:
util.SMlog("Failed to program default rules")
return 'false'
util.pread2(['iptables', '-A', vmchain, '-j', 'ACCEPT'])
if write_rule_log_for_vm(vm_name, '-1', '_ignore_', domid, '_initial_', '-1') == False:
@ -641,7 +665,7 @@ def default_network_rules(session, args):
try:
for v in vifs:
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-j', vmchain_default])
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-j', vmchain_default])
util.pread2(['iptables', '-I', 'BRIDGE-FIREWALL', '2', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-j', vmchain_default])
util.pread2(['iptables', '-A', vmchain_default, '-m', 'state', '--state', 'RELATED,ESTABLISHED', '-j', 'ACCEPT'])
#allow dhcp
for v in vifs:
@ -724,7 +748,7 @@ def network_rules_for_rebooted_vm(session, vmName):
util.SMlog("Found a rebooted VM -- reprogramming rules for " + vm_name)
delete_rules_for_vm_in_bridge_firewall_chain(vm_name)
if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-'] ]:
if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-', 'l-'] ]:
default_network_rules_systemvm(session, {"vmName":vm_name})
return True
@ -741,7 +765,7 @@ def network_rules_for_rebooted_vm(session, vmName):
for v in vifs:
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-j', vmchain_default])
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-j', vmchain_default])
util.pread2(['iptables', '-I', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-j', vmchain_default])
#change antispoof rule in vmchain
try:
@ -812,7 +836,7 @@ def get_rule_logs_for_vms(session, args):
result = []
try:
for name in [session.xenapi.VM.get_name_label(x) for x in vms]:
if 1 not in [ name.startswith(c) for c in ['r-', 's-', 'v-', 'i-'] ]:
if 1 not in [ name.startswith(c) for c in ['r-', 's-', 'v-', 'i-', 'l-'] ]:
continue
network_rules_for_rebooted_vm(session, name)
if name.startswith('i-'):
@ -829,7 +853,7 @@ def cleanup_rules_for_dead_vms(session):
vms = session.xenapi.VM.get_all()
cleaned = 0
for vm_name in [session.xenapi.VM.get_name_label(x) for x in vms]:
if 1 in [ vm_name.startswith(c) for c in ['r-', 'i-', 's-', 'v-'] ]:
if 1 in [ vm_name.startswith(c) for c in ['r-', 'i-', 's-', 'v-', 'l-'] ]:
vm = session.xenapi.VM.get_by_name_label(vm_name)
if len(vm) != 1:
continue
@ -857,11 +881,11 @@ def cleanup_rules(session, args):
cleaned = 0
cleanup = []
for chain in chains:
if 1 in [ chain.startswith(c) for c in ['r-', 'i-', 's-', 'v-'] ]:
vm = session.xenapi.VM.get_by_name_label(vm_name)
if 1 in [ chain.startswith(c) for c in ['r-', 'i-', 's-', 'v-', 'l-'] ]:
vm = session.xenapi.VM.get_by_name_label(chain)
if len(vm) != 1:
util.SMlog("chain " + chain + " does not correspond to a vm, cleaning up")
cleanup.append(vm_name)
cleanup.append(chain)
continue
vm_rec = session.xenapi.VM.get_record(vm[0])
state = vm_rec.get('power_state')
@ -1058,6 +1082,16 @@ def checkRouter(session, args):
return txt
if __name__ == "__main__":
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi, "gethostvmstats": gethostvmstats, "getvncport": getvncport, "getgateway": getgateway, "preparemigration": preparemigration, "setIptables": setIptables, "pingdomr": pingdomr, "pingxenserver": pingxenserver, "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, "networkUsage": networkUsage, "network_rules":network_rules, "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn, "cleanup_rules":cleanup_rules, "checkRouter": checkRouter})
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi, "gethostvmstats": gethostvmstats,
"getvncport": getvncport, "getgateway": getgateway, "preparemigration": preparemigration,
"setIptables": setIptables, "pingdomr": pingdomr, "pingxenserver": pingxenserver,
"ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword,
"saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule,
"setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile,
"networkUsage": networkUsage, "network_rules":network_rules,
"can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules,
"destroy_network_rules_for_vm":destroy_network_rules_for_vm,
"default_network_rules_systemvm":default_network_rules_systemvm,
"get_rule_logs_for_vms":get_rule_logs_for_vms,
"setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn,
"cleanup_rules":cleanup_rules, "checkRouter": checkRouter})

View File

@ -186,6 +186,14 @@ public enum Config {
UseUserConcentratedPodAllocation("Advanced", ManagementServer.class, Boolean.class, "use.user.concentrated.pod.allocation", "true", "If true, deployment planner applies the user concentration heuristic during VM resource allocation", "true,false"),
HostCapacityTypeToOrderClusters("Advanced", ManagementServer.class, String.class, "host.capacityType.to.order.clusters", "CPU", "The host capacity type (CPU or RAM) is used by deployment planner to order clusters during VM resource allocation", "CPU,RAM"),
EndpointeUrl("Advanced", ManagementServer.class, String.class, "endpointe.url", "http://localhost:8080/client/api", "Endpointe Url", "The endpoint callback URL"),
ElasticLoadBalancerEnabled("Advanced", ManagementServer.class, String.class, "network.loadbalancer.basiczone.elb.enabled", "false", "Whether the load balancing service is enabled for basic zones", "true,false"),
ElasticLoadBalancerNetwork("Advanced", ManagementServer.class, String.class, "network.loadbalancer.basiczone.elb.network", "guest", "Whether the elastic load balancing service public ips are taken from the public or guest network", "guest,public"),
ElasticLoadBalancerVmMemory("Advanced", ManagementServer.class, Integer.class, "network.loadbalancer.basiczone.elb.vm.ram.size", "128", "Memory in MB for the elastic load balancer vm", null),
ElasticLoadBalancerVmCpuMhz("Advanced", ManagementServer.class, Integer.class, "network.loadbalancer.basiczone.elb.vm.cpu.mhz", "128", "CPU speed for the elastic load balancer vm", null),
ElasticLoadBalancerVmNumVcpu("Advanced", ManagementServer.class, Integer.class, "network.loadbalancer.basiczone.elb.vm.vcpu.num", "1", "Number of VCPU for the elastic load balancer vm", null),
ElasticLoadBalancerVmGcInterval("Advanced", ManagementServer.class, Integer.class, "network.loadbalancer.basiczone.elb.gc.interval.minutes", "30", "Garbage collection interval to destroy unused ELB vms in minutes. Minimum of 5", null),
// XenServer
VmAllocationAlgorithm("Advanced", ManagementServer.class, String.class, "vm.allocation.algorithm", "random", "If 'random', hosts within a pod will be randomly considered for VM/volume allocation. If 'firstfit', they will be considered on a first-fit basis.", null),
@ -252,7 +260,7 @@ public enum Config {
AgentLbEnable("Advanced", ClusterManager.class, Boolean.class, "agent.lb.enabled", "true", "If agent load balancing enabled in cluster setup", null),
SubDomainNetworkAccess("Advanced", NetworkManager.class, Boolean.class, "allow.subdomain.network.access", "true", "Allow subdomains to use networks dedicated to their parent domain(s)", null),
UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, "use.external.dns", "false", "Bypass internal dns, use exetrnal dns1 and dns2", null),
UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, "use.external.dns", "false", "Bypass the cloudstack dhcp/DNS server vm name service, use zone external dns1 and dns2", null),
EncodeApiResponse("Advanced", ManagementServer.class, Boolean.class, "encode.api.response", "false", "Do UTF-8 encoding for the api response, false by default", null),
DnsBasicZoneUpdates("Advanced", NetworkManager.class, String.class, "network.dns.basiczone.updates", "all", "This parameter can take 2 values: all (default) and pod. It defines if DHCP/DNS requests have to be send to all dhcp servers in cloudstack, or only to the one in the same pod", "all,pod"),

View File

@ -81,7 +81,9 @@ import com.cloud.network.dao.NetworkDomainDaoImpl;
import com.cloud.network.dao.NetworkRuleConfigDaoImpl;
import com.cloud.network.dao.RemoteAccessVpnDaoImpl;
import com.cloud.network.dao.VpnUserDaoImpl;
import com.cloud.network.lb.ElasticLoadBalancerManagerImpl;
import com.cloud.network.lb.LoadBalancingRulesManagerImpl;
import com.cloud.network.lb.dao.ElasticLbVmMapDaoImpl;
import com.cloud.network.ovs.OvsNetworkManagerImpl;
import com.cloud.network.ovs.OvsTunnelManagerImpl;
import com.cloud.network.ovs.dao.GreTunnelDaoImpl;
@ -265,6 +267,8 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
addDao("DcDetailsDao", DcDetailsDaoImpl.class);
addDao("SwiftDao", SwiftDaoImpl.class);
addDao("AgentTransferMapDao", HostTransferMapDaoImpl.class);
addDao("ElasticLbVmMap", ElasticLbVmMapDaoImpl.class);
}
@Override
@ -312,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

View File

@ -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;

View File

@ -0,0 +1,103 @@
/**
* Copyright (C) 2011 Citrix Systems, 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;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables;
import javax.persistence.Table;
import com.cloud.utils.net.Ip;
@Entity
@Table(name = ("elastic_lb_vm_map"))
@SecondaryTables({
@SecondaryTable(name = "user_ip_address", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "ip_addr_id", referencedColumnName = "id") })
})
public class ElasticLbVmMapVO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "lb_id")
private Long lbId;
@Column(name = "ip_addr_id")
private long ipAddressId;
@Column(name = "elb_vm_id")
private long elbVmId;
/*@Column(name = "name", table = "load_balancing_rules", insertable = false, updatable = false)
private String lbName;*/
@Column(name = "public_ip_address", table = "user_ip_address", insertable = false, updatable = false)
@Enumerated(value=EnumType.STRING)
private Ip address = null;
public ElasticLbVmMapVO() {
}
public ElasticLbVmMapVO(long ipId, long elbVmId, long lbId) {
this.ipAddressId = ipId;
this.elbVmId = elbVmId;
this.lbId = lbId;
}
public Long getId() {
return id;
}
public long getLbId() {
return lbId;
}
public long getElbVmId() {
return elbVmId;
}
// public String getLbName() {
// return lbName;
// }
public long getIpAddressId() {
return ipAddressId;
}
public void setLbId(Long lbId) {
this.lbId = lbId;
}
public Ip getAddress() {
return address;
}
}

View File

@ -562,6 +562,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;
@ -604,7 +614,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);
@ -745,7 +755,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
NetworkOfferingVO guestNetworkOffering = new NetworkOfferingVO(NetworkOffering.SystemGuestNetwork, "System Offering for System-Guest-Network", TrafficType.Guest, true, false, null, null,
null, true, Availability.Required,
// services - all true except for firewall/lb/vpn and gateway services
true, true, true, false, false, false, false, GuestIpType.Direct);
true, true, true, false, false, true, false, GuestIpType.Direct);
guestNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(guestNetworkOffering);
_systemNetworks.put(NetworkOfferingVO.SystemGuestNetwork, guestNetworkOffering);
@ -757,8 +767,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();

View File

@ -0,0 +1,169 @@
/**
* 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.element;
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.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
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.Network.Capability;
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.dao.NetworkDao;
import com.cloud.network.lb.ElasticLoadBalancerManager;
import com.cloud.network.rules.FirewallRule;
import com.cloud.offering.NetworkOffering;
import com.cloud.offerings.dao.NetworkOfferingDao;
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<Service, Map<Capability, String>> capabilities = setCapabilities();
@Inject NetworkManager _networkManager;
@Inject ElasticLoadBalancerManager _lbMgr;
@Inject ConfigurationDao _configDao;
@Inject NetworkOfferingDao _networkOfferingDao;
@Inject NetworkDao _networksDao;
boolean _enabled;
TrafficType _frontEndTrafficType = TrafficType.Guest;
private boolean canHandle(Network network) {
if (network.getGuestType() != Network.GuestIpType.Direct || network.getTrafficType() != TrafficType.Guest) {
s_logger.debug("Not handling network with guest Type " + network.getGuestType() + " and traffic type " + network.getTrafficType());
return false;
}
return true;
}
@Override
public Provider getProvider() {
return Provider.ElasticLoadBalancerVm;
}
@Override
public Map<Service, Map<Capability, String>> getCapabilities() {
return capabilities;
}
private static Map<Service, Map<Capability, String>> setCapabilities() {
Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
Map<Capability, String> lbCapabilities = new HashMap<Capability, String>();
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);
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
String enabled = _configDao.getValue(Config.ElasticLoadBalancerEnabled.key());
_enabled = (enabled == null) ? false: Boolean.parseBoolean(enabled);
if (_enabled) {
String traffType = _configDao.getValue(Config.ElasticLoadBalancerNetwork.key());
if ("guest".equalsIgnoreCase(traffType)) {
_frontEndTrafficType = TrafficType.Guest;
} else if ("public".equalsIgnoreCase(traffType)){
_frontEndTrafficType = TrafficType.Public;
} else
throw new ConfigurationException("Traffic type for front end of load balancer has to be guest or public; found : " + traffType);
}
return true;
}
}

View File

@ -0,0 +1,42 @@
/**
* 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.util.List;
import com.cloud.api.commands.CreateLoadBalancerRuleCmd;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.LoadBalancer;
import com.cloud.user.Account;
public interface ElasticLoadBalancerManager {
public static final int DEFAULT_ELB_VM_RAMSIZE = 128; // 512 MB
public static final int DEFAULT_ELB_VM_CPU_MHZ = 256; // 500 MHz
public boolean applyLoadBalancerRules(Network network,
List<? extends FirewallRule> rules)
throws ResourceUnavailableException;
public LoadBalancer handleCreateLoadBalancerRule(CreateLoadBalancerRuleCmd lb, Account caller) throws InsufficientAddressCapacityException, NetworkRuleConflictException;
public void handleDeleteLoadBalancerRule(LoadBalancer lb, long callerUserId, Account caller);
}

View File

@ -0,0 +1,982 @@
/**
* Copyright (C) 2011 Citrix Systems, 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.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
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.StopAnswer;
import com.cloud.agent.api.check.CheckSshAnswer;
import com.cloud.agent.api.check.CheckSshCommand;
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.api.commands.CreateLoadBalancerRuleCmd;
import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.Pod;
import com.cloud.dc.PodVlanMapVO;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.PodVlanMapDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.ElasticLbVmMapVO;
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.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;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.lb.LoadBalancingRule.LbDestination;
import com.cloud.network.lb.dao.ElasticLbVmMapDao;
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.network.rules.LoadBalancer;
import com.cloud.offering.NetworkOffering;
import com.cloud.offerings.NetworkOfferingVO;
import com.cloud.offerings.dao.NetworkOfferingDao;
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.user.UserContext;
import com.cloud.user.dao.AccountDao;
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.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.ReservationContext;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineGuru;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineGuru;
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, VirtualMachineGuru<DomainRouterVO> {
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;
@Inject
LoadBalancerDao _lbDao;
@Inject
VlanDao _vlanDao;
@Inject
PodVlanMapDao _podVlanMapDao;
@Inject
ElasticLbVmMapDao _elbVmMapDao;
@Inject
NetworkDao _networksDao;
@Inject
AccountDao _accountDao;
String _name;
String _instance;
static final private String _elbVmNamePrefix = "l";
static final private String _systemVmType = "elbvm";
boolean _enabled;
TrafficType _frontendTrafficType = TrafficType.Guest;
Account _systemAcct;
ServiceOfferingVO _elasticLbVmOffering;
ScheduledExecutorService _gcThreadPool;
String _mgmtCidr;
String _mgmtHost;
Set<Long> _gcCandidateElbVmIds = Collections.newSetFromMap(new ConcurrentHashMap<Long,Boolean>());
int _elasticLbVmRamSize;
int _elasticLbvmCpuMHz;
int _elasticLbvmNumCpu;
private Long getPodIdForDirectIp(IPAddressVO ipAddr) {
List<PodVlanMapVO> podVlanMaps = _podVlanMapDao.listPodVlanMapsByVlan(ipAddr.getVlanId());
if (podVlanMaps.isEmpty()) {
return null;
} else {
return podVlanMaps.get(0).getPodId();
}
}
public DomainRouterVO deployLoadBalancerVM(Long networkId, IPAddressVO ipAddr, Long accountId) {
NetworkVO network = _networkDao.findById(networkId);
DataCenter dc = _dcDao.findById(network.getDataCenterId());
Long podId = getPodIdForDirectIp(ipAddr);
Pod pod = podId == null?null:_podDao.findById(podId);
Map<VirtualMachineProfile.Param, Object> params = new HashMap<VirtualMachineProfile.Param, Object>(
1);
params.put(VirtualMachineProfile.Param.RestartNetwork, true);
Account owner = _accountService.getActiveAccount("system", new Long(1));
DeployDestination dest = new DeployDestination(dc, pod, null, null);
s_logger.debug("About to deploy ELB vm ");
try {
DomainRouterVO elbVm = deployELBVm(network, dest, owner, params);
if (elbVm == null) {
throw new InvalidParameterValueException("Could not deploy or find existing ELB VM");
}
s_logger.debug("Deployed ELB vm = " + elbVm);
return elbVm;
} catch (Throwable t) {
s_logger.warn("Error while deploying ELB VM: " + t);
return null;
}
}
private boolean sendCommandsToRouter(final DomainRouterVO elbVm,
Commands cmds) throws AgentUnavailableException {
Answer[] answers = null;
try {
answers = _agentMgr.send(elbVm.getHostId(), cmds);
} catch (OperationTimedoutException e) {
s_logger.warn("ELB: Timed Out", e);
throw new AgentUnavailableException(
"Unable to send commands to virtual elbVm ",
elbVm.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<LoadBalancingRule> rules, DomainRouterVO elbVm, Commands cmds) {
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();
String elbIp = _networkMgr.getIp(rule.getSourceIpAddressId()).getAddress()
.addr();
int srcPort = rule.getSourcePortStart();
List<LbDestination> destinations = rule.getDestinations();
LoadBalancerTO lb = new LoadBalancerTO(elbIp, srcPort, protocol, null,
algorithm, revoked, false, destinations);
lbs[i++] = lb;
}
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs);
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP,
elbVm.getPrivateIpAddress());
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME,
elbVm.getInstanceName());
cmds.addCommand(cmd);
}
protected boolean applyLBRules(DomainRouterVO elbVm,
List<LoadBalancingRule> rules) throws ResourceUnavailableException {
Commands cmds = new Commands(OnError.Continue);
createApplyLoadBalancingRulesCommands(rules, elbVm, cmds);
// Send commands to elbVm
return sendCommandsToRouter(elbVm, cmds);
}
protected DomainRouterVO findElbVmForLb(FirewallRule lb) {//TODO: use a table to lookup
ElasticLbVmMapVO map = _elbVmMapDao.findOneByIp(lb.getSourceIpAddressId());
if (map == null) {
return null;
}
DomainRouterVO elbVm = _routerDao.findById(map.getElbVmId());
return elbVm;
}
public boolean applyLoadBalancerRules(Network network,
List<? extends FirewallRule> rules)
throws ResourceUnavailableException {
if (rules == null || rules.isEmpty()) {
return true;
}
if (rules.get(0).getPurpose() != Purpose.LoadBalancing) {
s_logger.warn("ELB: Not handling non-LB firewall rules");
return false;
}
DomainRouterVO elbVm = findElbVmForLb(rules.get(0));
if (elbVm == null) {
s_logger.warn("Unable to apply lb rules, ELB vm doesn't exist in the network "
+ network.getId());
throw new ResourceUnavailableException("Unable to apply lb rules",
DataCenter.class, network.getDataCenterId());
}
if (elbVm.getState() == State.Running) {
//resend all rules for the public ip
List<LoadBalancerVO> lbs = _lbDao.listByIpAddress(rules.get(0).getSourceIpAddressId());
List<LoadBalancingRule> lbRules = new ArrayList<LoadBalancingRule>();
for (LoadBalancerVO lb : lbs) {
List<LbDestination> dstList = _lbMgr.getExistingDestinations(lb.getId());
LoadBalancingRule loadBalancing = new LoadBalancingRule(
lb, dstList);
lbRules.add(loadBalancing);
}
return applyLBRules(elbVm, lbRules);
} else if (elbVm.getState() == State.Stopped
|| elbVm.getState() == State.Stopping) {
s_logger.debug("ELB VM is in "
+ elbVm.getState()
+ ", so not sending apply LoadBalancing rules commands to the backend");
return true;
} else {
s_logger.warn("Unable to apply loadbalancing rules, ELB VM is not in the right state "
+ elbVm.getState());
throw new ResourceUnavailableException(
"Unable to apply loadbalancing rules, ELB VM is not in the right state",
VirtualRouter.class, elbVm.getId());
}
}
@Override
public boolean configure(String name, Map<String, Object> params)
throws ConfigurationException {
_name = name;
final Map<String, String> configs = _configDao.getConfiguration("AgentManager", params);
_systemAcct = _accountService.getSystemAccount();
_instance = configs.get("instance.name");
if (_instance == null) {
_instance = "VM";
}
_mgmtCidr = _configDao.getValue(Config.ManagementNetwork.key());
_mgmtHost = _configDao.getValue(Config.ManagementHostIPAdr.key());
boolean useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));
_elasticLbVmRamSize = NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmMemory.key()), DEFAULT_ELB_VM_RAMSIZE);
_elasticLbvmCpuMHz = NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmCpuMhz.key()), DEFAULT_ELB_VM_CPU_MHZ);
_elasticLbvmNumCpu = NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmNumVcpu.key()), 1);
_elasticLbVmOffering = new ServiceOfferingVO("System Offering For Elastic LB VM", _elasticLbvmNumCpu,
_elasticLbVmRamSize, _elasticLbvmCpuMHz, 0, 0, true, null, useLocalStorage,
true, null, true, VirtualMachine.Type.ElasticLoadBalancerVm, true);
_elasticLbVmOffering.setUniqueName("Cloud.Com-ElasticLBVm");
_elasticLbVmOffering = _serviceOfferingDao.persistSystemServiceOffering(_elasticLbVmOffering);
String enabled = _configDao.getValue(Config.ElasticLoadBalancerEnabled.key());
_enabled = (enabled == null) ? false: Boolean.parseBoolean(enabled);
s_logger.info("Elastic Load balancer enabled: " + _enabled);
if (_enabled) {
String traffType = _configDao.getValue(Config.ElasticLoadBalancerNetwork.key());
if ("guest".equalsIgnoreCase(traffType)) {
_frontendTrafficType = TrafficType.Guest;
} else if ("public".equalsIgnoreCase(traffType)){
_frontendTrafficType = TrafficType.Public;
} else
throw new ConfigurationException("ELB: Traffic type for front end of load balancer has to be guest or public; found : " + traffType);
s_logger.info("ELB: Elastic Load Balancer: will balance on " + traffType );
int gcIntervalMinutes = NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmGcInterval.key()), 5);
if (gcIntervalMinutes < 5)
gcIntervalMinutes = 5;
s_logger.info("ELB: Elastic Load Balancer: scheduling GC to run every " + gcIntervalMinutes + " minutes" );
_gcThreadPool = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ELBVM-GC"));
_gcThreadPool.scheduleAtFixedRate(new CleanupThread(), gcIntervalMinutes, gcIntervalMinutes, TimeUnit.MINUTES);
_itMgr.registerGuru(VirtualMachine.Type.ElasticLoadBalancerVm, this);
}
return true;
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public String getName() {
return _name;
}
private DomainRouterVO findELBVmWithCapacity(Network guestNetwork, IPAddressVO ipAddr) {
List<DomainRouterVO> unusedElbVms = _elbVmMapDao.listUnusedElbVms();
if (unusedElbVms.size() > 0) {
List<DomainRouterVO> candidateVms = new ArrayList<DomainRouterVO>();
for (DomainRouterVO candidateVm: unusedElbVms) {
if (candidateVm.getPodIdToDeployIn() == getPodIdForDirectIp(ipAddr))
candidateVms.add(candidateVm);
}
return candidateVms.size()==0?null:candidateVms.get(new Random().nextInt(candidateVms.size()));
}
return null;
}
public DomainRouterVO deployELBVm(Network guestNetwork, DeployDestination dest, Account owner, Map<Param, Object> 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 lock: " + 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 ELB 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 elbVm = null;
plan = new DataCenterDeployment(dcId, dest.getPod().getId(), null, null, null);
if (elbVm == null) {
long id = _routerDao.getNextInSequence(Long.class, "id");
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating the ELB vm " + id);
}
List<NetworkOfferingVO> offerings = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemControlNetwork);
NetworkOfferingVO controlOffering = offerings.get(0);
NetworkVO controlConfig = _networkMgr.setupNetwork(_systemAcct, controlOffering, plan, null, null, false, false).get(0);
List<Pair<NetworkVO, NicProfile>> networks = new ArrayList<Pair<NetworkVO, NicProfile>>(2);
NicProfile guestNic = new NicProfile();
guestNic.setDefaultNic(true);
networks.add(new Pair<NetworkVO, NicProfile>((NetworkVO) guestNetwork, guestNic));
networks.add(new Pair<NetworkVO, NicProfile>(controlConfig, null));
VMTemplateVO template = _templateDao.findSystemVMTemplate(dcId);
elbVm = new DomainRouterVO(id, _elasticLbVmOffering.getId(), VirtualMachineName.getSystemVmName(id, _instance, _elbVmNamePrefix), template.getId(), template.getHypervisorType(), template.getGuestOSId(),
owner.getDomainId(), owner.getId(), guestNetwork.getId(), _elasticLbVmOffering.getOfferHA(), VirtualMachine.Type.ElasticLoadBalancerVm);
elbVm.setRole(Role.LB);
elbVm = _itMgr.allocate(elbVm, template, _elasticLbVmOffering, networks, plan, null, owner);
//TODO: create usage stats
}
State state = elbVm.getState();
if (state != State.Running) {
elbVm = this.start(elbVm, _accountService.getSystemUser(), _accountService.getSystemAccount(), params);
}
return elbVm;
} finally {
_networkDao.releaseFromLockTable(guestNetworkId);
}
}
private DomainRouterVO start(DomainRouterVO elbVm, User user, Account caller, Map<Param, Object> params) throws StorageUnavailableException, InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException {
s_logger.debug("Starting ELB VM " + elbVm);
if (_itMgr.start(elbVm, params, user, caller) != null) {
return _routerDao.findById(elbVm.getId());
} else {
return null;
}
}
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<LoadBalancerVO> findExistingLoadBalancers(String lbName, Long ipId, Long accountId, Long domainId, Integer publicPort) {
SearchBuilder<LoadBalancerVO> sb = _lbDao.createSearchBuilder();
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
sb.and("publicPort", sb.entity().getSourcePortStart(), SearchCriteria.Op.EQ);
if (ipId != null) {
sb.and("sourceIpAddress", sb.entity().getSourceIpAddressId(), SearchCriteria.Op.EQ);
}
if (domainId != null) {
sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.EQ);
}
if (publicPort != null) {
sb.and("publicPort", sb.entity().getSourcePortStart(), SearchCriteria.Op.EQ);
}
SearchCriteria<LoadBalancerVO> sc = sb.create();
sc.setParameters("name", lbName);
sc.setParameters("accountId", accountId);
if (ipId != null) {
sc.setParameters("sourceIpAddress", ipId);
}
if (domainId != null) {
sc.setParameters("domainId",domainId);
}
if (publicPort != null) {
sc.setParameters("publicPort", publicPort);
}
List<LoadBalancerVO> lbs = _lbDao.search(sc, null);
return lbs == null || lbs.size()==0 ? null: lbs;
}
@DB
public PublicIp allocIp(CreateLoadBalancerRuleCmd lb, Account account) throws InsufficientAddressCapacityException {
//TODO: this only works in the guest network. Handle the public network case also.
List<NetworkOfferingVO> offerings = _networkOfferingDao.listByTrafficTypeAndGuestType(true, _frontendTrafficType, GuestIpType.Direct);
if (offerings == null || offerings.size() == 0) {
s_logger.warn("ELB: Could not find system offering for direct networks of type " + _frontendTrafficType);
return null;
}
NetworkOffering frontEndOffering = offerings.get(0);
List<NetworkVO> networks = _networksDao.listBy(Account.ACCOUNT_ID_SYSTEM, frontEndOffering.getId(), lb.getZoneId());
if (networks == null || networks.size() == 0) {
s_logger.warn("ELB: Could not find network of offering type " + frontEndOffering + " in zone " + lb.getZoneId());
return null;
}
Network frontEndNetwork = networks.get(0);
Transaction txn = Transaction.currentTxn();
txn.start();
PublicIp ip = _networkMgr.assignPublicIpAddress(lb.getZoneId(), null, account, VlanType.DirectAttached, frontEndNetwork.getId(), null);
IPAddressVO ipvo = _ipAddressDao.findById(ip.getId());
ipvo.setAssociatedWithNetworkId(frontEndNetwork.getId());
_ipAddressDao.update(ipvo.getId(), ipvo);
txn.commit();
s_logger.info("Acquired frontend IP for ELB " + ip);
return ip;
}
public void releaseIp(long ipId, long userId, Account caller) {
s_logger.info("ELB: Release public IP for loadbalancing " + ipId);
IPAddressVO ipvo = _ipAddressDao.findById(ipId);
ipvo.setAssociatedWithNetworkId(null);
_ipAddressDao.update(ipvo.getId(), ipvo);
_networkMgr.releasePublicIpAddress(ipId, userId, caller);
_ipAddressDao.unassignIpAddress(ipId);
}
protected NetworkVO getNetworkToDeployLb(Long ipId) {
IPAddressVO ipAddr = _ipAddressDao.findById(ipId);
Long networkId= ipAddr.getSourceNetworkId();
NetworkVO network=_networkDao.findById(networkId);
if (network.getGuestType() != GuestIpType.Direct) {
s_logger.info("ELB: not handling guest traffic of type " + network.getGuestType());
return null;
}
return network;
}
@Override
@DB
public LoadBalancer handleCreateLoadBalancerRule( CreateLoadBalancerRuleCmd lb, Account account) throws InsufficientAddressCapacityException, NetworkRuleConflictException {
Long ipId = lb.getSourceIpAddressId();
if (ipId != null && getNetworkToDeployLb(ipId) == null) {
return null;
}
boolean newIp = false;
account = _accountDao.acquireInLockTable(account.getId());
if (account == null) {
s_logger.warn("ELB: CreateLoadBalancer: Failed to acquire lock on account");
throw new CloudRuntimeException("Failed to acquire lock on account");
}
try {
List<LoadBalancerVO> existingLbs = findExistingLoadBalancers(lb.getName(), lb.getSourceIpAddressId(), lb.getAccountId(), lb.getDomainId(), lb.getSourcePortStart());
if (existingLbs == null ){
existingLbs = findExistingLoadBalancers(lb.getName(), lb.getSourceIpAddressId(), lb.getAccountId(), lb.getDomainId(), null);
if (existingLbs == null) {
if (lb.getSourceIpAddressId() != null) {
existingLbs = findExistingLoadBalancers(lb.getName(), null, lb.getAccountId(), lb.getDomainId(), null);
if (existingLbs != null) {
throw new InvalidParameterValueException("Supplied LB name " + lb.getName() + " is not associated with IP " + lb.getSourceIpAddressId() );
}
} else {
s_logger.debug("Could not find any existing frontend ips for this account for this LB rule, acquiring a new frontent IP for ELB");
PublicIp ip = allocIp(lb, account);
ipId = ip.getId();
newIp = true;
}
} else {
ipId = existingLbs.get(0).getSourceIpAddressId();
s_logger.debug("ELB: Found existing frontend ip for this account for this LB rule " + ipId);
}
} else {
s_logger.warn("ELB: Found existing load balancers matching requested new LB");
throw new NetworkRuleConflictException("ELB: Found existing load balancers matching requested new LB");
}
NetworkVO network = getNetworkToDeployLb(ipId);
IPAddressVO ipAddr = _ipAddressDao.findById(ipId);
long networkId = network.getId();
LoadBalancer result = null;
try {
lb.setSourceIpAddressId(ipId);
result = _lbMgr.createLoadBalancer(lb);
} catch (NetworkRuleConflictException e) {
s_logger.warn("Failed to create LB rule, not continuing with ELB deployment");
if (newIp) {
releaseIp(ipId, UserContext.current().getCallerUserId(), account);
}
throw e;
}
DomainRouterVO elbVm = null;
if (existingLbs == null) {
elbVm = findELBVmWithCapacity(network, ipAddr);
if (elbVm == null) {
elbVm = deployLoadBalancerVM(networkId, ipAddr, account.getId());
if (elbVm == null) {
s_logger.warn("Failed to deploy a new ELB vm for ip " + ipAddr + " in network " + network + "lb name=" + lb.getName());
if (newIp)
releaseIp(ipId, UserContext.current().getCallerUserId(), account);
}
}
} else {
ElasticLbVmMapVO elbVmMap = _elbVmMapDao.findOneByIp(ipId);
if (elbVmMap != null) {
elbVm = _routerDao.findById(elbVmMap.getElbVmId());
}
}
if (elbVm == null) {
s_logger.warn("No ELB VM can be found or deployed");
s_logger.warn("Deleting LB since we failed to deploy ELB VM");
_lbDao.remove(result.getId());
return null;
}
ElasticLbVmMapVO mapping = new ElasticLbVmMapVO(ipId, elbVm.getId(), result.getId());
_elbVmMapDao.persist(mapping);
return result;
} finally {
if (account != null) {
_accountDao.releaseFromLockTable(account.getId());
}
}
}
void garbageCollectUnusedElbVms() {
List<DomainRouterVO> unusedElbVms = _elbVmMapDao.listUnusedElbVms();
if (unusedElbVms != null && unusedElbVms.size() > 0)
s_logger.info("Found " + unusedElbVms.size() + " unused ELB vms");
Set<Long> currentGcCandidates = new HashSet<Long>();
for (DomainRouterVO elbVm: unusedElbVms) {
currentGcCandidates.add(elbVm.getId());
}
_gcCandidateElbVmIds.retainAll(currentGcCandidates);
currentGcCandidates.removeAll(_gcCandidateElbVmIds);
User user = _accountService.getSystemUser();
for (Long elbVmId : _gcCandidateElbVmIds) {
DomainRouterVO elbVm = _routerDao.findById(elbVmId);
boolean gceed = false;
try {
s_logger.info("Attempting to stop ELB VM: " + elbVm);
stop(elbVm, true, user, _systemAcct);
gceed = true;
} catch (ConcurrentOperationException e) {
s_logger.warn("Unable to stop unused ELB vm " + elbVm + " due to ", e);
} catch (ResourceUnavailableException e) {
s_logger.warn("Unable to stop unused ELB vm " + elbVm + " due to ", e);
continue;
}
if (gceed) {
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);
gceed = false;
}
}
if (!gceed) {
currentGcCandidates.add(elbVm.getId());
}
}
_gcCandidateElbVmIds = currentGcCandidates;
}
public class CleanupThread implements Runnable {
@Override
public void run() {
garbageCollectUnusedElbVms();
}
CleanupThread() {
}
}
@Override
public void handleDeleteLoadBalancerRule(LoadBalancer lb, long userId, Account caller) {
List<LoadBalancerVO> remainingLbs = _loadBalancerDao.listByIpAddress(lb.getSourceIpAddressId());
if (remainingLbs.size() == 0) {
s_logger.debug("ELB mgr: releasing ip " + lb.getSourceIpAddressId() + " since no LB rules remain for this ip address");
releaseIp(lb.getSourceIpAddressId(), userId, caller);
}
}
@Override
public DomainRouterVO findByName(String name) {
if (!VirtualMachineName.isValidSystemVmName(name, _instance, _elbVmNamePrefix)) {
return null;
}
return _routerDao.findById(VirtualMachineName.getSystemVmId(name));
}
@Override
public DomainRouterVO findById(long id) {
return _routerDao.findById(id);
}
@Override
public DomainRouterVO persist(DomainRouterVO elbVm) {
return _routerDao.persist(elbVm);
}
@Override
public boolean finalizeVirtualMachineProfile(VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest, ReservationContext context) {
DomainRouterVO elbVm = profile.getVirtualMachine();
NetworkVO network = _networkDao.findById(elbVm.getNetworkId());
DataCenter dc = dest.getDataCenter();
StringBuilder buf = profile.getBootArgsBuilder();
buf.append(" template=domP type=" + _systemVmType);
buf.append(" name=").append(profile.getHostName());
NicProfile controlNic = null;
String defaultDns1 = null;
String defaultDns2 = null;
for (NicProfile nic : profile.getNics()) {
int deviceId = nic.getDeviceId();
buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address());
buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask());
if (nic.isDefaultNic()) {
buf.append(" gateway=").append(nic.getGateway());
defaultDns1 = nic.getDns1();
defaultDns2 = nic.getDns2();
}
if (nic.getTrafficType() == TrafficType.Management) {
buf.append(" localgw=").append(dest.getPod().getGateway());
} else if (nic.getTrafficType() == TrafficType.Control) {
// control command is sent over management network in VMware
if (dest.getHost().getHypervisorType() == HypervisorType.VMware) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Check if we need to add management server explicit route to ELB vm. pod cidr: " + dest.getPod().getCidrAddress() + "/" + dest.getPod().getCidrSize()
+ ", pod gateway: " + dest.getPod().getGateway() + ", management host: " + _mgmtHost);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Added management server explicit route to ELB vm.");
}
// always add management explicit route, for basic networking setup
buf.append(" mgmtcidr=").append(_mgmtCidr);
buf.append(" localgw=").append(dest.getPod().getGateway());
if (dc.getNetworkType() == NetworkType.Basic) {
// ask elb vm to setup SSH on guest network
buf.append(" sshonguest=true");
}
}
controlNic = nic;
}
}
String domain = network.getNetworkDomain();
if (domain != null) {
buf.append(" domain=" + domain);
}
buf.append(" dns1=").append(defaultDns1);
if (defaultDns2 != null) {
buf.append(" dns2=").append(defaultDns2);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Boot Args for " + profile + ": " + buf.toString());
}
if (controlNic == null) {
throw new CloudRuntimeException("Didn't start a control port");
}
return true;
}
@Override
public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException {
DomainRouterVO elbVm = profile.getVirtualMachine();
List<NicProfile> nics = profile.getNics();
for (NicProfile nic : nics) {
if (nic.getTrafficType() == TrafficType.Public) {
elbVm.setPublicIpAddress(nic.getIp4Address());
elbVm.setPublicNetmask(nic.getNetmask());
elbVm.setPublicMacAddress(nic.getMacAddress());
} else if (nic.getTrafficType() == TrafficType.Guest) {
elbVm.setGuestIpAddress(nic.getIp4Address());
} else if (nic.getTrafficType() == TrafficType.Control) {
elbVm.setPrivateIpAddress(nic.getIp4Address());
elbVm.setPrivateMacAddress(nic.getMacAddress());
}
}
_routerDao.update(elbVm.getId(), elbVm);
finalizeCommandsOnStart(cmds, profile);
return true;
}
@Override
public boolean finalizeStart(VirtualMachineProfile<DomainRouterVO> profile, long hostId, Commands cmds, ReservationContext context) {
CheckSshAnswer answer = (CheckSshAnswer) cmds.getAnswer("checkSsh");
if (answer == null || !answer.getResult()) {
s_logger.warn("Unable to ssh to the ELB VM: " + answer.getDetails());
return false;
}
return true;
}
@Override
public boolean finalizeCommandsOnStart(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile) {
DomainRouterVO elbVm = profile.getVirtualMachine();
DataCenterVO dcVo = _dcDao.findById(elbVm.getDataCenterIdToDeployIn());
NicProfile controlNic = null;
if(profile.getHypervisorType() == HypervisorType.VMware && dcVo.getNetworkType() == NetworkType.Basic) {
// TODO this is a ugly to test hypervisor type here
// for basic network mode, we will use the guest NIC for control NIC
for (NicProfile nic : profile.getNics()) {
if (nic.getTrafficType() == TrafficType.Guest && nic.getIp4Address() != null) {
controlNic = nic;
}
}
} else {
for (NicProfile nic : profile.getNics()) {
if (nic.getTrafficType() == TrafficType.Control && nic.getIp4Address() != null) {
controlNic = nic;
}
}
}
if (controlNic == null) {
s_logger.error("Control network doesn't exist for the ELB vm " + elbVm);
return false;
}
cmds.addCommand("checkSsh", new CheckSshCommand(profile.getInstanceName(), controlNic.getIp4Address(), 3922, 5, 20));
// Re-apply load balancing rules
List<LoadBalancerVO> lbs = _elbVmMapDao.listLbsForElbVm(elbVm.getId());
List<LoadBalancingRule> lbRules = new ArrayList<LoadBalancingRule>();
for (LoadBalancerVO lb : lbs) {
List<LbDestination> dstList = _lbMgr.getExistingDestinations(lb.getId());
LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList);
lbRules.add(loadBalancing);
}
s_logger.debug("Found " + lbRules.size() + " load balancing rule(s) to apply as a part of ELB vm " + elbVm + " start.");
if (!lbRules.isEmpty()) {
createApplyLoadBalancingRulesCommands(lbRules, elbVm, cmds);
}
return true;
}
@Override
public void finalizeStop(VirtualMachineProfile<DomainRouterVO> profile, StopAnswer answer) {
if (answer != null) {
VMInstanceVO vm = profile.getVirtualMachine();
DomainRouterVO elbVm = _routerDao.findById(vm.getId());
processStopOrRebootAnswer(elbVm, answer);
}
}
public void processStopOrRebootAnswer(final DomainRouterVO elbVm, Answer answer) {
//TODO: process network usage stats
}
@Override
public void finalizeExpunge(DomainRouterVO vm) {
// no-op
}
@Override
public Long convertToId(String vmName) {
if (!VirtualMachineName.isValidSystemVmName(vmName, _instance, _elbVmNamePrefix)) {
return null;
}
return VirtualMachineName.getSystemVmId(vmName);
}
}

View File

@ -19,11 +19,17 @@ package com.cloud.network.lb;
import java.util.List;
import com.cloud.api.commands.CreateLoadBalancerRuleCmd;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.lb.LoadBalancingRule.LbDestination;
import com.cloud.network.rules.LoadBalancer;
import com.cloud.user.Account;
public interface LoadBalancingRulesManager extends LoadBalancingRulesService {
LoadBalancer createLoadBalancer(CreateLoadBalancerRuleCmd lb) throws NetworkRuleConflictException;
boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId);
boolean removeAllLoadBalanacersForNetwork(long networkId, Account caller, long callerUserId);
List<LbDestination> getExistingDestinations(long lbId);

View File

@ -30,6 +30,7 @@ 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;
@ -42,6 +43,7 @@ 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;
@ -49,14 +51,15 @@ 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.Service;
import com.cloud.network.NetworkManager;
import com.cloud.network.dao.FirewallRulesCidrsDao;
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;
@ -70,6 +73,7 @@ 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.Adapters;
import com.cloud.utils.component.Inject;
import com.cloud.utils.component.Manager;
import com.cloud.utils.db.DB;
@ -122,6 +126,11 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager,
UsageEventDao _usageEventDao;
@Inject
FirewallRulesCidrsDao _firewallCidrsDao;
@Inject
ElasticLoadBalancerManager _elbMgr;
@Inject
NetworkDao _networkDao;
@Override
@DB
@ -340,23 +349,15 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager,
}
_rulesDao.remove(lb.getId());
_elbMgr.handleDeleteLoadBalancerRule(lb, callerUserId, caller);
s_logger.debug("Load balancer with id " + lb.getId() + " is removed successfully");
return true;
}
@Override @DB
@ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer")
public LoadBalancer createLoadBalancerRule(LoadBalancer lb) throws NetworkRuleConflictException {
public LoadBalancer createLoadBalancerRule(CreateLoadBalancerRuleCmd lb) throws NetworkRuleConflictException, InsufficientAddressCapacityException {
UserContext caller = UserContext.current();
long ipId = lb.getSourceIpAddressId();
// make sure ip address exists
IPAddressVO ipAddr = _ipAddressDao.findById(ipId);
if (ipAddr == null || !ipAddr.readyToUse()) {
throw new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id" + ipId);
}
int srcPortStart = lb.getSourcePortStart();
int srcPortEnd = lb.getSourcePortEnd();
int defPortStart = lb.getDefaultPortStart();
@ -384,7 +385,29 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager,
throw new InvalidParameterValueException("Invalid algorithm: " + lb.getAlgorithm());
}
Long networkId = ipAddr.getAssociatedWithNetworkId();
LoadBalancer result = _elbMgr.handleCreateLoadBalancerRule(lb, caller.getCaller());
if (result == null){
result = createLoadBalancer(lb);
}
return result;
}
@DB
public LoadBalancer createLoadBalancer(CreateLoadBalancerRuleCmd lb) throws NetworkRuleConflictException {
long ipId = lb.getSourceIpAddressId();
UserContext caller = UserContext.current();
int srcPortStart = lb.getSourcePortStart();
int defPortStart = lb.getDefaultPortStart();
IPAddressVO ipAddr = _ipAddressDao.findById(lb.getSourceIpAddressId());
Long networkId = ipAddr.getSourceNetworkId();
NetworkVO network = _networkDao.findById(networkId);
// make sure ip address exists
if (ipAddr == null || !ipAddr.readyToUse()) {
throw new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id" + ipId);
}
networkId = ipAddr.getAssociatedWithNetworkId();
if (networkId == null) {
throw new InvalidParameterValueException("Unable to create load balancer rule ; ip id=" + ipId + " is not associated with any network");
@ -393,9 +416,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);
}
Transaction txn = Transaction.currentTxn();

View File

@ -0,0 +1,39 @@
/**
* Copyright (C) 2011 Citrix Systems, 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.dao;
import java.util.List;
import com.cloud.network.ElasticLbVmMapVO;
import com.cloud.network.LoadBalancerVO;
import com.cloud.utils.db.GenericDao;
import com.cloud.vm.DomainRouterVO;
public interface ElasticLbVmMapDao extends GenericDao<ElasticLbVmMapVO, Long> {
ElasticLbVmMapVO findOneByLbIdAndElbVmId(long lbId, long elbVmId);
ElasticLbVmMapVO findOneByIpIdAndElbVmId(long ipId, long elbVmId);
ElasticLbVmMapVO findOneByIp(long ipId);
List<ElasticLbVmMapVO> listByElbVmId(long elbVmId);
List<ElasticLbVmMapVO> listByLbId(long lbId);
int deleteLB(long lbId);
List<DomainRouterVO> listUnusedElbVms();
List<LoadBalancerVO> listLbsForElbVm(long elbVmId);
}

View File

@ -0,0 +1,136 @@
/**
* Copyright (C) 2011 Citrix Systems, 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.dao;
import java.util.List;
import javax.ejb.Local;
import com.cloud.network.ElasticLbVmMapVO;
import com.cloud.network.LoadBalancerVO;
import com.cloud.network.dao.LoadBalancerDao;
import com.cloud.network.dao.LoadBalancerDaoImpl;
import com.cloud.network.router.VirtualRouter.Role;
import com.cloud.network.router.VirtualRouter.Role;
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<ElasticLbVmMapVO, Long> implements ElasticLbVmMapDao {
protected final DomainRouterDao _routerDao = ComponentLocator.inject(DomainRouterDaoImpl.class);
protected final LoadBalancerDao _loadbalancerDao = ComponentLocator.inject(LoadBalancerDaoImpl.class);
protected final SearchBuilder<ElasticLbVmMapVO> AllFieldsSearch;
protected final SearchBuilder<ElasticLbVmMapVO> UnusedVmSearch;
protected final SearchBuilder<ElasticLbVmMapVO> LoadBalancersForElbVmSearch;
protected final SearchBuilder<DomainRouterVO> ElbVmSearch;
protected final SearchBuilder<LoadBalancerVO> LoadBalancerSearch;
protected ElasticLbVmMapDaoImpl() {
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("ipId", AllFieldsSearch.entity().getIpAddressId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("lbId", AllFieldsSearch.entity().getLbId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("elbVmId", AllFieldsSearch.entity().getElbVmId(), SearchCriteria.Op.EQ);
AllFieldsSearch.done();
ElbVmSearch = _routerDao.createSearchBuilder();
ElbVmSearch.and("role", ElbVmSearch.entity().getRole(), SearchCriteria.Op.EQ);
UnusedVmSearch = createSearchBuilder();
UnusedVmSearch.and("elbVmId", UnusedVmSearch.entity().getElbVmId(), SearchCriteria.Op.NULL);
ElbVmSearch.join("UnusedVmSearch", UnusedVmSearch, ElbVmSearch.entity().getId(), UnusedVmSearch.entity().getElbVmId(), JoinType.LEFTOUTER);
ElbVmSearch.done();
UnusedVmSearch.done();
LoadBalancerSearch = _loadbalancerDao.createSearchBuilder();
LoadBalancersForElbVmSearch = createSearchBuilder();
LoadBalancersForElbVmSearch.and("elbVmId", LoadBalancersForElbVmSearch.entity().getElbVmId(), SearchCriteria.Op.EQ);
LoadBalancerSearch.join("LoadBalancersForElbVm", LoadBalancersForElbVmSearch, LoadBalancerSearch.entity().getId(), LoadBalancersForElbVmSearch.entity().getLbId(), JoinType.INNER);
LoadBalancersForElbVmSearch.done();
LoadBalancerSearch.done();
}
@Override
public ElasticLbVmMapVO findOneByLbIdAndElbVmId(long lbId, long elbVmId) {
SearchCriteria<ElasticLbVmMapVO> sc = AllFieldsSearch.create();
sc.setParameters("lbId", lbId);
sc.setParameters("elbVmId", elbVmId);
return findOneBy(sc);
}
@Override
public List<ElasticLbVmMapVO> listByLbId(long lbId) {
SearchCriteria<ElasticLbVmMapVO> sc = AllFieldsSearch.create();
sc.setParameters("lbId", lbId);
return listBy(sc);
}
@Override
public List<ElasticLbVmMapVO> listByElbVmId(long elbVmId) {
SearchCriteria<ElasticLbVmMapVO> sc = AllFieldsSearch.create();
sc.setParameters("elbVmId", elbVmId);
return listBy(sc);
}
@Override
public int deleteLB(long lbId) {
SearchCriteria<ElasticLbVmMapVO> sc = AllFieldsSearch.create();
sc.setParameters("lbId", lbId);
return super.expunge(sc);
}
@Override
public ElasticLbVmMapVO findOneByIpIdAndElbVmId(long ipId, long elbVmId) {
SearchCriteria<ElasticLbVmMapVO> sc = AllFieldsSearch.create();
sc.setParameters("ipId", ipId);
sc.setParameters("elbVmId", elbVmId);
return findOneBy(sc);
}
@Override
public ElasticLbVmMapVO findOneByIp(long ipId) {
SearchCriteria<ElasticLbVmMapVO> sc = AllFieldsSearch.create();
sc.setParameters("ipId", ipId);
return findOneBy(sc);
}
public List<DomainRouterVO> listUnusedElbVms() {
SearchCriteria<DomainRouterVO> sc = ElbVmSearch.create();
sc.setParameters("role", Role.LB);
return _routerDao.search(sc, null);
}
@Override
public List<LoadBalancerVO> listLbsForElbVm(long elbVmId) {
SearchCriteria<LoadBalancerVO> sc = LoadBalancerSearch.create();
sc.setJoinParameters("LoadBalancersForElbVm", "elbVmId", elbVmId);
return _loadbalancerDao.search(sc, null);
}
}

View File

@ -76,6 +76,7 @@ import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.dao.AccountVlanMapDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.DcDetailsDaoImpl;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DataCenterDeployment;
@ -661,8 +662,14 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
cmd.addVmData("metadata", "availability-zone", StringUtils.unicodeEscape(zoneName));
cmd.addVmData("metadata", "local-ipv4", guestIpAddress);
cmd.addVmData("metadata", "local-hostname", StringUtils.unicodeEscape(vmName));
cmd.addVmData("metadata", "public-ipv4", router.getPublicIpAddress());
cmd.addVmData("metadata", "public-hostname", router.getPublicIpAddress());
if (dcVo.getNetworkType() == NetworkType.Basic) {
cmd.addVmData("metadata", "public-ipv4", guestIpAddress);
cmd.addVmData("metadata", "public-hostname", StringUtils.unicodeEscape(vmName));
}else
{
cmd.addVmData("metadata", "public-ipv4", router.getPublicIpAddress());
cmd.addVmData("metadata", "public-hostname", router.getPublicIpAddress());
}
cmd.addVmData("metadata", "instance-id", vmInstanceName);
cmd.addVmData("metadata", "vm-id", String.valueOf(vmId));
cmd.addVmData("metadata", "public-keys", publicKey);
@ -1044,7 +1051,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
// In Basic zone and Guest network we have to start domR per pod, not per network
if (isPodBased) {
routers = _routerDao.findByNetworkAndPod(guestNetwork.getId(), podId);
routers = _routerDao.listByNetworkAndPodAndRole(guestNetwork.getId(), podId, Role.DHCP_USERDATA);
plan = new DataCenterDeployment(dcId, podId, null, null, null);
} else {
routers = _routerDao.findByNetwork(guestNetwork.getId());

View File

@ -810,7 +810,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);
@ -830,7 +830,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);
}

View File

@ -174,8 +174,10 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.info.ConsoleProxyInfo;
import com.cloud.keystore.KeystoreManager;
import com.cloud.network.IPAddressVO;
import com.cloud.network.LoadBalancerVO;
import com.cloud.network.NetworkVO;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.LoadBalancerDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.security.SecurityGroupVO;
import com.cloud.network.security.dao.SecurityGroupDao;
@ -325,6 +327,7 @@ public class ManagementServerImpl implements ManagementServer {
private final UploadMonitor _uploadMonitor;
private final UploadDao _uploadDao;
private final SSHKeyPairDao _sshKeyPairDao;
private final LoadBalancerDao _loadbalancerDao;
private final KeystoreManager _ksMgr;
@ -338,7 +341,7 @@ public class ManagementServerImpl implements ManagementServer {
private String _hashKey = null;
protected ManagementServerImpl() {
public ManagementServerImpl() {
ComponentLocator locator = ComponentLocator.getLocator(Name);
_configDao = locator.getDao(ConfigurationDao.class);
_routerDao = locator.getDao(DomainRouterDao.class);
@ -354,6 +357,7 @@ public class ManagementServerImpl implements ManagementServer {
_clusterDao = locator.getDao(ClusterDao.class);
_nicDao = locator.getDao(NicDao.class);
_networkDao = locator.getDao(NetworkDao.class);
_loadbalancerDao = locator.getDao(LoadBalancerDao.class);
_accountMgr = locator.getManager(AccountManager.class);
_agentMgr = locator.getManager(AgentManager.class);
@ -2501,6 +2505,7 @@ public class ManagementServerImpl implements ManagementServer {
Object address = cmd.getIpAddress();
Object vlan = cmd.getVlanId();
Object forVirtualNetwork = cmd.isForVirtualNetwork();
Object forLoadBalancing = cmd.isForLoadBalancing();
Object ipId = cmd.getId();
SearchBuilder<IPAddressVO> sb = _publicIpAddressDao.createSearchBuilder();
@ -2517,6 +2522,12 @@ public class ManagementServerImpl implements ManagementServer {
sb.join("domainSearch", domainSearch, sb.entity().getAllocatedInDomainId(), domainSearch.entity().getId(), JoinBuilder.JoinType.INNER);
}
if (forLoadBalancing != null && (Boolean)forLoadBalancing) {
SearchBuilder<LoadBalancerVO> lbSearch = _loadbalancerDao.createSearchBuilder();
sb.join("lbSearch", lbSearch, sb.entity().getId(), lbSearch.entity().getSourceIpAddressId(), JoinType.INNER);
sb.groupBy(sb.entity().getId());
}
if (keyword != null && address == null) {
sb.and("addressLIKE", sb.entity().getAddress(), SearchCriteria.Op.LIKE);
}
@ -4195,9 +4206,18 @@ public class ManagementServerImpl implements ManagementServer {
Map<String, Object> capabilities = new HashMap<String, Object>();
boolean securityGroupsEnabled = false;
boolean elasticLoadBalancerEnabled = false;
String supportELB = "false";
List<DataCenterVO> dc = _dcDao.listSecurityGroupEnabledZones();
if (dc != null && !dc.isEmpty()) {
securityGroupsEnabled = true;
String elbEnabled = _configDao.getValue(Config.ElasticLoadBalancerEnabled.key());
elasticLoadBalancerEnabled = elbEnabled==null?false:Boolean.parseBoolean(elbEnabled);
if (elasticLoadBalancerEnabled) {
String networkType = _configDao.getValue(Config.ElasticLoadBalancerNetwork.key());
if (networkType != null)
supportELB = networkType;
}
}
String userPublicTemplateEnabled = _configs.get(Config.AllowPublicUserTemplates.key());
@ -4205,6 +4225,7 @@ public class ManagementServerImpl implements ManagementServer {
capabilities.put("securityGroupsEnabled", securityGroupsEnabled);
capabilities.put("userPublicTemplateEnabled", (userPublicTemplateEnabled == null || userPublicTemplateEnabled.equals("false") ? false : true));
capabilities.put("cloudStackVersion", getVersion());
capabilities.put("supportELB", supportELB);
return capabilities;
}

View File

@ -94,4 +94,10 @@ public interface DomainRouterDao extends GenericDao<DomainRouterVO, Long> {
List<DomainRouterVO> findByNetworkOutsideThePod(long networkId, long podId, State state);
List<DomainRouterVO> listByNetworkAndState(long networkId, State state);
List<DomainRouterVO> listByNetworkAndPodAndRole(long networkId, long podId, Role role);
List<DomainRouterVO> listByNetworkAndRole(long networkId, Role role);
}

View File

@ -219,4 +219,21 @@ public class DomainRouterDaoImpl extends GenericDaoBase<DomainRouterVO, Long> im
}
return listBy(sc);
}
@Override
public List<DomainRouterVO> listByNetworkAndPodAndRole(long networkId, long podId, Role role) {
SearchCriteria<DomainRouterVO> sc = AllFieldsSearch.create();
sc.setParameters("network", networkId);
sc.setParameters("podId", podId);
sc.setParameters("role", role);
return listBy(sc);
}
@Override
public List<DomainRouterVO> listByNetworkAndRole(long networkId, Role role) {
SearchCriteria<DomainRouterVO> sc = AllFieldsSearch.create();
sc.setParameters("network", networkId);
sc.setParameters("role", role);
return listBy(sc);
}
}

View File

@ -66,7 +66,7 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
protected final SearchBuilder<UserVmVO> AccountHostSearch;
protected final SearchBuilder<UserVmVO> DestroySearch;
protected SearchBuilder<UserVmVO> AccountDataCenterVirtualSearch;
protected SearchBuilder<UserVmVO> AccountDataCenterVirtualSearch = null;
protected GenericSearchBuilder<UserVmVO, Long> CountByAccountPod;
protected GenericSearchBuilder<UserVmVO, Long> CountByAccount;
protected GenericSearchBuilder<UserVmVO, Long> PodsHavingVmsForAccount;

View File

@ -0,0 +1,45 @@
package com.cloud.network.dao;
import java.util.List;
import junit.framework.TestCase;
import com.cloud.network.ElasticLbVmMapVO;
import com.cloud.network.LoadBalancerVO;
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 testFindByIp() {
ElasticLbVmMapDaoImpl dao = ComponentLocator.inject(ElasticLbVmMapDaoImpl.class);
ElasticLbVmMapVO map = dao.findOneByIp(3);
if (map == null) {
System.out.println("Not Found");
} else {
System.out.println("Found");
}
}
public void testFindUnused() {
ElasticLbVmMapDaoImpl dao = ComponentLocator.inject(ElasticLbVmMapDaoImpl.class);
List<DomainRouterVO> map = dao.listUnusedElbVms();
if (map == null) {
System.out.println("Not Found");
} else {
System.out.println("Found");
}
}
public void testFindLB() {
ElasticLbVmMapDaoImpl dao = ComponentLocator.inject(ElasticLbVmMapDaoImpl.class);
List<LoadBalancerVO> lbs = dao.listLbsForElbVm(12);
if (lbs == null) {
System.out.println("Not Found");
} else {
System.out.println("Found " + lbs.size() + " lbs");
}
}
}

View File

@ -1603,4 +1603,15 @@ CREATE TABLE `cloud`.`op_host_transfer` (
CONSTRAINT `fk_op_host_transfer__future_mgmt_server_id` FOREIGN KEY `fk_op_host_transfer__future_mgmt_server_id`(`future_mgmt_server_id`) REFERENCES `mshost`(`msid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`elastic_lb_vm_map` (
`id` bigint unsigned NOT NULL auto_increment,
`ip_addr_id` bigint unsigned NOT NULL,
`elb_vm_id` bigint unsigned NOT NULL,
`lb_id` bigint unsigned,
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 `vm_instance` (`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`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET foreign_key_checks = 1;

View File

@ -53,5 +53,27 @@ INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-serve
INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.uri','/admin?stats','Load Balancer(haproxy) uri.');
INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.auth','admin1:AdMiN123','Load Balancer(haproxy) authetication string in the format username:password');
INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.port','8081','Load Balancer(haproxy) stats port number.');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'NetworkManager', 'use.external.dns', 'false', 'Bypass the cloudstack DHCP/DNS server vm name service, use zone external dns1 and dns2');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.enabled', 'false', 'Whether the load balancing service is enabled for basic zones');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.gc.interval.minutes', '120', 'Garbage collection interval to destroy unused ELB vms in minutes. Minimum of 5');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.network', 'guest', 'Whether the elastic load balancing service public ips are taken from the public or guest network');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.vm.cpu.mhz', '128', 'CPU speed for the elastic load balancer vm');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.vm.ram.size', '128', 'Memory in MB for the elastic load balancer vm');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.vm.vcpu.num', '1', 'Number of VCPU for the elastic load balancer vm');
UPDATE `cloud`.`nics` SET strategy='Start' where reserver_name='DirectPodBasedNetworkGuru';
UPDATE `cloud`.`network_offerings` SET lb_service=1 where unique_name='System-Guest-Network';
CREATE TABLE `cloud`.`elastic_lb_vm_map` (
`id` bigint unsigned NOT NULL auto_increment,
`ip_addr_id` bigint unsigned NOT NULL,
`elb_vm_id` bigint unsigned NOT NULL,
`lb_id` bigint unsigned,
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 `vm_instance` (`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`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -32,7 +32,7 @@ dictionary = {
</p>
</div>
<div class="tabbox" style="margin-top: 15px;">
<div class="content_tabs on" id="tab_details">
<div class="content_tabs on" id="tab_details" style="display: none">
<fmt:message key="label.details"/></div>
<div class="content_tabs off" id="tab_port_range" style="display: none">
<fmt:message key="label.port.range"/></div>
@ -43,7 +43,7 @@ dictionary = {
<div class="content_tabs off" id="tab_vpn" style="display: none">
<fmt:message key="label.vpn"/></div>
</div>
<div id="tab_content_details">
<div id="tab_content_details" style="display: none">
<div id="tab_spinning_wheel" class="rightpanel_mainloader_panel" style="display: none;">
<div class="rightpanel_mainloaderbox">
<div class="rightpanel_mainloader_animatedicon">
@ -423,8 +423,11 @@ dictionary = {
<input id="private_port" class="text" style="width: 70%; " type="text" />
<div id="private_port_errormsg" class="errormsg" style="display: none;"></div>
</div>
<div class="grid_row_cell" style="width: 12%;">
<div class="grid_row_cell" style="width: 15%;">
<select id="algorithm_select" class="select" style="width: 70%;">
<option value='roundrobin'>roundrobin</option>
<option value='leastconn'>leastconn</option>
<option value='source'>source</option>
</select>
</div>
<div class="grid_row_cell" style="width: 6%;">
@ -495,6 +498,15 @@ dictionary = {
</div>
</div>
</div>
<div class="actionpanel_button_wrapper" id="add_load_balancer_and_ip_button" style="display:none;">
<div class="actionpanel_button">
<div class="actionpanel_button_icons">
<img src="images/addvm_actionicon.png" /></div>
<div class="actionpanel_button_links">
<fmt:message key="label.add.load.balancer"/>
</div>
</div>
</div>
</div>
<!-- top buttons (end) -->
@ -548,8 +560,11 @@ dictionary = {
<div class="grid_row_cell" style="width: 12%; ">
<div class="row_celltitles" id="private_port"></div>
</div>
<div class="grid_row_cell" style="width: 12%; ">
<div class="grid_row_cell" style="width: 15%; ">
<select id="algorithm_select" class="select" style="width: 70%;">
<option value='roundrobin'>roundrobin</option>
<option value='leastconn'>leastconn</option>
<option value='source'>source</option>
</select>
</div>
<div class="grid_row_cell" style="width: 6%; ">
@ -782,6 +797,45 @@ dictionary = {
</div>
</div>
<div id="dialog_add_load_balancer_and_ip" title='<fmt:message key="label.add.load.balancer"/>' style="display: none">
<div class="dialog_formcontent">
<form action="#" method="post" id="form1">
<ol>
<li>
<label>
<fmt:message key="label.zone"/>:</label>
<select class="select" name="acquire_zone" id="acquire_zone">
<option value="default"><fmt:message key="label.waiting"/>....</option>
</select>
</li>
<li>
<label><fmt:message key="label.name"/>:</label>
<input class="text" type="text" id="name"/>
<div id="name_errormsg" class="dialog_formcontent_errormsg" style="display:none;"></div>
</li>
<li>
<label><fmt:message key="label.public.port"/>:</label>
<input class="text" type="text" id="public_port"/>
<div id="public_port_errormsg" class="dialog_formcontent_errormsg" style="display:none;"></div>
</li>
<li>
<label><fmt:message key="label.private.port"/>:</label>
<input class="text" type="text" id="private_port"/>
<div id="private_port_errormsg" class="dialog_formcontent_errormsg" style="display:none;"></div>
</li>
<li>
<label><fmt:message key="label.algorithm"/>:</label>
<select class="select" id="algorithm_select">
<option value='roundrobin'>roundrobin</option>
<option value='leastconn'>leastconn</option>
<option value='source'>source</option>
</select>
</li>
</ol>
</form>
</div>
</div>
<!-- Create User for VPN (begin) -->
<div id="dialog_add_vpnuser" title="Add VPN User" style="display:none">
<p>

View File

@ -209,8 +209,12 @@ $(document).ready(function() {
bindAndListMidMenuItems($("#leftmenu_volume"), "listVolumes", volumeGetSearchParams, "listvolumesresponse", "volume", "jsp/volume.jsp", afterLoadVolumeJSP, volumeToMidmenu, volumeToRightPanel, getMidmenuId, false);
bindAndListMidMenuItems($("#leftmenu_snapshot"), "listSnapshots", snapshotGetSearchParams, "listsnapshotsresponse", "snapshot", "jsp/snapshot.jsp", afterLoadSnapshotJSP, snapshotToMidmenu, snapshotToRightPanel, getMidmenuId, false);
//bindAndListMidMenuItems($("#leftmenu_ip"), "listPublicIpAddresses&forvirtualnetwork=true", ipGetSearchParams, "listpublicipaddressesresponse", "publicipaddress", "jsp/ipaddress.jsp", afterLoadIpJSP, ipToMidmenu, ipToRightPanel, ipGetMidmenuId, false);
bindAndListMidMenuItems($("#leftmenu_ip"), "listPublicIpAddresses", ipGetSearchParams, "listpublicipaddressesresponse", "publicipaddress", "jsp/ipaddress.jsp", afterLoadIpJSP, ipToMidmenu, ipToRightPanel, ipGetMidmenuId, false); //remove "&forvirtualnetwork=true" for advanced zone whose security group is enabled
if(g_supportELB == "guest") //ips are allocated on guest network
bindAndListMidMenuItems($("#leftmenu_ip"), "listPublicIpAddresses&forvirtualnetwork=false&forloadbalancing=true", ipGetSearchParams, "listpublicipaddressesresponse", "publicipaddress", "jsp/ipaddress.jsp", afterLoadIpJSP, ipToMidmenu, ipToRightPanel, ipGetMidmenuId, false);
else if(g_supportELB == "public") //ips are allocated on public network
bindAndListMidMenuItems($("#leftmenu_ip"), "listPublicIpAddresses&forvirtualnetwork=true&forloadbalancing=true", ipGetSearchParams, "listpublicipaddressesresponse", "publicipaddress", "jsp/ipaddress.jsp", afterLoadIpJSP, ipToMidmenu, ipToRightPanel, ipGetMidmenuId, false);
else
bindAndListMidMenuItems($("#leftmenu_ip"), "listPublicIpAddresses", ipGetSearchParams, "listpublicipaddressesresponse", "publicipaddress", "jsp/ipaddress.jsp", afterLoadIpJSP, ipToMidmenu, ipToRightPanel, ipGetMidmenuId, false); //remove "&forvirtualnetwork=true" for advanced zone whose security group is enabled
bindAndListMidMenuItems($("#leftmenu_security_group"), "listSecurityGroups", securityGroupGetSearchParams, "listsecuritygroupsresponse", "securitygroup", "jsp/securitygroup.jsp", afterLoadSecurityGroupJSP, securityGroupToMidmenu, securityGroupToRightPanel, getMidmenuId, false);
@ -591,6 +595,7 @@ $(document).ready(function() {
g_domainid = null;
g_timezoneoffset = null;
g_timezone = null;
g_supportELB = null;
$.cookie('JSESSIONID', null);
$.cookie('sessionKey', null);
@ -601,6 +606,7 @@ $(document).ready(function() {
$.cookie('networktype', null);
$.cookie('timezoneoffset', null);
$.cookie('timezone', null);
$.cookie('supportELB', null);
$("body").stopTime();
@ -694,6 +700,13 @@ $(document).ready(function() {
dataType: "json",
async: false,
success: function(json) {
/* g_supportELB: guest ips are allocated on guest network (so use 'forvirtualnetwork' = false)
* g_supportELB: public - ips are allocated on public network (so use 'forvirtualnetwork' = true)
* g_supportELB: false no ELB support
*/
g_supportELB = json.listcapabilitiesresponse.capability.supportELB;
$.cookie('supportELB', g_supportELB, { expires: 1});
if (json.listcapabilitiesresponse.capability.userpublictemplateenabled != null) {
g_userPublicTemplateEnabled = ""+json.listcapabilitiesresponse.capability.userpublictemplateenabled;
$.cookie('userpublictemplateenabled', g_userPublicTemplateEnabled, { expires: 1});
@ -788,6 +801,9 @@ $(document).ready(function() {
g_timezoneoffset = g_loginResponse.timezoneoffset;
}
if(g_supportELB == null)
g_supportELB = $.cookie("supportELB");
$.ajax({
data: createURL("command=listCapabilities"),
dataType: "json",

View File

@ -73,154 +73,301 @@ function afterLoadIpJSP() {
switchBetweenDifferentTabs(tabArray, tabContentArray, afterSwitchFnArray);
//***** switch between different tabs (end) **********************************************************************
//dialogs
initDialog("dialog_acquire_public_ip", 325);
initDialog("dialog_enable_vpn");
initDialog("dialog_disable_vpn");
initDialog("dialog_add_vpnuser");
initDialog("dialog_confirmation_remove_vpnuser");
initDialog("dialog_enable_static_NAT");
if(g_supportELB == "guest" || g_supportELB == "public") {
$("#tab_details,#tab_port_range,#tab_port_forwarding,#tab_load_balancer,#tab_vpn").hide();
//*** Acquire New IP (begin) ***
$.ajax({
data: createURL("command=listZones&available=true"),
dataType: "json",
success: function(json) {
var zones = json.listzonesresponse.zone;
var zoneSelect = $("#dialog_acquire_public_ip #acquire_zone").empty();
if (zones != null && zones.length > 0) {
for (var i = 0; i < zones.length; i++) {
zoneSelect.append("<option value='" + zones[i].id + "'>" + fromdb(zones[i].name) + "</option>");
}
}
}
});
$("#tab_content_details").hide();
$("#acquire_new_ip_button").unbind("click").bind("click", function(event) {
var submenuContent = $("#submenu_content_network");
$("#dialog_acquire_public_ip").dialog('option', 'buttons', {
"Acquire": function() {
var thisDialog = $(this);
thisDialog.dialog("close");
$("#acquire_new_ip_button").hide();
$("#add_load_balancer_and_ip_button").show();
var zoneid = thisDialog.find("#acquire_zone").val();
initDialog("dialog_add_load_balancer_and_ip");
var $midmenuItem1 = beforeAddingMidMenuItem() ;
$.ajax({
data: createURL("command=associateIpAddress&zoneid="+zoneid),
dataType: "json",
success: function(json) {
var jobId = json.associateipaddressresponse.jobid;
var timerKey = "associateIpJob_"+jobId;
$("body").everyTime(2000, timerKey, function() {
$.ajax({
data: createURL("command=queryAsyncJobResult&jobId="+jobId),
dataType: "json",
success: function(json) {
var result = json.queryasyncjobresultresponse;
if (result.jobstatus == 0) {
return; //Job has not completed
} else {
$("body").stopTime(timerKey);
if (result.jobstatus == 1) {
// Succeeded
ipToMidmenu(result.jobresult.ipaddress, $midmenuItem1);
bindClickToMidMenu($midmenuItem1, ipToRightPanel, ipGetMidmenuId);
afterAddingMidMenuItem($midmenuItem1, true);
} else if (result.jobstatus == 2) {
afterAddingMidMenuItem($midmenuItem1, false, fromdb(result.jobresult.errortext));
}
}
},
error: function(XMLHttpResponse) {
$("body").stopTime(timerKey);
handleError(XMLHttpResponse, function() {
afterAddingMidMenuItem($midmenuItem1, false, parseXMLHttpResponse(XMLHttpResponse));
});
}
});
}, 0);
},
error: function(XMLHttpResponse) {
handleError(XMLHttpResponse, function() {
afterAddingMidMenuItem($midmenuItem1, false, parseXMLHttpResponse(XMLHttpResponse));
});
$.ajax({
data: createURL("command=listZones&available=true"),
dataType: "json",
success: function(json) {
var zones = json.listzonesresponse.zone;
var zoneSelect = $("#dialog_add_load_balancer_and_ip #acquire_zone").empty();
if (zones != null && zones.length > 0) {
for (var i = 0; i < zones.length; i++) {
if(zones[i].networktype == "Basic")
zoneSelect.append("<option value='" + zones[i].id + "'>" + fromdb(zones[i].name) + "</option>");
}
});
},
"Cancel": function() {
$(this).dialog("close");
}
}
}).dialog("open");
return false;
});
//*** Acquire New IP (end) ***
});
//*** Port Range tab (begin) ***
var $createPortRangeRow = $("#tab_content_port_range").find("#create_port_range_row");
$("#add_load_balancer_and_ip_button").unbind("click").bind("click", function(event) {
$("#dialog_add_load_balancer_and_ip").dialog('option', 'buttons', {
"Acquire": function() {
var $thisDialog = $(this);
$createPortRangeRow.find("#add_link").bind("click", function(event){
var isValid = true;
isValid &= validateInteger("Start Port", $createPortRangeRow.find("#start_port"), $createPortRangeRow.find("#start_port_errormsg"), 1, 65535);
isValid &= validateInteger("End Port", $createPortRangeRow.find("#end_port"), $createPortRangeRow.find("#end_port_errormsg"), 1, 65535);
if (!isValid)
return;
var isValid = true;
isValid &= validateString("Name", $thisDialog.find("#name"), $thisDialog.find("#name_errormsg"));
isValid &= validateInteger("Public Port", $thisDialog.find("#public_port"), $thisDialog.find("#public_port_errormsg"), 1, 65535);
isValid &= validateInteger("Private Port", $thisDialog.find("#private_port"), $thisDialog.find("#private_port_errormsg"), 1, 65535);
if (!isValid)
return;
var $template = $("#port_range_template").clone();
$("#tab_content_port_range #grid_content").append($template.show());
$thisDialog.dialog("close");
var $spinningWheel = $template.find("#row_container").find("#spinning_wheel");
$spinningWheel.find("#description").text(g_dictionary["label.adding.processing"]);
$spinningWheel.show();
var array1 = [];
var $midmenuItem1 = $("#right_panel_content").data("$midmenuItem1");
var ipObj = $midmenuItem1.data("jsonObj");
var zoneId = $thisDialog.find("#acquire_zone").val();
array1.push("&zoneid="+zoneId);
var startPort = $createPortRangeRow.find("#start_port").val();
var endPort = $createPortRangeRow.find("#end_port").val();
var protocol = $createPortRangeRow.find("#protocol").val();
var name = $thisDialog.find("#name").val();
array1.push("&name="+todb(name));
var array1 = [];
array1.push("&ipaddressid="+ipObj.id);
array1.push("&startPort="+startPort);
array1.push("&endPort="+endPort);
array1.push("&protocol="+protocol);
var publicPort = $thisDialog.find("#public_port").val();
array1.push("&publicport="+publicPort);
$.ajax({
data: createURL("command=createIpForwardingRule"+array1.join("")),
dataType: "json",
success: function(json) {
var jobId = json.createipforwardingruleresponse.jobid;
var timerKey = "asyncJob_" + jobId;
$("body").everyTime(
10000,
timerKey,
function() {
$.ajax({
data: createURL("command=queryAsyncJobResult&jobId="+jobId),
dataType: "json",
success: function(json) {
var result = json.queryasyncjobresultresponse;
if (result.jobstatus == 0) {
return; //Job has not completed
} else {
$("body").stopTime(timerKey);
$spinningWheel.hide();
if (result.jobstatus == 1) { // Succeeded
var item = json.queryasyncjobresultresponse.jobresult.ipforwardingrule;
portRangeJsonToTemplate(item, $template);
$spinningWheel.hide();
refreshCreatePortRangeRow();
} else if (result.jobstatus == 2) { // Failed
$template.slideUp("slow", function() {
$(this).remove();
});
//var errorMsg = g_dictionary["label.failed"] + " - " + g_dictionary["label.error.code"] + " " + fromdb(result.jobresult.errorcode);
var errorMsg = g_dictionary["label.failed"] + " - " + fromdb(result.jobresult.errortext);
$("#dialog_error").text(errorMsg).dialog("open");
var privatePort = $thisDialog.find("#private_port").val();
array1.push("&privateport="+privatePort);
var algorithm = $thisDialog.find("#algorithm_select").val();
array1.push("&algorithm="+algorithm);
var $midmenuItem1 = beforeAddingMidMenuItem() ;
$.ajax({
data: createURL("command=createLoadBalancerRule"+array1.join("")),
dataType: "json",
success: function(json) {
var jobId = json.createloadbalancerruleresponse.jobid;
var timerKey = "addLbAndIpJob_"+jobId;
$("body").everyTime(2000, timerKey, function() {
$.ajax({
data: createURL("command=queryAsyncJobResult&jobId="+jobId),
dataType: "json",
success: function(json) {
var result = json.queryasyncjobresultresponse;
if (result.jobstatus == 0) {
return; //Job has not completed
} else {
$("body").stopTime(timerKey);
if (result.jobstatus == 1) {
// Succeeded
var publicipid = result.jobresult.loadbalancer.publicipid;
var cmd;
if(g_supportELB == "guest") {
cmd = "command=listPublicIpAddresses&forvirtualnetwork=false&id="+publicipid;
}
else if(g_supportELB == "public") {
cmd = "command=listPublicIpAddresses&forvirtualnetwork=true&id="+publicipid;
}
else {
if(g_supportELB == null)
alert("supportELB should be either guest or public. It should not be null.");
else
alert("supportELB should be either guest or public. It should not be " + g_supportELB);
return;
}
$.ajax({
data: createURL(cmd),
dataType: "json",
async: false,
success: function(json) {
var items = json.listpublicipaddressesresponse.publicipaddress;
if(items != null && items.length > 0) {
ipToMidmenu(items[0], $midmenuItem1);
bindClickToMidMenu($midmenuItem1, ipToRightPanel, ipGetMidmenuId);
afterAddingMidMenuItem($midmenuItem1, true);
}
}
});
} else if (result.jobstatus == 2) {
afterAddingMidMenuItem($midmenuItem1, false, fromdb(result.jobresult.errortext));
}
}
},
error: function(XMLHttpResponse) {
$("body").stopTime(timerKey);
handleError(XMLHttpResponse, function() {
afterAddingMidMenuItem($midmenuItem1, false, parseXMLHttpResponse(XMLHttpResponse));
});
}
});
}, 0);
},
error: function(XMLHttpResponse) {
handleError(XMLHttpResponse, function() {
afterAddingMidMenuItem($midmenuItem1, false, parseXMLHttpResponse(XMLHttpResponse));
});
}
});
},
"Cancel": function() {
$(this).dialog("close");
}
}).dialog("open");
return false;
});
}
else {
$("#tab_details,#tab_content_details").show();
//dialogs
initDialog("dialog_acquire_public_ip", 325);
initDialog("dialog_enable_vpn");
initDialog("dialog_disable_vpn");
initDialog("dialog_add_vpnuser");
initDialog("dialog_confirmation_remove_vpnuser");
initDialog("dialog_enable_static_NAT");
//*** Acquire New IP (begin) ***
$.ajax({
data: createURL("command=listZones&available=true"),
dataType: "json",
success: function(json) {
var zones = json.listzonesresponse.zone;
var zoneSelect = $("#dialog_acquire_public_ip #acquire_zone").empty();
if (zones != null && zones.length > 0) {
for (var i = 0; i < zones.length; i++) {
zoneSelect.append("<option value='" + zones[i].id + "'>" + fromdb(zones[i].name) + "</option>");
}
}
}
});
$("#acquire_new_ip_button").unbind("click").bind("click", function(event) {
$("#dialog_acquire_public_ip").dialog('option', 'buttons', {
"Acquire": function() {
var thisDialog = $(this);
thisDialog.dialog("close");
var zoneid = thisDialog.find("#acquire_zone").val();
var $midmenuItem1 = beforeAddingMidMenuItem() ;
$.ajax({
data: createURL("command=associateIpAddress&zoneid="+zoneid),
dataType: "json",
success: function(json) {
var jobId = json.associateipaddressresponse.jobid;
var timerKey = "associateIpJob_"+jobId;
$("body").everyTime(2000, timerKey, function() {
$.ajax({
data: createURL("command=queryAsyncJobResult&jobId="+jobId),
dataType: "json",
success: function(json) {
var result = json.queryasyncjobresultresponse;
if (result.jobstatus == 0) {
return; //Job has not completed
} else {
$("body").stopTime(timerKey);
if (result.jobstatus == 1) {
// Succeeded
ipToMidmenu(result.jobresult.ipaddress, $midmenuItem1);
bindClickToMidMenu($midmenuItem1, ipToRightPanel, ipGetMidmenuId);
afterAddingMidMenuItem($midmenuItem1, true);
} else if (result.jobstatus == 2) {
afterAddingMidMenuItem($midmenuItem1, false, fromdb(result.jobresult.errortext));
}
}
},
error: function(XMLHttpResponse) {
$("body").stopTime(timerKey);
handleError(XMLHttpResponse, function() {
afterAddingMidMenuItem($midmenuItem1, false, parseXMLHttpResponse(XMLHttpResponse));
});
}
});
}, 0);
},
error: function(XMLHttpResponse) {
handleError(XMLHttpResponse, function() {
afterAddingMidMenuItem($midmenuItem1, false, parseXMLHttpResponse(XMLHttpResponse));
});
}
});
},
"Cancel": function() {
$(this).dialog("close");
}
}).dialog("open");
return false;
});
//*** Acquire New IP (end) ***
//*** Port Range tab (begin) ***
var $createPortRangeRow = $("#tab_content_port_range").find("#create_port_range_row");
$createPortRangeRow.find("#add_link").bind("click", function(event){
var isValid = true;
isValid &= validateInteger("Start Port", $createPortRangeRow.find("#start_port"), $createPortRangeRow.find("#start_port_errormsg"), 1, 65535);
isValid &= validateInteger("End Port", $createPortRangeRow.find("#end_port"), $createPortRangeRow.find("#end_port_errormsg"), 1, 65535);
if (!isValid)
return;
var $template = $("#port_range_template").clone();
$("#tab_content_port_range #grid_content").append($template.show());
var $spinningWheel = $template.find("#row_container").find("#spinning_wheel");
$spinningWheel.find("#description").text(g_dictionary["label.adding.processing"]);
$spinningWheel.show();
var $midmenuItem1 = $("#right_panel_content").data("$midmenuItem1");
var ipObj = $midmenuItem1.data("jsonObj");
var startPort = $createPortRangeRow.find("#start_port").val();
var endPort = $createPortRangeRow.find("#end_port").val();
var protocol = $createPortRangeRow.find("#protocol").val();
var array1 = [];
array1.push("&ipaddressid="+ipObj.id);
array1.push("&startPort="+startPort);
array1.push("&endPort="+endPort);
array1.push("&protocol="+protocol);
$.ajax({
data: createURL("command=createIpForwardingRule"+array1.join("")),
dataType: "json",
success: function(json) {
var jobId = json.createipforwardingruleresponse.jobid;
var timerKey = "asyncJob_" + jobId;
$("body").everyTime(
10000,
timerKey,
function() {
$.ajax({
data: createURL("command=queryAsyncJobResult&jobId="+jobId),
dataType: "json",
success: function(json) {
var result = json.queryasyncjobresultresponse;
if (result.jobstatus == 0) {
return; //Job has not completed
} else {
$("body").stopTime(timerKey);
$spinningWheel.hide();
if (result.jobstatus == 1) { // Succeeded
var item = json.queryasyncjobresultresponse.jobresult.ipforwardingrule;
portRangeJsonToTemplate(item, $template);
$spinningWheel.hide();
refreshCreatePortRangeRow();
} else if (result.jobstatus == 2) { // Failed
$template.slideUp("slow", function() {
$(this).remove();
});
//var errorMsg = g_dictionary["label.failed"] + " - " + g_dictionary["label.error.code"] + " " + fromdb(result.jobresult.errorcode);
var errorMsg = g_dictionary["label.failed"] + " - " + fromdb(result.jobresult.errortext);
$("#dialog_error").text(errorMsg).dialog("open");
}
}
},
error: function(XMLHttpResponse) {
$("body").stopTime(timerKey);
handleError(XMLHttpResponse, function() {
$template.slideUp("slow", function() {
$(this).remove();
});
var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
$("#dialog_error").text(fromdb(errorMsg)).dialog("open");
});
}
},
error: function(XMLHttpResponse) {
@ -290,109 +437,118 @@ function afterLoadIpJSP() {
isValid &= validateInteger("Private Port", $createPortForwardingRow.find("#private_port"), $createPortForwardingRow.find("#private_port_errormsg"), 1, 65535, false); //required
isValid &= validateInteger("Private End Port", $createPortForwardingRow.find("#private_end_port"), $createPortForwardingRow.find("#private_end_port_errormsg"), 1, 65535, true); //optional
isValid &= validateDropDownBox("Instance", $createPortForwardingRow.find("#vm"), $createPortForwardingRow.find("#vm_errormsg"));
if (!isValid)
return;
isValid &= validateCIDRList("CIDR", $createPortForwardingRow.find("#cidr"), $createPortForwardingRow.find("#cidr_errormsg"), true); //optional
var $template = $("#port_forwarding_template").clone();
$("#tab_content_port_forwarding #grid_content").append($template.show());
isValid &= validateInteger("Public Port", $createPortForwardingRow.find("#public_port"), $createPortForwardingRow.find("#public_port_errormsg"), 1, 65535, false); //required
//isValid &= validateInteger("Public End Port", $createPortForwardingRow.find("#public_end_port"), $createPortForwardingRow.find("#public_end_port_errormsg"), 1, 65535, true); //optional
var $spinningWheel = $template.find("#row_container").find("#spinning_wheel");
$spinningWheel.find("#description").text(g_dictionary["label.adding.processing"]);
$spinningWheel.show();
isValid &= validateInteger("Private Port", $createPortForwardingRow.find("#private_port"), $createPortForwardingRow.find("#private_port_errormsg"), 1, 65535, false); //required
//isValid &= validateInteger("Private End Port", $createPortForwardingRow.find("#private_end_port"), $createPortForwardingRow.find("#private_end_port_errormsg"), 1, 65535, true); //optional
var $midmenuItem1 = $("#right_panel_content").data("$midmenuItem1");
var ipObj = $midmenuItem1.data("jsonObj");
isValid &= validateDropDownBox("Instance", $createPortForwardingRow.find("#vm"), $createPortForwardingRow.find("#vm_errormsg"));
if (!isValid)
return;
var array1 = [];
array1.push("&ipaddressid="+ipObj.id);
var $template = $("#port_forwarding_template").clone();
$("#tab_content_port_forwarding #grid_content").append($template.show());
var cidr = $createPortForwardingRow.find("#cidr").val();
if(cidr != null && cidr.length > 0)
array1.push("&cidrlist="+cidr);
var $spinningWheel = $template.find("#row_container").find("#spinning_wheel");
$spinningWheel.find("#description").text(g_dictionary["label.adding.processing"]);
$spinningWheel.show();
var publicPort = $createPortForwardingRow.find("#public_port").val();
array1.push("&publicport="+publicPort);
var publicEndPort = $createPortForwardingRow.find("#public_end_port").val();
if(publicEndPort != null && publicEndPort.length > 0)
array1.push("&publicendport="+publicEndPort);
var $midmenuItem1 = $("#right_panel_content").data("$midmenuItem1");
var ipObj = $midmenuItem1.data("jsonObj");
var privatePort = $createPortForwardingRow.find("#private_port").val();
array1.push("&privateport="+privatePort);
var privateEndPort = $createPortForwardingRow.find("#private_end_port").val();
if(privateEndPort != null && privateEndPort.length > 0)
array1.push("&privateendport="+privateEndPort);
var array1 = [];
array1.push("&ipaddressid="+ipObj.id);
var protocol = $createPortForwardingRow.find("#protocol").val();
array1.push("&protocol="+protocol);
var cidr = $createPortForwardingRow.find("#cidr").val();
if(cidr != null && cidr.length > 0)
array1.push("&cidrlist="+cidr);
var virtualMachineId = $createPortForwardingRow.find("#vm").val();
array1.push("&virtualmachineid=" + virtualMachineId);
var publicPort = $createPortForwardingRow.find("#public_port").val();
array1.push("&publicport="+publicPort);
var publicEndPort = $createPortForwardingRow.find("#public_end_port").val();
if(publicEndPort != null && publicEndPort.length > 0)
array1.push("&publicendport="+publicEndPort);
$.ajax({
data: createURL("command=createPortForwardingRule"+array1.join("")),
dataType: "json",
success: function(json) {
var jobId = json.createportforwardingruleresponse.jobid;
var timerKey = "asyncJob_" + jobId;
$("body").everyTime(
10000,
timerKey,
function() {
$.ajax({
data: createURL("command=queryAsyncJobResult&jobId="+jobId),
dataType: "json",
success: function(json) {
var result = json.queryasyncjobresultresponse;
if (result.jobstatus == 0) {
return; //Job has not completed
} else {
$("body").stopTime(timerKey);
$spinningWheel.hide();
if (result.jobstatus == 1) { // Succeeded
var item = json.queryasyncjobresultresponse.jobresult.portforwardingrule;
portForwardingJsonToTemplate(item,$template);
$spinningWheel.hide();
refreshCreatePortForwardingRow();
} else if (result.jobstatus == 2) { // Failed
$template.slideUp("slow", function() {
$(this).remove();
});
//var errorMsg = g_dictionary["label.failed"] + " - " + g_dictionary["label.error.code"] + " " + fromdb(result.jobresult.errorcode);
var errorMsg = g_dictionary["label.failed"] + " - " + fromdb(result.jobresult.errortext);
$("#dialog_error").text(errorMsg).dialog("open");
var privatePort = $createPortForwardingRow.find("#private_port").val();
array1.push("&privateport="+privatePort);
var privateEndPort = $createPortForwardingRow.find("#private_end_port").val();
if(privateEndPort != null && privateEndPort.length > 0)
array1.push("&privateendport="+privateEndPort);
var protocol = $createPortForwardingRow.find("#protocol").val();
array1.push("&protocol="+protocol);
var virtualMachineId = $createPortForwardingRow.find("#vm").val();
array1.push("&virtualmachineid=" + virtualMachineId);
$.ajax({
data: createURL("command=createPortForwardingRule"+array1.join("")),
dataType: "json",
success: function(json) {
var jobId = json.createportforwardingruleresponse.jobid;
var timerKey = "asyncJob_" + jobId;
$("body").everyTime(
10000,
timerKey,
function() {
$.ajax({
data: createURL("command=queryAsyncJobResult&jobId="+jobId),
dataType: "json",
success: function(json) {
var result = json.queryasyncjobresultresponse;
if (result.jobstatus == 0) {
return; //Job has not completed
} else {
$("body").stopTime(timerKey);
$spinningWheel.hide();
if (result.jobstatus == 1) { // Succeeded
var item = json.queryasyncjobresultresponse.jobresult.portforwardingrule;
portForwardingJsonToTemplate(item,$template);
$spinningWheel.hide();
refreshCreatePortForwardingRow();
} else if (result.jobstatus == 2) { // Failed
$template.slideUp("slow", function() {
$(this).remove();
});
//var errorMsg = g_dictionary["label.failed"] + " - " + g_dictionary["label.error.code"] + " " + fromdb(result.jobresult.errorcode);
var errorMsg = g_dictionary["label.failed"] + " - " + fromdb(result.jobresult.errortext);
$("#dialog_error").text(errorMsg).dialog("open");
}
}
}
},
error: function(XMLHttpResponse) {
$("body").stopTime(timerKey);
handleError(XMLHttpResponse, function() {
$template.slideUp("slow", function() {
$(this).remove();
},
error: function(XMLHttpResponse) {
$("body").stopTime(timerKey);
handleError(XMLHttpResponse, function() {
$template.slideUp("slow", function() {
$(this).remove();
});
var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
$("#dialog_error").text(fromdb(errorMsg)).dialog("open");
});
var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
$("#dialog_error").text(fromdb(errorMsg)).dialog("open");
});
}
});
},
0
);
},
error: function(XMLHttpResponse) {
handleError(XMLHttpResponse, function() {
$template.slideUp("slow", function() {
$(this).remove();
}
});
},
0
);
},
error: function(XMLHttpResponse) {
handleError(XMLHttpResponse, function() {
$template.slideUp("slow", function() {
$(this).remove();
});
var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
$("#dialog_error").text(fromdb(errorMsg)).dialog("open");
});
var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
$("#dialog_error").text(fromdb(errorMsg)).dialog("open");
});
}
});
}
});
return false;
});
//*** Port Forwarding tab (end) ***
return false;
});
//*** Port Forwarding tab (end) ***
}
//*** Load Balancer tab (begin) ***
var createLoadBalancerRow = $("#tab_content_load_balancer #create_load_balancer_row");
@ -439,13 +595,49 @@ function afterLoadIpJSP() {
data: createURL("command=createLoadBalancerRule"+array1.join("")),
dataType: "json",
success: function(json) {
var item = json.createloadbalancerruleresponse.loadbalancer;
loadBalancerJsonToTemplate(item, $template);
$spinningWheel.hide();
refreshCreateLoadBalancerRow();
var jobId = json.createloadbalancerruleresponse.jobid;
var timerKey = "addLbJob_"+jobId;
$("body").everyTime(2000, timerKey, function() {
$.ajax({
data: createURL("command=queryAsyncJobResult&jobId="+jobId),
dataType: "json",
success: function(json) {
var result = json.queryasyncjobresultresponse;
if (result.jobstatus == 0) {
return; //Job has not completed
} else {
$("body").stopTime(timerKey);
if (result.jobstatus == 1) {
// Succeeded
var item = result.jobresult.loadbalancer;
loadBalancerJsonToTemplate(item, $template);
$spinningWheel.hide();
refreshCreateLoadBalancerRow();
} else if (result.jobstatus == 2) {
$template.slideUp("slow", function() {
$(this).remove();
});
var errorMsg = fromdb(result.jobresult.errortext);
$("#dialog_error").text(fromdb(errorMsg)).dialog("open");
}
}
},
error: function(XMLHttpResponse) {
$("body").stopTime(timerKey);
handleError(XMLHttpResponse, function() {
$template.slideUp("slow", function() {
$(this).remove();
});
var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
$("#dialog_error").text(fromdb(errorMsg)).dialog("open");
});
}
});
}, 0);
},
error: function(XMLHttpResponse) {
handleError(XMLHttpResponse, function() {
error: function(XMLHttpResponse) {
handleError(XMLHttpResponse, function() {
$template.slideUp("slow", function() {
$(this).remove();
});
@ -454,6 +646,7 @@ function afterLoadIpJSP() {
});
}
});
return false;
});
//*** Load Balancer tab (end) ***
@ -516,7 +709,11 @@ function ipToRightPanel($midmenuItem1) {
copyActionInfoFromMidMenuToRightPanel($midmenuItem1);
$("#right_panel_content").data("$midmenuItem1", $midmenuItem1);
$("#tab_details").click();
if(g_supportELB == "guest" || g_supportELB == "public")
$("#tab_load_balancer").click();
else
$("#tab_details").click();
if(ipObj.isstaticnat == true) {
$("#tab_port_range").show();
@ -1184,14 +1381,30 @@ function ipJsonToDetailsTab() {
var networkObj = $midmenuItem1.data("networkObj");
var id = ipObj.id;
var publicipid = ipObj.id;
var $thisTab = $("#right_panel_content").find("#tab_content_details");
$thisTab.find("#tab_container").hide();
$thisTab.find("#tab_spinning_wheel").show();
var cmd;
if(g_supportELB == "guest") {
cmd = "command=listPublicIpAddresses&forvirtualnetwork=false&id="+publicipid;
}
else if(g_supportELB == "public") {
cmd = "command=listPublicIpAddresses&forvirtualnetwork=true&id="+publicipid;
}
else {
if(g_supportELB == null)
alert("supportELB should be either guest or public. It should not be null.");
else
alert("supportELB should be either guest or public. It should not be " + g_supportELB);
return;
}
$.ajax({
data: createURL("command=listPublicIpAddresses&id="+id),
data: createURL(cmd),
dataType: "json",
async: false,
success: function(json) {
@ -1744,8 +1957,21 @@ function loadBalancerJsonToTemplate(jsonObj, $template) {
$("body").stopTime(timerKey);
$spinningWheel.hide();
if (result.jobstatus == 1) { // Succeeded
var total_lbrules = $("#tab_content_load_balancer").find("#grid_content").find(".grid_rows").length;
$template.slideUp("slow", function() {
$(this).remove();
if(g_supportELB == "guest" || g_supportELB == "public") {
var count_lb = $("div[id*='loadBalancer_']").length;
if(count_lb == 0) {
var params = $("#middle_menu_pagination").data("params");
if(params == null)
return;
listMidMenuItems2(params.commandString, params.getSearchParamsFn, params.jsonResponse1, params.jsonResponse2, params.toMidmenuFn, params.toRightPanelFn, params.getMidmenuIdFn, params.isMultipleSelectionInMidMenu, 1);
if($("div[id*='midmenuItem_']").length == 0)
$("#tab_content_load_balancer").hide();
}
}
});
} else if (result.jobstatus == 2) { // Failed
var errorMsg = g_dictionary["label.deleting.failed"] + " - " + fromdb(result.jobresult.errortext);

View File

@ -1318,7 +1318,7 @@ function listMidMenuItems(commandString, getSearchParamsFn, jsonResponse1, jsonR
}
function bindAndListMidMenuItems($leftmenu, commandString, getSearchParamsFn, jsonResponse1, jsonResponse2, rightPanelJSP, afterLoadRightPanelJSPFn, toMidmenuFn, toRightPanelFn, getMidmenuIdFn, isMultipleSelectionInMidMenu) {
$leftmenu.bind("click", function(event) {
$leftmenu.unbind().bind("click", function(event) {
selectLeftSubMenu($(this));
listMidMenuItems(commandString, getSearchParamsFn, jsonResponse1, jsonResponse2, rightPanelJSP, afterLoadRightPanelJSPFn, toMidmenuFn, toRightPanelFn, getMidmenuIdFn, isMultipleSelectionInMidMenu, $(this).attr("id"), null);
return false;
@ -1526,14 +1526,17 @@ var g_domainid = null;
var g_enableLogging = false;
var g_timezoneoffset = null;
var g_timezone = null;
var g_supportELB = null;
// capabilities
var g_directAttachSecurityGroupsEnabled = "false";
function getDirectAttachSecurityGroupsEnabled() { return g_directAttachSecurityGroupsEnabled; }
var g_userPublicTemplateEnabled = "true"
var g_userPublicTemplateEnabled = "true";
function getUserPublicTemplateEnabled() { return g_userPublicTemplateEnabled; }
var g_supportELB = null;
//keyboard keycode
var keycode_Enter = 13;

View File

@ -1445,6 +1445,27 @@ function addZoneWizardSubmit($thisWizard) {
listZonesUpdate();
g_directAttachSecurityGroupsEnabled = true;
$("#leftmenu_security_group_container").show();
$.ajax({
data: createURL("command=listCapabilities"),
dataType: "json",
async: false,
success: function(json) {
/* g_supportELB: guest ips are allocated on guest network (so use 'forvirtualnetwork' = false)
* g_supportELB: public - ips are allocated on public network (so use 'forvirtualnetwork' = true)
* g_supportELB: false no ELB support
*/
g_supportELB = json.listcapabilitiesresponse.capability.supportELB;
$.cookie('supportELB', g_supportELB, { expires: 1});
if(g_supportELB == "guest") //ips are allocated on guest network
bindAndListMidMenuItems($("#leftmenu_ip"), "listPublicIpAddresses&forvirtualnetwork=false&forloadbalancing=true", ipGetSearchParams, "listpublicipaddressesresponse", "publicipaddress", "jsp/ipaddress.jsp", afterLoadIpJSP, ipToMidmenu, ipToRightPanel, ipGetMidmenuId, false);
else if(g_supportELB == "public") //ips are allocated on public network
bindAndListMidMenuItems($("#leftmenu_ip"), "listPublicIpAddresses&forvirtualnetwork=true&forloadbalancing=true", ipGetSearchParams, "listpublicipaddressesresponse", "publicipaddress", "jsp/ipaddress.jsp", afterLoadIpJSP, ipToMidmenu, ipToRightPanel, ipGetMidmenuId, false);
else
bindAndListMidMenuItems($("#leftmenu_ip"), "listPublicIpAddresses", ipGetSearchParams, "listpublicipaddressesresponse", "publicipaddress", "jsp/ipaddress.jsp", afterLoadIpJSP, ipToMidmenu, ipToRightPanel, ipGetMidmenuId, false); //remove "&forvirtualnetwork=true" for advanced zone whose security group is enabled
}
});
},
error: function(XMLHttpResponse) {
handleError(XMLHttpResponse, function() {