You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mu...@apache.org on 2012/06/25 18:23:57 UTC

[2/3] moving out F5 code from server into plugins/network-elements/f5/

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/422c4ce5/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancerNetworksCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancerNetworksCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancerNetworksCmd.java
new file mode 100644
index 0000000..efa71b5
--- /dev/null
+++ b/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancerNetworksCmd.java
@@ -0,0 +1,94 @@
+// Copyright 2012 Citrix Systems, Inc. Licensed under the
+// Apache License, Version 2.0 (the "License"); you may not use this
+// file except in compliance with the License.  Citrix Systems, Inc.
+// reserves all rights not expressly granted by the License.
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
+// Automatically generated by addcopyright.py at 04/03/2012
+package com.cloud.api.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.api.ApiConstants;
+import com.cloud.api.BaseCmd;
+import com.cloud.api.BaseListCmd;
+import com.cloud.api.IdentityMapper;
+import com.cloud.api.Implementation;
+import com.cloud.api.Parameter;
+import com.cloud.api.PlugService;
+import com.cloud.api.ServerApiException;
+import com.cloud.api.response.ListResponse;
+import com.cloud.api.response.NetworkResponse;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.network.element.F5ExternalLoadBalancerElementService;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Implementation(responseObject=NetworkResponse.class, description="lists network that are using a F5 load balancer device")
+public class ListF5LoadBalancerNetworksCmd extends BaseListCmd {
+
+    public static final Logger s_logger = Logger.getLogger(ListF5LoadBalancerNetworksCmd.class.getName());
+    private static final String s_name = "listf5loadbalancernetworksresponse";
+    @PlugService F5ExternalLoadBalancerElementService _f5DeviceManagerService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @IdentityMapper(entityTableName="external_load_balancer_devices")
+    @Parameter(name=ApiConstants.LOAD_BALANCER_DEVICE_ID, type=CommandType.LONG, required = true, description="f5 load balancer device ID")
+    private Long lbDeviceId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getLoadBalancerDeviceId() {
+        return lbDeviceId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
+        try {
+            List<? extends Network> networks  = _f5DeviceManagerService.listNetworks(this);
+            ListResponse<NetworkResponse> response = new ListResponse<NetworkResponse>();
+            List<NetworkResponse> networkResponses = new ArrayList<NetworkResponse>();
+
+            if (networks != null && !networks.isEmpty()) {
+                for (Network network : networks) {
+                    NetworkResponse networkResponse = _responseGenerator.createNetworkResponse(network);
+                    networkResponses.add(networkResponse);
+                }
+            }
+
+            response.setResponses(networkResponses);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        }  catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(BaseCmd.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(BaseCmd.INTERNAL_ERROR, runtimeExcp.getMessage());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/422c4ce5/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancersCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancersCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancersCmd.java
new file mode 100644
index 0000000..228bab5
--- /dev/null
+++ b/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancersCmd.java
@@ -0,0 +1,101 @@
+// Copyright 2012 Citrix Systems, Inc. Licensed under the
+// Apache License, Version 2.0 (the "License"); you may not use this
+// file except in compliance with the License.  Citrix Systems, Inc.
+// reserves all rights not expressly granted by the License.
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
+// Automatically generated by addcopyright.py at 04/03/2012
+package com.cloud.api.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.api.ApiConstants;
+import com.cloud.api.BaseCmd;
+import com.cloud.api.BaseListCmd;
+import com.cloud.api.IdentityMapper;
+import com.cloud.api.Implementation;
+import com.cloud.api.Parameter;
+import com.cloud.api.PlugService;
+import com.cloud.api.ServerApiException;
+import com.cloud.api.response.F5LoadBalancerResponse;
+import com.cloud.api.response.ListResponse;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.ExternalLoadBalancerDeviceVO;
+import com.cloud.network.element.F5ExternalLoadBalancerElementService;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Implementation(responseObject=F5LoadBalancerResponse.class, description="lists F5 load balancer devices")
+public class ListF5LoadBalancersCmd extends BaseListCmd {
+    public static final Logger s_logger = Logger.getLogger(ListF5LoadBalancersCmd.class.getName());
+    private static final String s_name = "listf5loadbalancerresponse";
+    @PlugService F5ExternalLoadBalancerElementService _f5DeviceManagerService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @IdentityMapper(entityTableName="physical_network")
+    @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.LONG, description="the Physical Network ID")
+    private Long physicalNetworkId;
+
+    @IdentityMapper(entityTableName="external_load_balancer_devices")
+    @Parameter(name=ApiConstants.LOAD_BALANCER_DEVICE_ID, type=CommandType.LONG,  description="f5 load balancer device ID")
+    private Long lbDeviceId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getLoadBalancerDeviceId() {
+        return lbDeviceId;
+    }
+
+    public Long getPhysicalNetworkId() {
+        return physicalNetworkId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
+        try {
+            List<ExternalLoadBalancerDeviceVO> lbDevices = _f5DeviceManagerService.listF5LoadBalancers(this);
+            ListResponse<F5LoadBalancerResponse> response = new ListResponse<F5LoadBalancerResponse>();
+            List<F5LoadBalancerResponse> lbDevicesResponse = new ArrayList<F5LoadBalancerResponse>();
+
+            if (lbDevices != null && !lbDevices.isEmpty()) {
+                for (ExternalLoadBalancerDeviceVO lbDeviceVO : lbDevices) {
+                    F5LoadBalancerResponse lbdeviceResponse = _f5DeviceManagerService.createF5LoadBalancerResponse(lbDeviceVO);
+                    lbDevicesResponse.add(lbdeviceResponse);
+                }
+            }
+
+            response.setResponses(lbDevicesResponse);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        }  catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(BaseCmd.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(BaseCmd.INTERNAL_ERROR, runtimeExcp.getMessage());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/422c4ce5/plugins/network-elements/f5/src/com/cloud/api/response/F5LoadBalancerResponse.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/f5/src/com/cloud/api/response/F5LoadBalancerResponse.java b/plugins/network-elements/f5/src/com/cloud/api/response/F5LoadBalancerResponse.java
new file mode 100644
index 0000000..dbb962f
--- /dev/null
+++ b/plugins/network-elements/f5/src/com/cloud/api/response/F5LoadBalancerResponse.java
@@ -0,0 +1,101 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api.response;
+
+import com.cloud.api.ApiConstants;
+import com.cloud.utils.IdentityProxy;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+public class F5LoadBalancerResponse extends BaseResponse {
+    @SerializedName(ApiConstants.LOAD_BALANCER_DEVICE_ID) @Param(description="device id of the F5 load balancer")
+    private IdentityProxy id = new IdentityProxy("external_load_balancer_devices");
+
+    @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network to which this F5 device belongs to")
+    private IdentityProxy physicalNetworkId = new IdentityProxy("physical_network");
+
+    @SerializedName(ApiConstants.PROVIDER) @Param(description="name of the provider")
+    private String providerName;
+    
+    @SerializedName(ApiConstants.LOAD_BALANCER_DEVICE_NAME) @Param(description="device name")
+    private String deviceName; 
+    
+    @SerializedName(ApiConstants.LOAD_BALANCER_DEVICE_STATE) @Param(description="device state")
+    private String deviceState;
+
+    @SerializedName(ApiConstants.LOAD_BALANCER_DEVICE_CAPACITY) @Param(description="device capacity")
+    private Long deviceCapacity;
+
+    @SerializedName(ApiConstants.LOAD_BALANCER_DEVICE_DEDICATED) @Param(description="true if device is dedicated for an account")
+    private Boolean dedicatedLoadBalancer;
+
+    @SerializedName(ApiConstants.INLINE) @Param(description="true if device is inline with firewall device")
+    private Boolean inlineLoadBalancer;
+
+    @SerializedName(ApiConstants.PUBLIC_INTERFACE) @Param(description="the public interface of the load balancer")
+    private String publicInterface;
+    
+    @SerializedName(ApiConstants.PRIVATE_INTERFACE) @Param(description="the private interface of the load balancer")
+    private String privateInterface;
+
+    @SerializedName(ApiConstants.IP_ADDRESS) @Param(description="the management IP address of the external load balancer")
+    private String ipAddress;
+
+    public void setId(long lbDeviceId) {
+        this.id.setValue(lbDeviceId);
+    }
+
+    public void setPhysicalNetworkId(long physicalNetworkId) {
+        this.physicalNetworkId.setValue(physicalNetworkId);
+    }
+
+    public void setProvider(String provider) {
+        this.providerName = provider;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public void setDeviceCapacity(long deviceCapacity) {
+        this.deviceCapacity = deviceCapacity;
+    }
+
+    public void setDeviceState(String deviceState) {
+        this.deviceState = deviceState;
+    }
+
+    public void setDedicatedLoadBalancer(boolean isDedicated) {
+        this.dedicatedLoadBalancer = isDedicated;
+    }
+
+    public void setInlineMode(boolean inline) {
+        this.inlineLoadBalancer = inline;
+    }
+
+    public void setPublicInterface(String publicInterface) {
+        this.publicInterface = publicInterface;
+    }
+
+    public void setPrivateInterface(String privateInterface) {
+        this.privateInterface = privateInterface;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/422c4ce5/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java
new file mode 100644
index 0000000..1b1cbf7
--- /dev/null
+++ b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java
@@ -0,0 +1,470 @@
+// Copyright 2012 Citrix Systems, Inc. Licensed under the
+// Apache License, Version 2.0 (the "License"); you may not use this
+// file except in compliance with the License.  Citrix Systems, Inc.
+// reserves all rights not expressly granted by the License.
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
+// Automatically generated by addcopyright.py at 04/03/2012
+package com.cloud.network.element;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ejb.Local;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.api.commands.AddExternalLoadBalancerCmd;
+import com.cloud.api.commands.AddF5LoadBalancerCmd;
+import com.cloud.api.commands.ConfigureF5LoadBalancerCmd;
+import com.cloud.api.commands.DeleteExternalLoadBalancerCmd;
+import com.cloud.api.commands.DeleteF5LoadBalancerCmd;
+import com.cloud.api.commands.ListExternalLoadBalancersCmd;
+import com.cloud.api.commands.ListF5LoadBalancerNetworksCmd;
+import com.cloud.api.commands.ListF5LoadBalancersCmd;
+import com.cloud.api.response.F5LoadBalancerResponse;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.ConfigurationManager;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InsufficientNetworkCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.host.dao.HostDetailsDao;
+import com.cloud.network.ExternalLoadBalancerDeviceManager;
+import com.cloud.network.ExternalLoadBalancerDeviceManagerImpl;
+import com.cloud.network.ExternalLoadBalancerDeviceVO;
+import com.cloud.network.ExternalLoadBalancerDeviceVO.LBDeviceState;
+import com.cloud.network.ExternalNetworkDeviceManager.NetworkDevice;
+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.NetworkExternalLoadBalancerVO;
+import com.cloud.network.NetworkManager;
+import com.cloud.network.NetworkVO;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.PhysicalNetworkVO;
+import com.cloud.network.PublicIpAddress;
+import com.cloud.network.dao.ExternalLoadBalancerDeviceDao;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkExternalLoadBalancerDao;
+import com.cloud.network.dao.NetworkServiceMapDao;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.lb.LoadBalancingRule;
+import com.cloud.network.resource.F5BigIpResource;
+import com.cloud.network.rules.LbStickinessMethod;
+import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.resource.ServerResource;
+import com.cloud.server.api.response.ExternalLoadBalancerResponse;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+import com.google.gson.Gson;
+
+@Local(value = NetworkElement.class)
+public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, IpDeployer, F5ExternalLoadBalancerElementService, ExternalLoadBalancerDeviceManager {
+
+    private static final Logger s_logger = Logger.getLogger(F5ExternalLoadBalancerElement.class);
+
+    @Inject
+    NetworkManager _networkManager;
+    @Inject
+    ConfigurationManager _configMgr;
+    @Inject
+    NetworkServiceMapDao _ntwkSrvcDao;
+    @Inject
+    DataCenterDao _dcDao;
+    @Inject
+    PhysicalNetworkDao _physicalNetworkDao;
+    @Inject
+    HostDao _hostDao;
+    @Inject
+    ExternalLoadBalancerDeviceDao _lbDeviceDao;
+    @Inject
+    NetworkExternalLoadBalancerDao _networkLBDao;
+    @Inject
+    NetworkDao _networkDao;
+    @Inject
+    HostDetailsDao _detailsDao;
+    @Inject
+    ConfigurationDao _configDao;
+
+    private boolean canHandle(Network config) {
+        if (config.getGuestType() != Network.GuestType.Isolated || config.getTrafficType() != TrafficType.Guest) {
+            s_logger.trace("Not handling network with Type  " + config.getGuestType() + " and traffic type " + config.getTrafficType());
+            return false;
+        }
+
+        return (_networkManager.isProviderForNetwork(getProvider(), config.getId()) && _ntwkSrvcDao.canProviderSupportServiceInNetwork(config.getId(), Service.Lb, Network.Provider.F5BigIp));
+    }
+
+    @Override
+    public boolean implement(Network guestConfig, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException,
+            InsufficientNetworkCapacityException {
+
+        if (!canHandle(guestConfig)) {
+            return false;
+        }
+
+        try {
+            return manageGuestNetworkWithExternalLoadBalancer(true, guestConfig);
+        } catch (InsufficientCapacityException capacityException) {
+            throw new ResourceUnavailableException("There are no F5 load balancer devices with the free capacity for implementing this network", DataCenter.class, guestConfig.getDataCenterId());
+        }
+    }
+
+    @Override
+    public boolean prepare(Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException,
+            InsufficientNetworkCapacityException, ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean release(Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, ReservationContext context) {
+        return true;
+    }
+
+    @Override
+    public boolean shutdown(Network guestConfig, ReservationContext context, boolean cleanup) throws ResourceUnavailableException, ConcurrentOperationException {
+        if (!canHandle(guestConfig)) {
+            return false;
+        }
+
+        try {
+            return manageGuestNetworkWithExternalLoadBalancer(false, guestConfig);
+        } catch (InsufficientCapacityException capacityException) {
+            // TODO: handle out of capacity exception
+            return false;
+        }
+    }
+
+    @Override
+    public boolean destroy(Network config) {
+        return true;
+    }
+
+    @Override
+    public boolean validateLBRule(Network network, LoadBalancingRule rule) {
+        return true;
+    }
+
+    @Override
+    public boolean applyLBRules(Network config, List<LoadBalancingRule> rules) throws ResourceUnavailableException {
+        if (!canHandle(config)) {
+            return false;
+        }
+
+        return applyLoadBalancerRules(config, rules);
+    }
+
+    @Override
+    public Map<Service, Map<Capability, String>> getCapabilities() {
+        Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
+
+        // Set capabilities for LB service
+        Map<Capability, String> lbCapabilities = new HashMap<Capability, String>();
+
+        // Specifies that the RoundRobin and Leastconn algorithms are supported for load balancing rules
+        lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn");
+
+        // specifies that F5 BIG IP network element can provide shared mode only
+        lbCapabilities.put(Capability.SupportedLBIsolation, "dedicated, shared");
+
+        // Specifies that load balancing rules can be made for either TCP or UDP traffic
+        lbCapabilities.put(Capability.SupportedProtocols, "tcp,udp");
+
+        // Specifies that this element can measure network usage on a per public IP basis
+        lbCapabilities.put(Capability.TrafficStatistics, "per public ip");
+
+        // Specifies that load balancing rules can only be made with public IPs that aren't source NAT IPs
+        lbCapabilities.put(Capability.LoadBalancingSupportedIps, "additional");
+
+        LbStickinessMethod method;
+        List<LbStickinessMethod> methodList = new ArrayList<LbStickinessMethod>();
+        method = new LbStickinessMethod(StickinessMethodType.LBCookieBased, "This is cookie based sticky method, can be used only for http");
+        methodList.add(method);
+        method.addParam("holdtime", false, "time period (in seconds) for which persistence is in effect.", false);
+
+        Gson gson = new Gson();
+        String stickyMethodList = gson.toJson(methodList);
+        lbCapabilities.put(Capability.SupportedStickinessMethods, stickyMethodList);
+
+        capabilities.put(Service.Lb, lbCapabilities);
+
+        return capabilities;
+    }
+
+    @Override
+    public Provider getProvider() {
+        return Provider.F5BigIp;
+    }
+
+    @Override
+    public boolean isReady(PhysicalNetworkServiceProvider provider) {
+        List<ExternalLoadBalancerDeviceVO> lbDevices = _lbDeviceDao.listByPhysicalNetworkAndProvider(provider.getPhysicalNetworkId(), Provider.F5BigIp.getName());
+
+        // true if at-least one F5 device is added in to physical network and is in configured (in enabled state) state
+        if (lbDevices != null && !lbDevices.isEmpty()) {
+            for (ExternalLoadBalancerDeviceVO lbDevice : lbDevices) {
+                if (lbDevice.getState() == LBDeviceState.Enabled) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException,
+            ResourceUnavailableException {
+        // TODO Auto-generated method stub
+        return true;
+    }
+
+    @Override
+    public boolean canEnableIndividualServices() {
+        return false;
+    }
+
+    @Override
+    public String getPropertiesFile() {
+        return "f5bigip_commands.properties";
+    }
+
+    @Override
+    @Deprecated
+    public Host addExternalLoadBalancer(AddExternalLoadBalancerCmd cmd) {
+        Long zoneId = cmd.getZoneId();
+        DataCenterVO zone = null;
+        PhysicalNetworkVO pNetwork = null;
+        ExternalLoadBalancerDeviceVO lbDeviceVO = null;
+        HostVO lbHost = null;
+
+        zone = _dcDao.findById(zoneId);
+        if (zone == null) {
+            throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId);
+        }
+
+        List<PhysicalNetworkVO> physicalNetworks = _physicalNetworkDao.listByZone(zoneId);
+        if ((physicalNetworks == null) || (physicalNetworks.size() > 1)) {
+            throw new InvalidParameterValueException("There are no physical networks or multiple physical networks configured in zone with ID: "
+                    + zoneId + " to add this device.");
+        }
+        pNetwork = physicalNetworks.get(0);
+
+        String deviceType = NetworkDevice.F5BigIpLoadBalancer.getName();
+        lbDeviceVO = addExternalLoadBalancer(pNetwork.getId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), deviceType, (ServerResource) new F5BigIpResource());
+
+        if (lbDeviceVO != null) {
+            lbHost = _hostDao.findById(lbDeviceVO.getHostId());
+        }
+
+        return lbHost;
+    }
+
+    @Override
+    @Deprecated
+    public boolean deleteExternalLoadBalancer(DeleteExternalLoadBalancerCmd cmd) {
+        return deleteExternalLoadBalancer(cmd.getId());
+    }
+
+    @Override
+    @Deprecated
+    public List<Host> listExternalLoadBalancers(ListExternalLoadBalancersCmd cmd) {
+        Long zoneId = cmd.getZoneId();
+        DataCenterVO zone = null;
+        PhysicalNetworkVO pNetwork = null;
+
+        if (zoneId != null) {
+            zone = _dcDao.findById(zoneId);
+            if (zone == null) {
+                throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId);
+            }
+
+            List<PhysicalNetworkVO> physicalNetworks = _physicalNetworkDao.listByZone(zoneId);
+            if ((physicalNetworks == null) || (physicalNetworks.size() > 1)) {
+                throw new InvalidParameterValueException("There are no physical networks or multiple physical networks configured in zone with ID: "
+                        + zoneId + " to add this device.");
+            }
+            pNetwork = physicalNetworks.get(0);
+            return listExternalLoadBalancers(pNetwork.getId(), NetworkDevice.F5BigIpLoadBalancer.getName());
+        } else {
+            throw new InvalidParameterValueException("Zone Id must be specified to list the external load balancers");
+        }
+    }
+
+    @Override
+    @Deprecated
+    public ExternalLoadBalancerResponse createExternalLoadBalancerResponse(Host externalLb) {
+        return super.createExternalLoadBalancerResponse(externalLb);
+    }
+
+    @Override
+    public ExternalLoadBalancerDeviceVO addF5LoadBalancer(AddF5LoadBalancerCmd cmd) {
+        String deviceName = cmd.getDeviceType();
+        if (!deviceName.equalsIgnoreCase(NetworkDevice.F5BigIpLoadBalancer.getName())) {
+            throw new InvalidParameterValueException("Invalid F5 load balancer device type");
+        }
+
+        return addExternalLoadBalancer(cmd.getPhysicalNetworkId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), deviceName, (ServerResource) new F5BigIpResource());
+
+    }
+
+    @Override
+    public boolean deleteF5LoadBalancer(DeleteF5LoadBalancerCmd cmd) {
+        Long lbDeviceId = cmd.getLoadBalancerDeviceId();
+
+        ExternalLoadBalancerDeviceVO lbDeviceVo = _lbDeviceDao.findById(lbDeviceId);
+        if ((lbDeviceVo == null) || !lbDeviceVo.getDeviceName().equalsIgnoreCase(NetworkDevice.F5BigIpLoadBalancer.getName())) {
+            throw new InvalidParameterValueException("No F5 load balancer device found with ID: " + lbDeviceId);
+        }
+
+        return deleteExternalLoadBalancer(lbDeviceVo.getHostId());
+    }
+
+    @Override
+    public ExternalLoadBalancerDeviceVO configureF5LoadBalancer(ConfigureF5LoadBalancerCmd cmd) {
+        Long lbDeviceId = cmd.getLoadBalancerDeviceId();
+        Long capacity = cmd.getLoadBalancerCapacity();
+
+        ExternalLoadBalancerDeviceVO lbDeviceVo = _lbDeviceDao.findById(lbDeviceId);
+        if ((lbDeviceVo == null) || !lbDeviceVo.getDeviceName().equalsIgnoreCase(NetworkDevice.F5BigIpLoadBalancer.getName())) {
+            throw new InvalidParameterValueException("No F5 load balancer device found with ID: " + lbDeviceId);
+        }
+
+        if (capacity != null) {
+            // check if any networks are using this F5 device
+            List<NetworkExternalLoadBalancerVO> networks = _networkLBDao.listByLoadBalancerDeviceId(lbDeviceId);
+            if ((networks != null) && !networks.isEmpty()) {
+                if (capacity < networks.size()) {
+                    throw new CloudRuntimeException("There are more number of networks already using this F5 device than configured capacity");
+                }
+            }
+            if (capacity != null) {
+                lbDeviceVo.setCapacity(capacity);
+            }
+        }
+
+        lbDeviceVo.setState(LBDeviceState.Enabled);
+        _lbDeviceDao.update(lbDeviceId, lbDeviceVo);
+        return lbDeviceVo;
+    }
+
+    @Override
+    public List<ExternalLoadBalancerDeviceVO> listF5LoadBalancers(ListF5LoadBalancersCmd cmd) {
+        Long physcialNetworkId = cmd.getPhysicalNetworkId();
+        Long lbDeviceId = cmd.getLoadBalancerDeviceId();
+        PhysicalNetworkVO pNetwork = null;
+        List<ExternalLoadBalancerDeviceVO> lbDevices = new ArrayList<ExternalLoadBalancerDeviceVO>();
+
+        if (physcialNetworkId == null && lbDeviceId == null) {
+            throw new InvalidParameterValueException("Either physical network Id or load balancer device Id must be specified");
+        }
+
+        if (lbDeviceId != null) {
+            ExternalLoadBalancerDeviceVO lbDeviceVo = _lbDeviceDao.findById(lbDeviceId);
+            if (lbDeviceVo == null || !lbDeviceVo.getDeviceName().equalsIgnoreCase(NetworkDevice.F5BigIpLoadBalancer.getName())) {
+                throw new InvalidParameterValueException("Could not find F5 load balancer device with ID: " + lbDeviceId);
+            }
+            lbDevices.add(lbDeviceVo);
+            return lbDevices;
+        }
+
+        if (physcialNetworkId != null) {
+            pNetwork = _physicalNetworkDao.findById(physcialNetworkId);
+            if (pNetwork == null) {
+                throw new InvalidParameterValueException("Could not find phyical network with ID: " + physcialNetworkId);
+            }
+            lbDevices = _lbDeviceDao.listByPhysicalNetworkAndProvider(physcialNetworkId, Provider.F5BigIp.getName());
+            return lbDevices;
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<? extends Network> listNetworks(ListF5LoadBalancerNetworksCmd cmd) {
+        Long lbDeviceId = cmd.getLoadBalancerDeviceId();
+        List<NetworkVO> networks = new ArrayList<NetworkVO>();
+
+        ExternalLoadBalancerDeviceVO lbDeviceVo = _lbDeviceDao.findById(lbDeviceId);
+        if (lbDeviceVo == null || !lbDeviceVo.getDeviceName().equalsIgnoreCase(NetworkDevice.F5BigIpLoadBalancer.getName())) {
+            throw new InvalidParameterValueException("Could not find F5 load balancer device with ID " + lbDeviceId);
+        }
+
+        List<NetworkExternalLoadBalancerVO> networkLbMaps = _networkLBDao.listByLoadBalancerDeviceId(lbDeviceId);
+        if (networkLbMaps != null && !networkLbMaps.isEmpty()) {
+            for (NetworkExternalLoadBalancerVO networkLbMap : networkLbMaps) {
+                NetworkVO network = _networkDao.findById(networkLbMap.getNetworkId());
+                networks.add(network);
+            }
+        }
+
+        return networks;
+    }
+
+    @Override
+    public F5LoadBalancerResponse createF5LoadBalancerResponse(ExternalLoadBalancerDeviceVO lbDeviceVO) {
+        F5LoadBalancerResponse response = new F5LoadBalancerResponse();
+        Host lbHost = _hostDao.findById(lbDeviceVO.getHostId());
+        Map<String, String> lbDetails = _detailsDao.findDetails(lbDeviceVO.getHostId());
+
+        response.setId(lbDeviceVO.getId());
+        response.setIpAddress(lbHost.getPrivateIpAddress());
+        response.setPhysicalNetworkId(lbDeviceVO.getPhysicalNetworkId());
+        response.setPublicInterface(lbDetails.get("publicInterface"));
+        response.setPrivateInterface(lbDetails.get("privateInterface"));
+        response.setDeviceName(lbDeviceVO.getDeviceName());
+        if (lbDeviceVO.getCapacity() == 0) {
+            long defaultLbCapacity = NumbersUtil.parseLong(_configDao.getValue(Config.DefaultExternalLoadBalancerCapacity.key()), 50);
+            response.setDeviceCapacity(defaultLbCapacity);
+        } else {
+            response.setDeviceCapacity(lbDeviceVO.getCapacity());
+        }
+        response.setInlineMode(lbDeviceVO.getIsInLineMode());
+        response.setDedicatedLoadBalancer(lbDeviceVO.getIsDedicatedDevice());
+        response.setProvider(lbDeviceVO.getProviderName());
+        response.setDeviceState(lbDeviceVO.getState().name());
+        response.setObjectName("f5loadbalancer");
+        return response;
+    }
+
+    @Override
+    public boolean verifyServicesCombination(List<String> services) {
+        return true;
+    }
+
+    @Override
+    public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Service> service) throws ResourceUnavailableException {
+        // return true, as IP will be associated as part of LB rule configuration
+        return false;
+    }
+
+    @Override
+    public IpDeployer getIpDeployer(Network network) {
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/422c4ce5/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElementService.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElementService.java b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElementService.java
new file mode 100644
index 0000000..ee288ef
--- /dev/null
+++ b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElementService.java
@@ -0,0 +1,84 @@
+// Copyright 2012 Citrix Systems, Inc. Licensed under the
+// Apache License, Version 2.0 (the "License"); you may not use this
+// file except in compliance with the License.  Citrix Systems, Inc.
+// reserves all rights not expressly granted by the License.
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
+// Automatically generated by addcopyright.py at 04/03/2012
+package com.cloud.network.element;
+
+import java.util.List;
+
+import com.cloud.api.commands.AddExternalLoadBalancerCmd;
+import com.cloud.api.commands.AddF5LoadBalancerCmd;
+import com.cloud.api.commands.ConfigureF5LoadBalancerCmd;
+import com.cloud.api.commands.DeleteExternalLoadBalancerCmd;
+import com.cloud.api.commands.DeleteF5LoadBalancerCmd;
+import com.cloud.api.commands.ListExternalLoadBalancersCmd;
+import com.cloud.api.commands.ListF5LoadBalancerNetworksCmd;
+import com.cloud.api.commands.ListF5LoadBalancersCmd;
+import com.cloud.api.response.F5LoadBalancerResponse;
+import com.cloud.host.Host;
+import com.cloud.network.ExternalLoadBalancerDeviceVO;
+import com.cloud.network.Network;
+import com.cloud.server.api.response.ExternalLoadBalancerResponse;
+import com.cloud.utils.component.PluggableService;
+
+@SuppressWarnings("deprecation")
+public interface F5ExternalLoadBalancerElementService extends PluggableService {
+
+    /**
+     * adds a F5 load balancer device in to a physical network
+     * @param AddF5LoadBalancerCmd 
+     * @return ExternalLoadBalancerDeviceVO object for the device added
+     */
+    public ExternalLoadBalancerDeviceVO addF5LoadBalancer(AddF5LoadBalancerCmd cmd);
+
+    /**
+     * removes a F5 load balancer device from a physical network
+     * @param DeleteF5LoadBalancerCmd 
+     * @return true if F5 load balancer device is successfully deleted
+     */
+    public boolean deleteF5LoadBalancer(DeleteF5LoadBalancerCmd cmd);
+
+    /**
+     * configures a F5 load balancer device added in a physical network
+     * @param ConfigureF5LoadBalancerCmd
+     * @return ExternalLoadBalancerDeviceVO for the device configured
+     */
+    public ExternalLoadBalancerDeviceVO configureF5LoadBalancer(ConfigureF5LoadBalancerCmd cmd);
+
+    /**
+     * lists all the load balancer devices added in to a physical network
+     * @param ListF5LoadBalancersCmd
+     * @return list of ExternalLoadBalancerDeviceVO for the devices in the physical network.
+     */
+    public List<ExternalLoadBalancerDeviceVO> listF5LoadBalancers(ListF5LoadBalancersCmd cmd);
+
+    /**
+     * lists all the guest networks using a F5 load balancer device
+     * @param ListF5LoadBalancerNetworksCmd
+     * @return list of the guest networks that are using this F5 load balancer
+     */
+    public List<? extends Network> listNetworks(ListF5LoadBalancerNetworksCmd cmd);
+
+    public F5LoadBalancerResponse createF5LoadBalancerResponse(ExternalLoadBalancerDeviceVO lbDeviceVO);
+
+    /* Deprecated API helper function */
+    @Deprecated  // API helper function supported for backward compatibility
+    public Host addExternalLoadBalancer(AddExternalLoadBalancerCmd cmd);
+
+    @Deprecated //  API helper function supported for backward compatibility
+    public boolean deleteExternalLoadBalancer(DeleteExternalLoadBalancerCmd cmd);
+
+    @Deprecated //  API helper function supported for backward compatibility
+    public List<Host> listExternalLoadBalancers(ListExternalLoadBalancersCmd cmd);
+
+    @Deprecated //  API helper function supported for backward compatibility
+    public ExternalLoadBalancerResponse createExternalLoadBalancerResponse(Host externalLb);
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/422c4ce5/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java b/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java
new file mode 100644
index 0000000..501656f
--- /dev/null
+++ b/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java
@@ -0,0 +1,1081 @@
+// Copyright 2012 Citrix Systems, Inc. Licensed under the
+// Apache License, Version 2.0 (the "License"); you may not use this
+// file except in compliance with the License.  Citrix Systems, Inc.
+// reserves all rights not expressly granted by the License.
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
+// Automatically generated by addcopyright.py at 04/03/2012
+package com.cloud.network.resource;
+
+import iControl.CommonEnabledState;
+import iControl.CommonIPPortDefinition;
+import iControl.CommonStatistic;
+import iControl.CommonStatisticType;
+import iControl.CommonVirtualServerDefinition;
+import iControl.Interfaces;
+import iControl.LocalLBLBMethod;
+import iControl.LocalLBNodeAddressBindingStub;
+import iControl.LocalLBPersistenceMode;
+import iControl.LocalLBPoolBindingStub;
+import iControl.LocalLBProfileContextType;
+import iControl.LocalLBProfilePersistenceBindingStub;
+import iControl.LocalLBProfileULong;
+import iControl.LocalLBVirtualServerBindingStub;
+import iControl.LocalLBVirtualServerVirtualServerPersistence;
+import iControl.LocalLBVirtualServerVirtualServerProfile;
+import iControl.LocalLBVirtualServerVirtualServerResource;
+import iControl.LocalLBVirtualServerVirtualServerStatisticEntry;
+import iControl.LocalLBVirtualServerVirtualServerStatistics;
+import iControl.LocalLBVirtualServerVirtualServerType;
+import iControl.NetworkingMemberTagType;
+import iControl.NetworkingMemberType;
+import iControl.NetworkingRouteDomainBindingStub;
+import iControl.NetworkingSelfIPBindingStub;
+import iControl.NetworkingVLANBindingStub;
+import iControl.NetworkingVLANMemberEntry;
+import iControl.SystemConfigSyncBindingStub;
+import iControl.SystemConfigSyncSaveMode;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.IAgentControl;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer;
+import com.cloud.agent.api.ExternalNetworkResourceUsageCommand;
+import com.cloud.agent.api.MaintainAnswer;
+import com.cloud.agent.api.MaintainCommand;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.ReadyAnswer;
+import com.cloud.agent.api.ReadyCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupExternalLoadBalancerCommand;
+import com.cloud.agent.api.routing.IpAssocAnswer;
+import com.cloud.agent.api.routing.IpAssocCommand;
+import com.cloud.agent.api.routing.LoadBalancerConfigCommand;
+import com.cloud.agent.api.routing.NetworkElementCommand;
+import com.cloud.agent.api.to.IpAddressTO;
+import com.cloud.agent.api.to.LoadBalancerTO;
+import com.cloud.agent.api.to.LoadBalancerTO.DestinationTO;
+import com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO;
+import com.cloud.host.Host;
+import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType;
+import com.cloud.resource.ServerResource;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.exception.ExecutionException;
+import com.cloud.utils.net.NetUtils;
+
+public class F5BigIpResource implements ServerResource {
+	
+	private enum LbAlgorithm {
+		RoundRobin(null, LocalLBLBMethod.LB_METHOD_ROUND_ROBIN),
+		LeastConn(null, LocalLBLBMethod.LB_METHOD_LEAST_CONNECTION_MEMBER);
+		
+		String persistenceProfileName;
+		LocalLBLBMethod method;
+		
+		LbAlgorithm(String persistenceProfileName, LocalLBLBMethod method) {
+			this.persistenceProfileName = persistenceProfileName;
+			this.method = method;
+		}
+		
+		public String getPersistenceProfileName() {
+			return persistenceProfileName;
+		}
+		
+		public LocalLBLBMethod getMethod() {
+			return method;
+		}		
+	}
+	
+	private enum LbProtocol {
+		tcp,
+		udp;
+	}
+
+	private String _name;
+	private String _zoneId;
+	private String _ip;
+	private String _username;
+	private String _password;
+	private String _publicInterface;
+	private String _privateInterface;
+	private Integer _numRetries; 
+	private String _guid;
+	private boolean _inline;
+
+	private Interfaces _interfaces;
+	private LocalLBVirtualServerBindingStub _virtualServerApi;
+	private LocalLBPoolBindingStub _loadbalancerApi;
+	private LocalLBNodeAddressBindingStub _nodeApi;
+	private NetworkingVLANBindingStub _vlanApi;
+	private NetworkingSelfIPBindingStub _selfIpApi;
+	private NetworkingRouteDomainBindingStub _routeDomainApi;
+	private SystemConfigSyncBindingStub _configSyncApi;
+	private LocalLBProfilePersistenceBindingStub  _persistenceProfileApi;
+	private String _objectNamePathSep = "-";
+	private String _routeDomainIdentifier = "%";
+	
+	private static final Logger s_logger = Logger.getLogger(F5BigIpResource.class);
+	
+	@Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+    	try {    		    		
+    		XTrustProvider.install();
+    		
+    		_name = (String) params.get("name");
+    		if (_name == null) {
+    			throw new ConfigurationException("Unable to find name");
+    		}
+    		
+    		_zoneId = (String) params.get("zoneId");
+    		if (_zoneId == null) {
+    			throw new ConfigurationException("Unable to find zone");
+    		}
+    		
+    		_ip = (String) params.get("ip");
+    		if (_ip == null) {
+    			throw new ConfigurationException("Unable to find IP");
+    		}
+    		
+    		_username = (String) params.get("username");
+    		if (_username == null) {
+    			throw new ConfigurationException("Unable to find username");
+    		}
+    		
+    		_password = (String) params.get("password");
+    		if (_password == null) {
+    			throw new ConfigurationException("Unable to find password");
+    		}    		    		
+    		
+    		_publicInterface = (String) params.get("publicinterface");
+    		if (_publicInterface == null) {
+    			throw new ConfigurationException("Unable to find public interface");
+    		}
+    		
+    		_privateInterface = (String) params.get("privateinterface");
+    		if (_privateInterface == null) {
+    			throw new ConfigurationException("Unable to find private interface");
+    		}
+    		
+    		_numRetries = NumbersUtil.parseInt((String) params.get("numretries"), 1);
+			    		
+    		_guid = (String)params.get("guid");
+            if (_guid == null) {
+                throw new ConfigurationException("Unable to find the guid");
+            }
+            
+            _inline = Boolean.parseBoolean((String) params.get("inline"));
+    		    		    	
+            login();
+		
+    		return true;
+    	} catch (Exception e) {
+    		throw new ConfigurationException(e.getMessage());
+    	}
+    	
+    }
+
+	@Override
+    public StartupCommand[] initialize() {   
+		StartupExternalLoadBalancerCommand cmd = new StartupExternalLoadBalancerCommand();
+		cmd.setName(_name);
+		cmd.setDataCenter(_zoneId);
+		cmd.setPod("");
+    	cmd.setPrivateIpAddress(_ip);
+    	cmd.setStorageIpAddress("");
+    	cmd.setVersion("");
+    	cmd.setGuid(_guid);
+    	return new StartupCommand[]{cmd};
+    }
+
+	@Override
+    public Host.Type getType() {
+		return Host.Type.ExternalLoadBalancer;
+	}
+	
+	@Override
+	public String getName() {
+		return _name;
+	}
+	
+	@Override
+    public PingCommand getCurrentStatus(final long id) {
+		return new PingCommand(Host.Type.ExternalLoadBalancer, id);
+    }
+	
+	@Override
+	public boolean start() {
+		return true;
+	}
+
+	@Override
+	public boolean stop() {
+		return true;
+	}
+
+	@Override
+	public void disconnected() {
+		return;
+	}		
+
+	@Override
+    public IAgentControl getAgentControl() {
+		return null;
+	}
+
+	@Override
+    public void setAgentControl(IAgentControl agentControl) {
+		return;
+	}
+
+	@Override
+    public Answer executeRequest(Command cmd) {
+		return executeRequest(cmd, _numRetries);
+	}		
+	
+	private Answer executeRequest(Command cmd, int numRetries) {
+		if (cmd instanceof ReadyCommand) {
+			return execute((ReadyCommand) cmd);
+		} else if (cmd instanceof MaintainCommand) {
+			return execute((MaintainCommand) cmd);
+		} else if (cmd instanceof IpAssocCommand) {
+			return execute((IpAssocCommand) cmd, numRetries);
+		} else if (cmd instanceof LoadBalancerConfigCommand) {
+			return execute((LoadBalancerConfigCommand) cmd, numRetries);
+		} else if (cmd instanceof ExternalNetworkResourceUsageCommand) {
+			return execute((ExternalNetworkResourceUsageCommand) cmd);
+		} else {
+			return Answer.createUnsupportedCommandAnswer(cmd);
+		}
+	}
+	
+	private Answer retry(Command cmd, int numRetries) {				
+		int numRetriesRemaining = numRetries - 1;
+		s_logger.error("Retrying " + cmd.getClass().getSimpleName() + ". Number of retries remaining: " + numRetriesRemaining);
+		return executeRequest(cmd, numRetriesRemaining);	
+	}
+	
+	private boolean shouldRetry(int numRetries) {
+        try {
+            if (numRetries > 0) {
+                login();
+                return true;
+            }
+        } catch (Exception e) {
+            s_logger.error("Failed to log in to F5 device at " + _ip + " due to " + e.getMessage());
+        }
+        return false;
+	}
+	
+	private Answer execute(ReadyCommand cmd) {
+        return new ReadyAnswer(cmd);
+    }
+	
+	private Answer execute(MaintainCommand cmd) {
+		return new MaintainAnswer(cmd);
+	}	
+	
+	private synchronized Answer execute(IpAssocCommand cmd, int numRetries) {
+	    String[] results = new String[cmd.getIpAddresses().length];
+        int i = 0;
+		try {		
+			IpAddressTO[] ips = cmd.getIpAddresses();
+            for (IpAddressTO ip : ips) {
+                long guestVlanTag = Long.valueOf(ip.getVlanId());
+                String vlanSelfIp = _inline ? tagAddressWithRouteDomain(ip.getVlanGateway(), guestVlanTag) : ip.getVlanGateway();
+                String vlanNetmask = ip.getVlanNetmask();      
+                
+                // Delete any existing guest VLAN with this tag, self IP, and netmask
+                deleteGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask);
+                
+                if (ip.isAdd()) {
+                	// Add a new guest VLAN
+                    addGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask);
+                }
+                
+                saveConfiguration();               
+                results[i++] = ip.getPublicIp() + " - success";
+            }
+                        
+		} catch (ExecutionException e) {
+			s_logger.error("Failed to execute IPAssocCommand due to " + e);				    
+		    
+		    if (shouldRetry(numRetries)) {
+		    	return retry(cmd, numRetries);
+		    } else {
+		    	results[i++] = IpAssocAnswer.errorResult;
+		    }
+		}		
+		
+		return new IpAssocAnswer(cmd, results);
+	}
+	
+	private synchronized Answer execute(LoadBalancerConfigCommand cmd, int numRetries) {
+		try {			
+			long guestVlanTag = Long.parseLong(cmd.getAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG));
+			LoadBalancerTO[] loadBalancers = cmd.getLoadBalancers();
+			for (LoadBalancerTO loadBalancer : loadBalancers) {
+				LbProtocol lbProtocol;
+				try {
+					if (loadBalancer.getProtocol() == null) {
+						lbProtocol = LbProtocol.tcp;
+					} else {
+						lbProtocol = LbProtocol.valueOf(loadBalancer.getProtocol());
+					}
+				} catch (IllegalArgumentException e) {
+					throw new ExecutionException("Got invalid protocol: " + loadBalancer.getProtocol());
+				}
+				
+				LbAlgorithm lbAlgorithm;
+				if (loadBalancer.getAlgorithm().equals("roundrobin")) {
+					lbAlgorithm = LbAlgorithm.RoundRobin;
+				} else if (loadBalancer.getAlgorithm().equals("leastconn")) {
+					lbAlgorithm = LbAlgorithm.LeastConn;
+				} else {
+					throw new ExecutionException("Got invalid algorithm: " + loadBalancer.getAlgorithm());
+				}		
+				
+				String srcIp = _inline ? tagAddressWithRouteDomain(loadBalancer.getSrcIp(), guestVlanTag) : loadBalancer.getSrcIp();
+				int srcPort = loadBalancer.getSrcPort();	
+				String virtualServerName = genVirtualServerName(lbProtocol, srcIp, srcPort);
+												
+				boolean destinationsToAdd = false;
+				for (DestinationTO destination : loadBalancer.getDestinations()) {
+					if (!destination.isRevoked()) {
+						destinationsToAdd = true;
+						break;
+					}
+				}
+				
+				if (!loadBalancer.isRevoked() && destinationsToAdd) {		
+					// Add the pool 
+					addPool(virtualServerName, lbAlgorithm);
+					
+					// Add pool members  
+					List<String> activePoolMembers = new ArrayList<String>();
+					for (DestinationTO destination : loadBalancer.getDestinations()) {
+						if (!destination.isRevoked()) {
+							String destIp = _inline ? tagAddressWithRouteDomain(destination.getDestIp(), guestVlanTag) : destination.getDestIp();
+							addPoolMember(virtualServerName, destIp, destination.getDestPort());
+							activePoolMembers.add(destIp + "-" + destination.getDestPort());
+						}
+					}			
+					
+					// Delete any pool members that aren't in the current list of destinations
+					deleteInactivePoolMembers(virtualServerName, activePoolMembers);
+					
+					// Add the virtual server 
+					addVirtualServer(virtualServerName, lbProtocol, srcIp, srcPort, loadBalancer.getStickinessPolicies());
+				} else {
+					// Delete the virtual server with this protocol, source IP, and source port, along with its default pool and all pool members
+					deleteVirtualServerAndDefaultPool(virtualServerName);			
+				}
+			}																																																		
+			
+			saveConfiguration();				
+			return new Answer(cmd);		
+		} catch (ExecutionException e) {
+			s_logger.error("Failed to execute LoadBalancerConfigCommand due to " + e);
+			
+			if (shouldRetry(numRetries)) {
+				return retry(cmd, numRetries);
+			} else {
+				return new Answer(cmd, e);
+			}
+			
+		}
+	}		
+	
+	private synchronized ExternalNetworkResourceUsageAnswer execute(ExternalNetworkResourceUsageCommand cmd) {
+		try {
+			return getIpBytesSentAndReceived(cmd);
+		} catch (ExecutionException e) {
+			return new ExternalNetworkResourceUsageAnswer(cmd, e);
+		}
+	}
+	
+	private void saveConfiguration() throws ExecutionException {
+		try {
+			_configSyncApi.save_configuration("", SystemConfigSyncSaveMode.SAVE_BASE_LEVEL_CONFIG);		
+			_configSyncApi.save_configuration("", SystemConfigSyncSaveMode.SAVE_HIGH_LEVEL_CONFIG);		
+			s_logger.debug("Successfully saved F5 BigIp configuration.");
+		} catch (RemoteException e) {
+			s_logger.error("Failed to save F5 BigIp configuration due to: " + e);
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private void addGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask) throws ExecutionException {
+		try {
+			String vlanName = genVlanName(vlanTag);	
+			List<String> allVlans = getVlans();
+			if (!allVlans.contains(vlanName)) {				
+				String[] vlanNames = genStringArray(vlanName);
+				long[] vlanTags = genLongArray(vlanTag);
+				CommonEnabledState[] commonEnabledState = {CommonEnabledState.STATE_DISABLED};
+				
+				// Create the interface name
+				NetworkingVLANMemberEntry[][] vlanMemberEntries = {{new NetworkingVLANMemberEntry()}};
+				vlanMemberEntries[0][0].setMember_type(NetworkingMemberType.MEMBER_INTERFACE);
+				vlanMemberEntries[0][0].setTag_state(NetworkingMemberTagType.MEMBER_TAGGED);
+				vlanMemberEntries[0][0].setMember_name(_privateInterface);
+					
+				s_logger.debug("Creating a guest VLAN with tag " + vlanTag);
+				_vlanApi.create(vlanNames, vlanTags, vlanMemberEntries, commonEnabledState, new long[]{10L}, new String[]{"00:00:00:00:00:00"});		
+				
+				if (!getVlans().contains(vlanName)) {
+					throw new ExecutionException("Failed to create vlan with tag " + vlanTag);
+				}
+			}
+			
+			if (_inline) {
+				List<Long> allRouteDomains = getRouteDomains();
+				if (!allRouteDomains.contains(vlanTag)) {
+					long[] routeDomainIds = genLongArray(vlanTag);
+					String[][] vlanNames = new String[][]{genStringArray(genVlanName(vlanTag))};
+					
+					s_logger.debug("Creating route domain " + vlanTag);
+					_routeDomainApi.create(routeDomainIds, vlanNames);
+					
+					if (!getRouteDomains().contains(vlanTag)) {
+						throw new ExecutionException("Failed to create route domain " + vlanTag);
+					}
+				}
+			}
+			
+			List<String> allSelfIps = getSelfIps();
+			if (!allSelfIps.contains(vlanSelfIp)) {
+				String[] selfIpsToCreate = genStringArray(vlanSelfIp);
+				String[] vlans = genStringArray(vlanName);
+				String[] netmasks = genStringArray(vlanNetmask);
+				long[] unitIds = genLongArray(0L);
+				CommonEnabledState[] enabledStates = new CommonEnabledState[]{CommonEnabledState.STATE_DISABLED};
+				
+				s_logger.debug("Creating self IP " + vlanSelfIp);
+				_selfIpApi.create(selfIpsToCreate, vlans, netmasks, unitIds, enabledStates);
+				
+				if (!getSelfIps().contains(vlanSelfIp)) {
+					throw new ExecutionException("Failed to create self IP " + vlanSelfIp);
+				}
+			}
+		} catch (RemoteException e) {
+			s_logger.error(e);
+			throw new ExecutionException(e.getMessage());
+		}
+			
+	}
+	
+	private void deleteGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask) throws ExecutionException {
+		try {
+			// Delete all virtual servers and pools that use this guest VLAN
+			deleteVirtualServersInGuestVlan(vlanSelfIp, vlanNetmask);
+
+			List<String> allSelfIps = getSelfIps();
+			if (allSelfIps.contains(vlanSelfIp)) {
+				s_logger.debug("Deleting self IP " + vlanSelfIp);
+				_selfIpApi.delete_self_ip(genStringArray(vlanSelfIp));
+
+				if (getSelfIps().contains(vlanSelfIp)) {
+					throw new ExecutionException("Failed to delete self IP " + vlanSelfIp);
+				}
+			}
+			
+			if (_inline) {
+				List<Long> allRouteDomains = getRouteDomains();
+				if (allRouteDomains.contains(vlanTag)) {
+					s_logger.debug("Deleting route domain " + vlanTag);
+					_routeDomainApi.delete_route_domain(genLongArray(vlanTag));
+					
+					if (getRouteDomains().contains(vlanTag)) {
+						throw new ExecutionException("Failed to delete route domain " + vlanTag);
+					}
+				}
+			}
+
+			String vlanName = genVlanName(vlanTag);	
+			List<String> allVlans = getVlans();
+			if (allVlans.contains(vlanName)) {
+				_vlanApi.delete_vlan(genStringArray(vlanName));
+
+				if (getVlans().contains(vlanName)) {
+					throw new ExecutionException("Failed to delete VLAN with tag: " + vlanTag);
+				}
+			}				
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private void deleteVirtualServersInGuestVlan(String vlanSelfIp, String vlanNetmask) throws ExecutionException {
+		vlanSelfIp = stripRouteDomainFromAddress(vlanSelfIp);
+		List<String> virtualServersToDelete = new ArrayList<String>();
+		
+		List<String> allVirtualServers = getVirtualServers();
+		for (String virtualServerName : allVirtualServers) {
+			// Check if the virtual server's default pool has members in this guest VLAN
+			List<String> poolMembers = getMembers(virtualServerName);
+			for (String poolMemberName : poolMembers) {
+				String poolMemberIp = stripRouteDomainFromAddress(getIpAndPort(poolMemberName)[0]);
+				if (NetUtils.sameSubnet(vlanSelfIp, poolMemberIp, vlanNetmask)) {
+					virtualServersToDelete.add(virtualServerName);
+					break;
+				}
+			}			
+		}
+		
+		for (String virtualServerName : virtualServersToDelete) {
+			s_logger.debug("Found a virtual server (" + virtualServerName + ") for guest network with self IP " + vlanSelfIp + " that is active when the guest network is being destroyed.");
+			deleteVirtualServerAndDefaultPool(virtualServerName);
+		}
+	}
+	
+	private String genVlanName(long vlanTag) {
+		return "vlan-" + String.valueOf(vlanTag);
+	}
+	
+	private List<Long> getRouteDomains() throws ExecutionException {
+		try {
+			List<Long> routeDomains = new ArrayList<Long>();
+			long[] routeDomainsArray = _routeDomainApi.get_list();
+			
+			for (long routeDomainName : routeDomainsArray) {
+				routeDomains.add(routeDomainName);
+			}
+			
+			return routeDomains;
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private List<String> getSelfIps() throws ExecutionException {
+		try {
+			List<String> selfIps = new ArrayList<String>();
+			String[] selfIpsArray = _selfIpApi.get_list();
+
+			for (String selfIp : selfIpsArray) {
+				selfIps.add(selfIp);
+			}
+
+			return selfIps;
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private List<String> getVlans() throws ExecutionException {
+		try {
+			List<String> vlans = new ArrayList<String>();
+			String[] vlansArray = _vlanApi.get_list();
+
+			for (String vlan : vlansArray) {
+				vlans.add(vlan);
+			}
+
+			return vlans;
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	// Login	
+	
+	private void login() throws ExecutionException {
+		try {			
+			_interfaces = new Interfaces();
+			
+			if (!_interfaces.initialize(_ip, _username, _password)) {
+				throw new ExecutionException("Failed to log in to BigIp appliance");
+			}
+
+			// iControl.Interfaces.initialize always return true so make a call to force connect to F5 to validate credentials
+			_interfaces.getSystemSystemInfo().get_system_information();
+
+			_virtualServerApi = _interfaces.getLocalLBVirtualServer();
+			_loadbalancerApi = _interfaces.getLocalLBPool();		
+			_nodeApi = _interfaces.getLocalLBNodeAddress();
+			_vlanApi = _interfaces.getNetworkingVLAN();
+			_selfIpApi = _interfaces.getNetworkingSelfIP();
+			_routeDomainApi = _interfaces.getNetworkingRouteDomain();
+			_configSyncApi = _interfaces.getSystemConfigSync();
+			_persistenceProfileApi = _interfaces.getLocalLBProfilePersistence();
+		} catch (Exception e) {
+		    throw new ExecutionException("Failed to log in to BigIp appliance due to " + e.getMessage());
+		}
+	}
+
+	// Virtual server methods
+	
+	private void addVirtualServer(String virtualServerName, LbProtocol protocol, String srcIp, int srcPort, StickinessPolicyTO[] stickyPolicies) throws ExecutionException {
+		try {
+			if (!virtualServerExists(virtualServerName)) {
+				s_logger.debug("Adding virtual server " + virtualServerName);
+				_virtualServerApi.create(genVirtualServerDefinition(virtualServerName, protocol, srcIp, srcPort), new String[]{"255.255.255.255"}, genVirtualServerResource(virtualServerName), genVirtualServerProfile(protocol));
+				_virtualServerApi.set_snat_automap(genStringArray(virtualServerName));
+				if (!virtualServerExists(virtualServerName)) {
+					throw new ExecutionException("Failed to add virtual server " + virtualServerName);
+				}
+			}
+
+            if ((stickyPolicies != null) && (stickyPolicies.length > 0) && (stickyPolicies[0] != null)){
+                StickinessPolicyTO stickinessPolicy = stickyPolicies[0];
+                if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
+
+                    String[] profileNames = genStringArray("Cookie-profile-" + virtualServerName);
+                    if (!persistenceProfileExists(profileNames[0])) {
+                        LocalLBPersistenceMode[] lbPersistenceMode = new iControl.LocalLBPersistenceMode[1];
+                        lbPersistenceMode[0] = iControl.LocalLBPersistenceMode.PERSISTENCE_MODE_COOKIE;
+                        _persistenceProfileApi.create(profileNames, lbPersistenceMode);
+                        _virtualServerApi.add_persistence_profile(genStringArray(virtualServerName), genPersistenceProfile(profileNames[0]));
+                    }
+
+                    List<Pair<String, String>> paramsList = stickinessPolicy.getParams();
+                    for(Pair<String,String> param : paramsList) {
+                        if ("holdtime".equalsIgnoreCase(param.first())) {
+                            long timeout = 180; //F5 default
+                            if (param.second() != null) {
+                                timeout = Long.parseLong(param.second());
+                            }
+                            LocalLBProfileULong[] cookieTimeout =  new LocalLBProfileULong[1];
+                            cookieTimeout[0] = new LocalLBProfileULong();
+                            cookieTimeout[0].setValue(timeout);
+                            _persistenceProfileApi.set_cookie_expiration(profileNames, cookieTimeout);
+                        }
+                    }
+                }
+            } else {
+                _virtualServerApi.remove_all_persistence_profiles(genStringArray(virtualServerName));
+            }
+
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private void deleteVirtualServerAndDefaultPool(String virtualServerName) throws ExecutionException {
+		try {
+			if (virtualServerExists(virtualServerName)) {
+				// Delete the default pool's members
+				List<String> poolMembers = getMembers(virtualServerName);
+				for (String poolMember : poolMembers) {
+					String[] destIpAndPort = getIpAndPort(poolMember);
+					deletePoolMember(virtualServerName, destIpAndPort[0], Integer.valueOf(destIpAndPort[1]));
+				}
+
+				// Delete the virtual server
+				s_logger.debug("Deleting virtual server " + virtualServerName);
+				_virtualServerApi.delete_virtual_server(genStringArray(virtualServerName));
+
+				if (getVirtualServers().contains(virtualServerName)) {
+					throw new ExecutionException("Failed to delete virtual server " + virtualServerName);
+				}	
+
+				// Delete the default pool
+				deletePool(virtualServerName);	
+			}
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private String genVirtualServerName(LbProtocol protocol, String srcIp, long srcPort) {
+		srcIp = stripRouteDomainFromAddress(srcIp);
+		return genObjectName("vs", protocol, srcIp, srcPort);
+	}
+	
+	private boolean virtualServerExists(String virtualServerName) throws ExecutionException {
+		return getVirtualServers().contains(virtualServerName);
+	}
+	
+	private List<String> getVirtualServers() throws ExecutionException {
+		try {
+			List<String> virtualServers = new ArrayList<String>();
+			String[] virtualServersArray = _virtualServerApi.get_list();
+
+			for (String virtualServer : virtualServersArray) {
+				virtualServers.add(virtualServer);
+			}
+
+			return virtualServers;
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+
+    private boolean persistenceProfileExists(String profileName) throws ExecutionException {
+        try {
+            String[] persistenceProfileArray = _persistenceProfileApi.get_list();
+            if (persistenceProfileArray == null) {
+                return false;
+            }
+            for (String profile: persistenceProfileArray) {
+                if (profile.equalsIgnoreCase(profileName)) {
+                    return true;
+                }
+            }
+            return false;
+        } catch (RemoteException e) {
+            throw new ExecutionException(e.getMessage());
+        }
+    }
+
+	private iControl.CommonVirtualServerDefinition[] genVirtualServerDefinition(String name, LbProtocol protocol, String srcIp, long srcPort) {
+		CommonVirtualServerDefinition vsDefs[] = {new CommonVirtualServerDefinition()};
+		vsDefs[0].setName(name);
+        vsDefs[0].setAddress(srcIp);
+        vsDefs[0].setPort(srcPort);
+        
+        if (protocol.equals(LbProtocol.tcp)) {
+        	vsDefs[0].setProtocol(iControl.CommonProtocolType.PROTOCOL_TCP);
+        } else if (protocol.equals(LbProtocol.udp)) {
+        	vsDefs[0].setProtocol(iControl.CommonProtocolType.PROTOCOL_UDP);
+        }
+        
+		return vsDefs;
+	}
+	
+	private iControl.LocalLBVirtualServerVirtualServerResource[] genVirtualServerResource(String poolName) {
+		LocalLBVirtualServerVirtualServerResource vsRes[] = {new LocalLBVirtualServerVirtualServerResource()};
+		vsRes[0].setType(LocalLBVirtualServerVirtualServerType.RESOURCE_TYPE_POOL);
+        vsRes[0].setDefault_pool_name(poolName);
+		return vsRes;
+	}
+	
+	private LocalLBVirtualServerVirtualServerProfile[][] genVirtualServerProfile(LbProtocol protocol) {
+		LocalLBVirtualServerVirtualServerProfile vsProfs[][] = {{new LocalLBVirtualServerVirtualServerProfile()}};	
+		vsProfs[0][0].setProfile_context(LocalLBProfileContextType.PROFILE_CONTEXT_TYPE_ALL);		
+		
+		if (protocol.equals(LbProtocol.tcp)) {					
+			vsProfs[0][0].setProfile_name("http");
+		} else if (protocol.equals(LbProtocol.udp)) {
+			vsProfs[0][0].setProfile_name("udp");
+		}
+		
+		return vsProfs;
+	}
+	
+	private LocalLBVirtualServerVirtualServerPersistence[][] genPersistenceProfile(String persistenceProfileName) {
+		LocalLBVirtualServerVirtualServerPersistence[][] persistenceProfs = {{new LocalLBVirtualServerVirtualServerPersistence()}};
+		persistenceProfs[0][0].setDefault_profile(true);
+		persistenceProfs[0][0].setProfile_name(persistenceProfileName);
+		return persistenceProfs;
+	}			
+	
+	// Load balancing pool methods
+	
+	private void addPool(String virtualServerName, LbAlgorithm algorithm) throws ExecutionException {
+		try {
+			if (!poolExists(virtualServerName)) {
+				if (algorithm.getPersistenceProfileName() != null) {
+					algorithm = LbAlgorithm.RoundRobin;
+				}
+
+				s_logger.debug("Adding pool for virtual server " + virtualServerName + " with algorithm " + algorithm);
+				_loadbalancerApi.create(genStringArray(virtualServerName), genLbMethod(algorithm), genEmptyMembersArray());
+
+				if (!poolExists(virtualServerName)) {
+					throw new ExecutionException("Failed to create new pool for virtual server " + virtualServerName);
+				}							
+			}
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private void deletePool(String virtualServerName) throws ExecutionException {
+		try {
+			if (poolExists(virtualServerName) && getMembers(virtualServerName).size() == 0) {
+				s_logger.debug("Deleting pool for virtual server " + virtualServerName);
+				_loadbalancerApi.delete_pool(genStringArray(virtualServerName));
+				
+				if (poolExists(virtualServerName)) {
+					throw new ExecutionException("Failed to delete pool for virtual server " + virtualServerName);
+				}
+			}
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}	
+	
+	private void addPoolMember(String virtualServerName, String destIp, int destPort) throws ExecutionException {
+		try {
+			String memberIdentifier = destIp + "-" + destPort;			
+
+			if (poolExists(virtualServerName) && !memberExists(virtualServerName, memberIdentifier)) {
+				s_logger.debug("Adding member " + memberIdentifier + " into pool for virtual server " + virtualServerName);
+				_loadbalancerApi.add_member(genStringArray(virtualServerName), genMembers(destIp, destPort));
+
+				if (!memberExists(virtualServerName, memberIdentifier)) {
+					throw new ExecutionException("Failed to add new member " + memberIdentifier + " into pool for virtual server " + virtualServerName);
+				}
+			}
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private void deleteInactivePoolMembers(String virtualServerName, List<String> activePoolMembers) throws ExecutionException {
+		List<String> allPoolMembers = getMembers(virtualServerName);
+		
+		for (String member : allPoolMembers) {
+			if (!activePoolMembers.contains(member)) {
+				String[] ipAndPort = member.split("-");
+				deletePoolMember(virtualServerName, ipAndPort[0], Integer.valueOf(ipAndPort[1]));
+			}
+		}
+	}
+	
+	private void deletePoolMember(String virtualServerName, String destIp, int destPort) throws ExecutionException {
+		try {
+			String memberIdentifier = destIp + "-" + destPort;			
+			List<String> lbPools = getAllLbPools();
+
+			if (lbPools.contains(virtualServerName) && memberExists(virtualServerName, memberIdentifier)) {
+				s_logger.debug("Deleting member "  + memberIdentifier + " from pool for virtual server " + virtualServerName);
+				_loadbalancerApi.remove_member(genStringArray(virtualServerName), genMembers(destIp, destPort));
+
+				if (memberExists(virtualServerName, memberIdentifier)) {
+					throw new ExecutionException("Failed to delete member " + memberIdentifier + " from pool for virtual server " + virtualServerName);
+				}
+
+				if (nodeExists(destIp)) {
+					boolean nodeNeeded = false;
+					done:
+						for (String poolToCheck : lbPools) {
+							for (String memberInPool : getMembers(poolToCheck)) {
+								if (getIpAndPort(memberInPool)[0].equals(destIp)) {
+									nodeNeeded = true;
+									break done;
+								}
+							}		
+						}						
+
+					if (!nodeNeeded) {
+						s_logger.debug("Deleting node " + destIp);
+						_nodeApi.delete_node_address(genStringArray(destIp));
+
+						if (nodeExists(destIp)) {
+							throw new ExecutionException("Failed to delete node " + destIp);
+						}
+					}
+				}
+			}			
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private boolean poolExists(String poolName) throws ExecutionException {
+		return getAllLbPools().contains(poolName);
+	}
+	
+	private boolean memberExists(String poolName, String memberIdentifier) throws ExecutionException {
+		return getMembers(poolName).contains(memberIdentifier);
+	}
+	
+	private boolean nodeExists(String destIp) throws RemoteException {
+		return getNodes().contains(destIp);
+	}
+	
+	private String[] getIpAndPort(String memberIdentifier) {
+		return memberIdentifier.split("-");
+	}
+	
+	public List<String> getAllLbPools() throws ExecutionException {
+		try {
+			List<String> lbPools = new ArrayList<String>();
+			String[] pools = _loadbalancerApi.get_list();
+
+			for (String pool : pools) {
+				lbPools.add(pool);
+			}
+
+			return lbPools;
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private List<String> getMembers(String virtualServerName) throws ExecutionException {
+		try {
+			List<String> members = new ArrayList<String>();
+			String[] virtualServerNames = genStringArray(virtualServerName);
+			CommonIPPortDefinition[] membersArray = _loadbalancerApi.get_member(virtualServerNames)[0];
+
+			for (CommonIPPortDefinition member : membersArray) {
+				members.add(member.getAddress() + "-" + member.getPort());
+			}
+
+			return members;
+		} catch (RemoteException e) {
+			throw new ExecutionException(e.getMessage());
+		}
+	}
+	
+	private List<String> getNodes() throws RemoteException {
+		List<String> nodes = new ArrayList<String>();
+		String[] nodesArray = _nodeApi.get_list();
+		
+		for (String node : nodesArray) {
+			nodes.add(node);		
+		}
+		
+		return nodes;
+	}
+	
+	private iControl.CommonIPPortDefinition[][] genMembers(String destIp, long destPort) {
+		iControl.CommonIPPortDefinition[] membersInnerArray = new iControl.CommonIPPortDefinition[1];
+		membersInnerArray[0] = new iControl.CommonIPPortDefinition(destIp, destPort);
+		return new iControl.CommonIPPortDefinition[][]{membersInnerArray};
+	}
+	
+	private iControl.CommonIPPortDefinition[][] genEmptyMembersArray() {
+		iControl.CommonIPPortDefinition[] membersInnerArray = new iControl.CommonIPPortDefinition[0];
+		return new iControl.CommonIPPortDefinition[][]{membersInnerArray};
+	}
+	
+	private LocalLBLBMethod[] genLbMethod(LbAlgorithm algorithm) {
+		if (algorithm.getMethod() != null) {
+			return new LocalLBLBMethod[]{algorithm.getMethod()};
+		} else {
+			return new LocalLBLBMethod[]{LbAlgorithm.RoundRobin.getMethod()};
+		}
+	}
+	
+	// Stats methods
+	
+	private ExternalNetworkResourceUsageAnswer getIpBytesSentAndReceived(ExternalNetworkResourceUsageCommand cmd) throws ExecutionException {
+		ExternalNetworkResourceUsageAnswer answer = new ExternalNetworkResourceUsageAnswer(cmd);
+		
+		try {
+			
+			LocalLBVirtualServerVirtualServerStatistics stats = _virtualServerApi.get_all_statistics();
+			for (LocalLBVirtualServerVirtualServerStatisticEntry entry : stats.getStatistics()) {
+				String virtualServerIp = entry.getVirtual_server().getAddress();
+				
+				if (_inline) {
+					virtualServerIp = stripRouteDomainFromAddress(virtualServerIp);
+				}
+				
+				long[] bytesSentAndReceived = answer.ipBytes.get(virtualServerIp);
+				
+				if (bytesSentAndReceived == null) {
+				    bytesSentAndReceived = new long[]{0, 0};
+				}
+								
+				for (CommonStatistic stat : entry.getStatistics()) {	
+					int index;
+					if (stat.getType().equals(CommonStatisticType.STATISTIC_CLIENT_SIDE_BYTES_OUT)) {		
+						// Add to the outgoing bytes
+						index = 0;
+					} else if (stat.getType().equals(CommonStatisticType.STATISTIC_CLIENT_SIDE_BYTES_IN)) {
+						// Add to the incoming bytes
+						index = 1;
+					} else {
+						continue;
+					}
+					
+					long high = stat.getValue().getHigh(); 
+					long low = stat.getValue().getLow(); 
+					long full = getFullUsage(high, low);
+					
+					
+					bytesSentAndReceived[index] += full;
+				}
+				
+				if (bytesSentAndReceived[0] >= 0 && bytesSentAndReceived[1] >= 0) {
+					answer.ipBytes.put(virtualServerIp, bytesSentAndReceived);			
+				}
+			}
+		} catch (Exception e) {
+			s_logger.error(e);
+			throw new ExecutionException(e.getMessage());
+		}
+		
+		return answer;
+	}
+	
+	private long getFullUsage(long high, long low) {
+		Double full; 
+		Double rollOver = new Double((double) 0x7fffffff); 
+		rollOver = new Double(rollOver.doubleValue() + 1.0); 
+		
+		if (high >= 0) { 
+			// shift left 32 bits and mask off new bits to 0's 
+			full = new Double((high << 32 & 0xffff0000)); 
+		} else {
+			// mask off sign bits + shift left by 32 bits then add the sign bit back
+			full = new Double(((high & 0x7fffffff) << 32) + (0x80000000 << 32)); 
+		}
+		
+		if (low >= 0) {
+			// add low to full and we're good
+			full = new Double(full.doubleValue() + (double) low); 
+		} else {
+			// add full to low after masking off sign bits and adding 1 to the masked off low order value
+			full = new Double(full.doubleValue() + (double) ((low & 0x7fffffff)) + rollOver.doubleValue()); 
+		}
+		
+		return full.longValue();
+	}
+
+	
+	
+	// Misc methods
+	
+	private String tagAddressWithRouteDomain(String address, long vlanTag) {
+		return address + _routeDomainIdentifier + vlanTag;
+	}
+	
+	private String stripRouteDomainFromAddress(String address) {
+		int i = address.indexOf(_routeDomainIdentifier);
+		
+		if (i > 0) {
+			address = address.substring(0, i);
+		}
+		
+		return address;
+	}
+	
+	private String genObjectName(Object... args) {
+		String objectName = "";
+		
+		for (int i = 0; i < args.length; i++) {
+			objectName += args[i];
+			if (i != args.length -1) {
+				objectName += _objectNamePathSep;
+			}
+		}
+		
+		return objectName;
+	}	
+	
+	private long[] genLongArray(long l) {
+		return new long[]{l};
+	}
+	
+	private static String[] genStringArray(String s) {
+		return new String[]{s};
+	}				
+
+}
+
+
+	
+	
+
+	  
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/422c4ce5/plugins/network-elements/netscaler/.classpath
----------------------------------------------------------------------
diff --git a/plugins/network-elements/netscaler/.classpath b/plugins/network-elements/netscaler/.classpath
index 1c573a6..a3f5d12 100644
--- a/plugins/network-elements/netscaler/.classpath
+++ b/plugins/network-elements/netscaler/.classpath
@@ -1,10 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="src"/>
-        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/api"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/core"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/server"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/utils"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/deps"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/422c4ce5/server/src/com/cloud/api/commands/AddExternalLoadBalancerCmd.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/commands/AddExternalLoadBalancerCmd.java b/server/src/com/cloud/api/commands/AddExternalLoadBalancerCmd.java
deleted file mode 100644
index a8208ae..0000000
--- a/server/src/com/cloud/api/commands/AddExternalLoadBalancerCmd.java
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2012 Citrix Systems, Inc. Licensed under the
-// Apache License, Version 2.0 (the "License"); you may not use this
-// file except in compliance with the License.  Citrix Systems, Inc.
-// reserves all rights not expressly granted by the License.
-// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// 
-// Automatically generated by addcopyright.py at 04/03/2012
-package com.cloud.api.commands;
-
-import org.apache.log4j.Logger;
-
-import com.cloud.api.ApiConstants;
-import com.cloud.api.BaseCmd;
-import com.cloud.api.IdentityMapper;
-import com.cloud.api.Implementation;
-import com.cloud.api.Parameter;
-import com.cloud.api.PlugService;
-import com.cloud.api.ServerApiException;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.host.Host;
-import com.cloud.network.element.F5ExternalLoadBalancerElementService;
-import com.cloud.server.api.response.ExternalLoadBalancerResponse;
-import com.cloud.user.Account;
-import com.cloud.utils.exception.CloudRuntimeException;
-
-@Implementation(description="Adds F5 external load balancer appliance.", responseObject = ExternalLoadBalancerResponse.class)
-@Deprecated // API supported only for backward compatibility.
-public class AddExternalLoadBalancerCmd extends BaseCmd {
-    public static final Logger s_logger = Logger.getLogger(AddExternalLoadBalancerCmd.class.getName());
-    private static final String s_name = "addexternalloadbalancerresponse";
-    
-    /////////////////////////////////////////////////////
-    //////////////// API parameters /////////////////////
-    /////////////////////////////////////////////////////
-	
-    @IdentityMapper(entityTableName="data_center")
-	@Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required = true, description="Zone in which to add the external load balancer appliance.")
-	private Long zoneId;
-
-    @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the external load balancer appliance.")
-    private String url;
-
-    @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Username of the external load balancer appliance.")
-    private String username;
-
-    @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Password of the external load balancer appliance.")
-    private String password;
-
-    ///////////////////////////////////////////////////
-    /////////////////// Accessors ///////////////////////
-    /////////////////////////////////////////////////////
-     
-    public Long getZoneId() {
-        return zoneId;
-    }
-    
-    public String getUrl() {
-        return url;
-    }
-    
-    public String getUsername() {
-        return username;
-    }
-    
-    public String getPassword() {
-        return password;
-    }
-
-    @PlugService
-    F5ExternalLoadBalancerElementService _f5DeviceManagerService;
-
-    /////////////////////////////////////////////////////
-    /////////////// API Implementation///////////////////
-    /////////////////////////////////////////////////////
-
-    @Override
-    public String getCommandName() {
-        return s_name;
-    }
-
-    @Override
-    public long getEntityOwnerId() {
-        return Account.ACCOUNT_ID_SYSTEM;
-    }
-
-    @Override
-    public void execute(){
-        try {
-            Host externalLoadBalancer = _f5DeviceManagerService.addExternalLoadBalancer(this);
-            ExternalLoadBalancerResponse response = _f5DeviceManagerService.createExternalLoadBalancerResponse(externalLoadBalancer);
-            response.setObjectName("externalloadbalancer");
-            response.setResponseName(getCommandName());
-            this.setResponseObject(response);
-        } catch (InvalidParameterValueException ipve) {
-            throw new ServerApiException(BaseCmd.PARAM_ERROR, ipve.getMessage());
-        } catch (CloudRuntimeException cre) {
-            throw new ServerApiException(BaseCmd.INTERNAL_ERROR, cre.getMessage());
-        }
-    }
-}
\ No newline at end of file