cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sate...@apache.org
Subject [cloudstack] 01/05: CLOUDSTACK-8672 : NCC Integration with CloudStack.
Date Thu, 20 Jul 2017 07:12:49 GMT
This is an automated email from the ASF dual-hosted git repository.

sateesh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 884606f77be7621944d2f315fd8eabe8884c45d9
Author: Rajesh Battala <rajesh.battala@citrix.com>
AuthorDate: Thu Jul 23 14:14:07 2015 +0530

    CLOUDSTACK-8672 : NCC Integration with CloudStack.
---
 api/src/com/cloud/event/EventTypes.java            |    9 +
 api/src/com/cloud/host/Host.java                   |    2 +-
 .../org/apache/cloudstack/api/ApiConstants.java    |    2 +
 .../api/NetScalerImplementNetworkCommand.java      |   65 +
 .../api/StartupExternalLoadBalancerCommand.java    |    3 +
 .../engine/orchestration/NetworkOrchestrator.java  |   18 +-
 .../schema/src/com/cloud/host/dao/HostDaoImpl.java |    2 +-
 plugins/network-elements/netscaler/pom.xml         |    5 +
 .../netscaler/spring-netscaler-context.xml         |    3 +-
 .../RegisterNetscalerControlCenterCmd.java         |  144 +
 .../api/commands/RegisterServicePackageCmd.java    |  107 +
 .../response/NetScalerServicePackageResponse.java  |   71 +
 .../cloud/network/NetScalerControlCenterVO.java    |  129 +
 .../cloud/network/NetScalerServicePackageVO.java   |  107 +
 .../network/dao/NetScalerControlCenterDao.java     |   15 +-
 .../network/dao/NetScalerControlCenterDaoImpl.java |   31 +-
 .../network/dao/NetScalerServicePackageDao.java    |   16 +-
 .../dao/NetScalerServicePackageDaoImpl.java        |   65 +
 .../cloud/network/element/NetscalerElement.java    |  329 +-
 .../NetscalerLoadBalancerElementService.java       |   20 +
 .../resource/NetScalerControlCenterResource.java   | 4026 ++++++++++++++++++++
 server/src/com/cloud/configuration/Config.java     |    9 +-
 .../ExternalLoadBalancerDeviceManagerImpl.java     |    7 +-
 server/src/com/cloud/server/StatsCollector.java    |    1 +
 setup/db/db/schema-4930to41000.sql                 |   25 +-
 25 files changed, 5170 insertions(+), 41 deletions(-)

diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index 3cc4eac..b46b352 100644
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -545,6 +545,11 @@ public class EventTypes {
     //Usage related events
     public static final String EVENT_USAGE_REMOVE_USAGE_RECORDS = "USAGE.REMOVE.USAGE.RECORDS";
 
+    // Netscaler Service Package events
+    public static final String EVENT_NETSCALER_SERVICEPACKAGE_ADD = "NETSCALER.SERVICEPACKAGE.ADD";
+    public static final String EVENT_NETSCALER_SERVICEPACKAGE_DELETE = "NETSCALER.SERVICEPACKAGE.DELETE";
+
+
     static {
 
         // TODO: need a way to force author adding event types to declare the entity details as well, with out braking
@@ -918,6 +923,10 @@ public class EventTypes {
 
         //Usage
         entityEventDetails.put(EVENT_USAGE_REMOVE_USAGE_RECORDS, Usage.class);
+        // Netscaler Service Packages
+        entityEventDetails.put(EVENT_NETSCALER_SERVICEPACKAGE_ADD, "NETSCALER.SERVICEPACKAGE.CREATE");
+        entityEventDetails.put(EVENT_NETSCALER_SERVICEPACKAGE_DELETE, "NETSCALER.SERVICEPACKAGE.DELETE");
+
     }
 
     public static String getEntityForEvent(String eventName) {
diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java
index 689ed12..3ed4f5e 100644
--- a/api/src/com/cloud/host/Host.java
+++ b/api/src/com/cloud/host/Host.java
@@ -31,7 +31,7 @@ import com.cloud.utils.fsm.StateObject;
 public interface Host extends StateObject<Status>, Identity, InternalIdentity {
     public enum Type {
         Storage(false), Routing(false), SecondaryStorage(false), SecondaryStorageCmdExecutor(false), ConsoleProxy(true), ExternalFirewall(false), ExternalLoadBalancer(
-                false), ExternalVirtualSwitchSupervisor(false), PxeServer(false), BaremetalPxe(false), BaremetalDhcp(false), TrafficMonitor(false),
+                false), ExternalVirtualSwitchSupervisor(false), PxeServer(false), BaremetalPxe(false), BaremetalDhcp(false), TrafficMonitor(false), NetScalerControlCenter(false),
 
         ExternalDhcp(false), SecondaryStorageVM(true), LocalSecondaryStorage(false), L2Networking(false);
         boolean _virtual;
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index a16a327..febbb0f 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -652,6 +652,8 @@ public class ApiConstants {
     public static final String OVM3_CLUSTER = "ovm3cluster";
     public static final String OVM3_VIP = "ovm3vip";
     public static final String CLEAN_UP_DETAILS = "cleanupdetails";
+    public static final String NETSCALER_CONTROLCENTER_ID = "netscalercontrolcenterid";
+    public static final String NETSCALER_SERVICEPACKAGE_ID = "netscalerservicepackageid";
 
     public static final String ZONE_ID_LIST = "zoneids";
     public static final String DESTINATION_ZONE_ID_LIST = "destzoneids";
diff --git a/core/src/com/cloud/agent/api/NetScalerImplementNetworkCommand.java b/core/src/com/cloud/agent/api/NetScalerImplementNetworkCommand.java
new file mode 100644
index 0000000..ea6afa1
--- /dev/null
+++ b/core/src/com/cloud/agent/api/NetScalerImplementNetworkCommand.java
@@ -0,0 +1,65 @@
+//
+// 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.agent.api;
+
+public class NetScalerImplementNetworkCommand extends Command {
+    private String _networkDetails;
+
+    public NetScalerImplementNetworkCommand() {
+        super();
+    }
+
+    private Long dcId;
+    private Long hostId;
+
+    public NetScalerImplementNetworkCommand(Long dcId) {
+        super();
+        this.dcId = dcId;
+    }
+
+    public NetScalerImplementNetworkCommand(Long dcId, Long hostId, String networkDetails) {
+        this(dcId);
+        this.hostId = hostId;
+        this._networkDetails = networkDetails;
+    }
+
+    public void setDetails(String details) {
+        _networkDetails = details;
+    }
+
+    public String getDetails() {
+        return _networkDetails;
+    }
+
+    public Long getDataCenterId() {
+        return dcId;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        //TODO checkout whether we need to mark it true ??
+        //Marking it true is causing another guest network execution in queue
+        return false;
+    }
+
+    public Long getHostId() {
+        return hostId;
+    }
+}
diff --git a/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java b/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
index 50187b2..698988e 100644
--- a/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
+++ b/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
@@ -26,4 +26,7 @@ public class StartupExternalLoadBalancerCommand extends StartupCommand {
         super(Host.Type.ExternalLoadBalancer);
     }
 
+    public StartupExternalLoadBalancerCommand(Host.Type type) {
+        super(type);
+    }
 }
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index 37f5330..7f43b52 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -442,7 +442,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                 if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) {
                     offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true,
                             Availability.Optional, null, new HashMap<Network.Service, Set<Network.Provider>>(), true, Network.GuestType.Shared, false, null, true, null, true,
-                            false, null, false, null, true);
+                            false, null, false, null, true, null);
                     offering.setState(NetworkOffering.State.Enabled);
                     _networkOfferingDao.update(offering.getId(), offering);
                 }
@@ -451,7 +451,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                 if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) {
                     offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks",
                             TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true,
-                            null, true, false, null, false, null, true);
+                            null, true, false, null, false, null, true, null);
                     offering.setState(NetworkOffering.State.Enabled);
                     _networkOfferingDao.update(offering.getId(), offering);
                 }
@@ -460,7 +460,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                 if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) {
                     offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true,
                             Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false,
-                            null, true);
+                            null, true, null);
                     offering.setState(NetworkOffering.State.Enabled);
                     _networkOfferingDao.update(offering.getId(), offering);
                 }
@@ -470,7 +470,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                     offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService,
                             "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null,
                             defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null,
-                            true);
+                            true, null);
 
                     offering.setState(NetworkOffering.State.Enabled);
                     _networkOfferingDao.update(offering.getId(), offering);
@@ -480,7 +480,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                 if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) {
                     offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks,
                             "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null,
-                            defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true);
+                            defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, null);
                     offering.setState(NetworkOffering.State.Enabled);
                     _networkOfferingDao.update(offering.getId(), offering);
                 }
@@ -491,7 +491,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                     defaultVPCOffProviders.remove(Service.Lb);
                     offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB,
                             "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional,
-                            null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true);
+                            null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, null);
                     offering.setState(NetworkOffering.State.Enabled);
                     _networkOfferingDao.update(offering.getId(), offering);
                 }
@@ -500,7 +500,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                 if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) {
                     offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service",
                             TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null,
-                            true, null, true, false, null, false, null, true);
+                            true, null, true, false, null, false, null, true, null);
                     offering.setState(NetworkOffering.State.Enabled);
                     _networkOfferingDao.update(offering.getId(), offering);
                 }
@@ -524,7 +524,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                 if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) {
                     offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB,
                             "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest, null, false, Availability.Optional, null, internalLbOffProviders,
-                            true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true);
+                            true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, null);
                     offering.setState(NetworkOffering.State.Enabled);
                     offering.setInternalLb(true);
                     offering.setPublicLb(false);
@@ -556,7 +556,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                 if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) {
                     offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering,
                             "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null,
-                            netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true);
+                            netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, null);
                     offering.setState(NetworkOffering.State.Enabled);
                     offering.setDedicatedLB(false);
                     _networkOfferingDao.update(offering.getId(), offering);
diff --git a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java
index a74b908..f12a628 100644
--- a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java
+++ b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java
@@ -642,7 +642,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
         SearchCriteria<HostVO> sc = UnmanagedApplianceSearch.create();
         sc.setParameters("lastPinged", lastPingSecondsAfter);
         sc.setParameters("types", Type.ExternalDhcp, Type.ExternalFirewall, Type.ExternalLoadBalancer, Type.BaremetalDhcp, Type.BaremetalPxe, Type.TrafficMonitor,
-            Type.L2Networking);
+            Type.L2Networking, Type.NetScalerControlCenter);
         List<HostVO> hosts = lockRows(sc, null, true);
 
         for (HostVO host : hosts) {
diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml
index 9076687..a8a7eb1 100644
--- a/plugins/network-elements/netscaler/pom.xml
+++ b/plugins/network-elements/netscaler/pom.xml
@@ -37,5 +37,10 @@
       <artifactId>sdx_nitro</artifactId>
       <version>${cs.nitro.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.json</groupId>
+      <artifactId>json</artifactId>
+      <version>20090211</version>
+    </dependency>
   </dependencies>
 </project>
diff --git a/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/spring-netscaler-context.xml b/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/spring-netscaler-context.xml
index a75db6b..5727304 100644
--- a/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/spring-netscaler-context.xml
+++ b/plugins/network-elements/netscaler/resources/META-INF/cloudstack/netscaler/spring-netscaler-context.xml
@@ -26,7 +26,8 @@
                       http://www.springframework.org/schema/context
                       http://www.springframework.org/schema/context/spring-context.xsd"
                       >
-
+    <bean id="netScalerServicePackageDaoImpl" class="com.cloud.network.dao.NetScalerServicePackageDaoImpl" />
+    <bean id="netScalerControlCenterDaoImpl" class="com.cloud.network.dao.NetScalerControlCenterDaoImpl" />
     <bean id="netScalerPodDaoImpl" class="com.cloud.network.dao.NetScalerPodDaoImpl" />
     <bean id="netscalerElement" class="com.cloud.network.element.NetscalerElement" >
         <property name="name" value="Netscaler"/>
diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/commands/RegisterNetscalerControlCenterCmd.java b/plugins/network-elements/netscaler/src/com/cloud/api/commands/RegisterNetscalerControlCenterCmd.java
new file mode 100644
index 0000000..8887736
--- /dev/null
+++ b/plugins/network-elements/netscaler/src/com/cloud/api/commands/RegisterNetscalerControlCenterCmd.java
@@ -0,0 +1,144 @@
+// 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.commands;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.api.response.NetscalerLoadBalancerResponse;
+import com.cloud.event.EventTypes;
+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.NetScalerControlCenterVO;
+import com.cloud.network.element.NetscalerLoadBalancerElementService;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "registerNetscalerControlCenter", responseObject = NetscalerLoadBalancerResponse.class, description = "Adds a netscaler control center device",
+        requestHasSensitiveInfo = true, responseHasSensitiveInfo = false)
+public class RegisterNetscalerControlCenterCmd extends BaseAsyncCmd {
+
+    public static final Logger s_logger = Logger.getLogger(RegisterNetscalerControlCenterCmd.class.getName());
+    private static final String s_name = "registernetscalercontrolcenterrresponse";
+    @Inject
+    NetscalerLoadBalancerElementService _netsclarLbService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.IP_ADDRESS , type = CommandType.STRING, required = true, description = "URL of the netscaler controlcenter appliance.")
+    private String ipaddress;
+
+    @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "Credentials to reach netscaler controlcenter device")
+    private String username;
+
+    @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = true, description = "Credentials to reach netscaler controlcenter  device")
+    private String password;
+
+    @Parameter(name = ApiConstants.NUM_RETRIES , type = CommandType.INTEGER, required = true, description = "Credentials to reach netscaler controlcenter device")
+    private int numretries;
+
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+
+    public static Logger getsLogger() {
+        return s_logger;
+    }
+
+    public static String getsName() {
+        return s_name;
+    }
+
+    public NetscalerLoadBalancerElementService get_netsclarLbService() {
+        return _netsclarLbService;
+    }
+
+    public String getIpaddress() {
+        return ipaddress;
+    }
+
+    public int getNumretries() {
+        return numretries;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
+        ResourceAllocationException {
+        try {
+            NetScalerControlCenterVO nccVO = _netsclarLbService.registerNetscalerControlCenter(this);
+            if (nccVO != null) {
+                /*NetscalerLoadBalancerResponse response = _netsclarLbService.createNetscalerLoadBalancerResponse(lbDeviceVO);
+                response.setObjectName("netscalerloadbalancer");
+                response.setResponseName(getCommandName());
+                this.setResponseObject(response);*/
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add netscaler load balancer due to internal error.");
+            }
+        } catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage());
+        }
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Adding a netscaler load balancer device";
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_EXTERNAL_LB_DEVICE_ADD;
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccount().getId();
+    }
+}
\ No newline at end of file
diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/commands/RegisterServicePackageCmd.java b/plugins/network-elements/netscaler/src/com/cloud/api/commands/RegisterServicePackageCmd.java
new file mode 100644
index 0000000..52e8e5a
--- /dev/null
+++ b/plugins/network-elements/netscaler/src/com/cloud/api/commands/RegisterServicePackageCmd.java
@@ -0,0 +1,107 @@
+//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.commands;
+
+import javax.inject.Inject;
+import javax.persistence.EntityExistsException;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.api.response.NetScalerServicePackageResponse;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.network.element.NetscalerLoadBalancerElementService;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "registerNetscalerServicePackage", responseObject = NetScalerServicePackageResponse.class,
+    description = "Registers NCC Service Package")
+public class RegisterServicePackageCmd extends BaseCmd {
+
+    public static final Logger s_logger = Logger.getLogger(RegisterServicePackageCmd.class.getName());
+    private static final String s_name = "registerNetscalerServicePackage";
+
+    @Inject
+    NetscalerLoadBalancerElementService _netsclarLbService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Name of the service Package.")
+    private String spName;
+
+    @Parameter(name = ApiConstants.DESCRIPTION , type = CommandType.STRING, required = true, description = "Description of Service Package")
+    private String description;
+
+/*    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_NETSCALER_SERVICEPACKAGE_ADD;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Adding Netscaler Service Package";
+    }
+*/
+    @Override
+    public void execute() throws ServerApiException, ConcurrentOperationException, EntityExistsException {
+        try {
+            NetScalerServicePackageResponse response =  _netsclarLbService.registerNetscalerServicePackage(this);
+
+            if (response != null) {
+                //NetScalerServicePackageResponse response = _netsclarLbService.createNetscalerServicePackageResponse(servicePackageVO);
+                response.setObjectName("netscalerservicepackage");
+                response.setResponseName(getCommandName());
+                this.setResponseObject(response);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Service Package due to internal error.");
+            }
+        } catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage());
+        } catch (EntityExistsException runtimeExcp) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR , "Service Pacakge Already Exists with Name " + getSpName() );
+        }
+
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccount().getId();
+    }
+
+    public String getSpName() {
+        return spName;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/response/NetScalerServicePackageResponse.java b/plugins/network-elements/netscaler/src/com/cloud/api/response/NetScalerServicePackageResponse.java
new file mode 100644
index 0000000..4950875
--- /dev/null
+++ b/plugins/network-elements/netscaler/src/com/cloud/api/response/NetScalerServicePackageResponse.java
@@ -0,0 +1,71 @@
+// 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.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.network.NetScalerServicePackageVO;
+import com.cloud.serializer.Param;
+
+public class NetScalerServicePackageResponse extends BaseResponse {
+    @SerializedName(ApiConstants.ID)
+    @Param(description = "Service Package UUID")
+    private String id;
+
+    @SerializedName(ApiConstants.NAME)
+    @Param(description = "Service Package Name")
+    private String name;
+
+    @SerializedName(ApiConstants.DESCRIPTION)
+    @Param(description = "Description of Service Package")
+    private String description;
+
+    public NetScalerServicePackageResponse() {}
+
+    public NetScalerServicePackageResponse(NetScalerServicePackageVO servicePackage) {
+        this.id = servicePackage.getUuid();
+        this.name = servicePackage.getName();
+        this.description = servicePackage.getDescription();
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+}
diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/NetScalerControlCenterVO.java b/plugins/network-elements/netscaler/src/com/cloud/network/NetScalerControlCenterVO.java
new file mode 100644
index 0000000..e1cd13d
--- /dev/null
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/NetScalerControlCenterVO.java
@@ -0,0 +1,129 @@
+// 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.network;
+
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+
+/**
+ * NetScalerPodVO contains information about a EIP deployment where on datacenter L3 router a PBR (policy
+ * based routing) is setup between a POD's subnet IP range to a NetScaler device. This VO object
+ * represents a mapping between a POD and NetScaler device where PBR is setup.
+ *
+ */
+@Entity
+@Table(name = "external_netscaler_controlcenter")
+public class NetScalerControlCenterVO implements InternalIdentity {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private long id;
+
+    @Column(name = "username")
+    private String username;
+
+    @Column(name = "password")
+    private String password;
+
+    @Column(name = "uuid")
+    private String uuid;
+
+    @Column(name = "ncc_ip")
+    private String nccip;
+
+    @Column(name = "num_retries")
+    private int numRetries;
+
+    public NetScalerControlCenterVO() {
+    }
+
+    public NetScalerControlCenterVO(long hostId, String username, String password, String nccip, int retries) {
+        this.username = username;
+        this.password = password;
+        this.uuid = UUID.randomUUID().toString();
+        this.nccip = nccip;
+        this.numRetries = retries;
+    }
+    public NetScalerControlCenterVO(String username, String password, String nccip, int retries) {
+        this.username = username;
+        this.password = password;
+        this.uuid = UUID.randomUUID().toString();
+        this.nccip = nccip;
+        this.numRetries = retries;
+    }
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public String getNccip() {
+        return nccip;
+    }
+
+    public void setNccip(String nccip) {
+        this.nccip = nccip;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public int getNumRetries() {
+        return numRetries;
+    }
+
+    public void setNumRetries(int numRetries) {
+        this.numRetries = numRetries;
+    }
+
+    @Override
+    public long getId() {
+        // TODO Auto-generated method stub
+        return id;
+    }
+
+}
diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/NetScalerServicePackageVO.java b/plugins/network-elements/netscaler/src/com/cloud/network/NetScalerServicePackageVO.java
new file mode 100644
index 0000000..758d5a3
--- /dev/null
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/NetScalerServicePackageVO.java
@@ -0,0 +1,107 @@
+// 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.network;
+
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import com.cloud.api.commands.RegisterServicePackageCmd;
+
+/**
+ * NetScalerPodVO contains information about a EIP deployment where on datacenter L3 router a PBR (policy
+ * based routing) is setup between a POD's subnet IP range to a NetScaler device. This VO object
+ * represents a mapping between a POD and NetScaler device where PBR is setup.
+ *
+ */
+@Entity
+@Table(name = " netscaler_servicepackages")
+public class NetScalerServicePackageVO implements InternalIdentity {
+
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private long id;
+
+    @Column(name = "name")
+    private String name;
+
+    @Column(name = "description")
+    private String description;
+
+    @Column(name = "uuid")
+    private String uuid;
+
+    public NetScalerServicePackageVO() {
+
+    }
+
+
+    public NetScalerServicePackageVO(RegisterServicePackageCmd cmd) {
+        this.name = cmd.getSpName();
+        this.description = cmd.getDescription();
+        this.uuid = UUID.randomUUID().toString();
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    public String getDescription() {
+        return description;
+    }
+
+
+    public String getUuid() {
+        return uuid;
+    }
+
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+}
diff --git a/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java b/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerControlCenterDao.java
similarity index 68%
copy from core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
copy to plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerControlCenterDao.java
index 50187b2..acf8dce 100644
--- a/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerControlCenterDao.java
@@ -1,4 +1,3 @@
-//
 // 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
@@ -15,15 +14,15 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
+package com.cloud.network.dao;
 
-package com.cloud.agent.api;
+import java.util.List;
 
-import com.cloud.host.Host;
+import com.cloud.network.NetScalerControlCenterVO;
+import com.cloud.utils.db.GenericDao;
 
-public class StartupExternalLoadBalancerCommand extends StartupCommand {
-    public StartupExternalLoadBalancerCommand() {
-        super(Host.Type.ExternalLoadBalancer);
-    }
+public interface NetScalerControlCenterDao extends GenericDao<NetScalerControlCenterVO, Long> {
 
+    NetScalerControlCenterVO findByPodId(long podId);
+    List<NetScalerControlCenterVO> listByNetScalerDeviceId(long netscalerDeviceId);
 }
diff --git a/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java b/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerControlCenterDaoImpl.java
similarity index 51%
copy from core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
copy to plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerControlCenterDaoImpl.java
index 50187b2..ec24842 100644
--- a/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerControlCenterDaoImpl.java
@@ -1,4 +1,3 @@
-//
 // 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
@@ -15,15 +14,33 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
+package com.cloud.network.dao;
+
+import java.util.List;
+
+import javax.ejb.Local;
 
-package com.cloud.agent.api;
+import org.springframework.stereotype.Component;
 
-import com.cloud.host.Host;
+import com.cloud.network.NetScalerControlCenterVO;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.GenericDaoBase;
+
+@Component
+@Local(value = NetScalerControlCenterDao.class)
+@DB
+public class NetScalerControlCenterDaoImpl extends GenericDaoBase<NetScalerControlCenterVO, Long> implements NetScalerControlCenterDao {
+
+    @Override
+    public NetScalerControlCenterVO findByPodId(long podId) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 
-public class StartupExternalLoadBalancerCommand extends StartupCommand {
-    public StartupExternalLoadBalancerCommand() {
-        super(Host.Type.ExternalLoadBalancer);
+    @Override
+    public List<NetScalerControlCenterVO> listByNetScalerDeviceId(long netscalerDeviceId) {
+        // TODO Auto-generated method stub
+        return null;
     }
 
 }
diff --git a/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java b/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerServicePackageDao.java
similarity index 67%
copy from core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
copy to plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerServicePackageDao.java
index 50187b2..fcda584 100644
--- a/core/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerServicePackageDao.java
@@ -1,4 +1,3 @@
-//
 // 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
@@ -15,15 +14,16 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
+package com.cloud.network.dao;
+
+import java.util.List;
 
-package com.cloud.agent.api;
+import com.cloud.network.NetScalerServicePackageVO;
+import com.cloud.utils.db.GenericDao;
 
-import com.cloud.host.Host;
+public interface NetScalerServicePackageDao extends GenericDao<NetScalerServicePackageVO, Long> {
 
-public class StartupExternalLoadBalancerCommand extends StartupCommand {
-    public StartupExternalLoadBalancerCommand() {
-        super(Host.Type.ExternalLoadBalancer);
-    }
+    NetScalerServicePackageVO findByPodId(long podId);
 
+    List<NetScalerServicePackageVO> listByNetScalerDeviceId(long netscalerDeviceId);
 }
diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerServicePackageDaoImpl.java b/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerServicePackageDaoImpl.java
new file mode 100644
index 0000000..df99b49
--- /dev/null
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/dao/NetScalerServicePackageDaoImpl.java
@@ -0,0 +1,65 @@
+// 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.network.dao;
+
+import java.util.List;
+
+import javax.ejb.Local;
+
+import org.springframework.stereotype.Component;
+
+import com.cloud.network.NetScalerServicePackageVO;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@Component
+@Local(value = NetScalerServicePackageDao.class)
+@DB
+public class NetScalerServicePackageDaoImpl extends GenericDaoBase<NetScalerServicePackageVO, Long> implements NetScalerServicePackageDao {
+
+    final SearchBuilder<NetScalerServicePackageVO> podIdSearch;
+    final SearchBuilder<NetScalerServicePackageVO> deviceIdSearch;
+
+    protected NetScalerServicePackageDaoImpl() {
+        super();
+
+        podIdSearch = createSearchBuilder();
+        //podIdSearch.and("pod_id", podIdSearch.entity().getPodId(), Op.EQ);
+        podIdSearch.done();
+
+        deviceIdSearch = createSearchBuilder();
+        //deviceIdSearch.and("netscalerDeviceId", deviceIdSearch.entity().getNetscalerDeviceId(), Op.EQ);
+        deviceIdSearch.done();
+    }
+
+    @Override
+    public NetScalerServicePackageVO findByPodId(long podId) {
+        SearchCriteria<NetScalerServicePackageVO> sc = podIdSearch.create();
+        sc.setParameters("pod_id", podId);
+        return findOneBy(sc);
+    }
+
+    @Override
+    public List<NetScalerServicePackageVO> listByNetScalerDeviceId(long netscalerDeviceId) {
+        SearchCriteria<NetScalerServicePackageVO> sc = deviceIdSearch.create();
+        sc.setParameters("netscalerDeviceId", netscalerDeviceId);
+        return search(sc, null);
+    }
+
+}
diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java
index dbf6d9a..60baa89 100644
--- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java
@@ -23,20 +23,26 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
 import javax.inject.Inject;
+import javax.naming.ConfigurationException;
 
 import org.apache.log4j.Logger;
+import org.json.JSONException;
+import org.json.JSONObject;
 
 import com.google.gson.Gson;
 
 import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice;
 import org.apache.cloudstack.region.gslb.GslbServiceProvider;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.NetScalerImplementNetworkCommand;
 import com.cloud.agent.api.routing.GlobalLoadBalancerConfigCommand;
 import com.cloud.agent.api.routing.HealthCheckLBConfigAnswer;
 import com.cloud.agent.api.routing.HealthCheckLBConfigCommand;
@@ -51,12 +57,16 @@ import com.cloud.api.commands.ConfigureNetscalerLoadBalancerCmd;
 import com.cloud.api.commands.DeleteNetscalerLoadBalancerCmd;
 import com.cloud.api.commands.ListNetscalerLoadBalancerNetworksCmd;
 import com.cloud.api.commands.ListNetscalerLoadBalancersCmd;
+import com.cloud.api.commands.RegisterNetscalerControlCenterCmd;
+import com.cloud.api.commands.RegisterServicePackageCmd;
+import com.cloud.api.response.NetScalerServicePackageResponse;
 import com.cloud.api.response.NetscalerLoadBalancerResponse;
 import com.cloud.configuration.Config;
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.dc.DataCenterIpAddressVO;
+import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.HostPodVO;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.DataCenterIpAddressDao;
@@ -67,13 +77,17 @@ import com.cloud.exception.InsufficientNetworkCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.host.Host;
+import com.cloud.host.Host.Type;
 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.IpAddress;
+import com.cloud.network.IpAddressManager;
+import com.cloud.network.NetScalerControlCenterVO;
 import com.cloud.network.NetScalerPodVO;
+import com.cloud.network.NetScalerServicePackageVO;
 import com.cloud.network.Network;
 import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.Provider;
@@ -88,7 +102,9 @@ import com.cloud.network.as.AutoScaleCounter.AutoScaleCounterType;
 import com.cloud.network.dao.ExternalLoadBalancerDeviceDao;
 import com.cloud.network.dao.ExternalLoadBalancerDeviceVO;
 import com.cloud.network.dao.ExternalLoadBalancerDeviceVO.LBDeviceState;
+import com.cloud.network.dao.NetScalerControlCenterDao;
 import com.cloud.network.dao.NetScalerPodDao;
+import com.cloud.network.dao.NetScalerServicePackageDao;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkExternalLoadBalancerDao;
 import com.cloud.network.dao.NetworkExternalLoadBalancerVO;
@@ -98,6 +114,7 @@ import com.cloud.network.dao.PhysicalNetworkDao;
 import com.cloud.network.dao.PhysicalNetworkVO;
 import com.cloud.network.lb.LoadBalancingRule;
 import com.cloud.network.lb.LoadBalancingRule.LbDestination;
+import com.cloud.network.resource.NetScalerControlCenterResource;
 import com.cloud.network.resource.NetscalerResource;
 import com.cloud.network.rules.FirewallRule;
 import com.cloud.network.rules.LbStickinessMethod;
@@ -105,9 +122,13 @@ import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType;
 import com.cloud.network.rules.LoadBalancerContainer;
 import com.cloud.network.rules.StaticNat;
 import com.cloud.offering.NetworkOffering;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ServerResource;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
 import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
@@ -155,9 +176,25 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl
     DataCenterIpAddressDao _privateIpAddressDao;
     @Inject
     ExternalLoadBalancerDeviceDao _externalLoadBalancerDeviceDao;
+    @Inject
+    NetScalerServicePackageDao _netscalerServicePackageDao;
+    @Inject
+    NetScalerControlCenterDao _netscalerControlCenterDao;
+    @Inject
+    ResourceManager _resourceMgr;
+    @Inject
+    HostDetailsDao _hostDetailDao;
+    @Inject
+    IpAddressManager _ipAddrMgr;
+    @Inject
+    NetworkOrchestrationService _networkService;
+    @Inject
+    NetworkOfferingDao _networkOfferingDao = null;
 
     private boolean canHandle(Network config, Service service) {
         DataCenter zone = _dcDao.findById(config.getDataCenterId());
+        // Create a NCC Resource on Demand for the zone.
+
         boolean handleInAdvanceZone =
             (zone.getNetworkType() == NetworkType.Advanced && (config.getGuestType() == Network.GuestType.Isolated || config.getGuestType() == Network.GuestType.Shared) && config.getTrafficType() == TrafficType.Guest);
         boolean handleInBasicZone =
@@ -193,13 +230,217 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl
         }
 
         try {
-            return manageGuestNetworkWithExternalLoadBalancer(true, guestConfig);
+            if(offering.getServicePackage() == null) {
+                return manageGuestNetworkWithExternalLoadBalancer(true, guestConfig);
+            } else {
+                // if the network offering has service package implement it with Netscaler Control Center
+                manageGuestNetworkWithNetscalerControlCenter(true, guestConfig, offering);
+                return true;
+            }
         } catch (InsufficientCapacityException capacityException) {
             throw new ResourceUnavailableException("There are no NetScaler load balancer devices with the free capacity for implementing this network", DataCenter.class,
                 guestConfig.getDataCenterId());
+        } catch (ConfigurationException e) {
+            throw new ResourceUnavailableException("There are no NetScaler load balancer devices with the free capacity for implementing this network : " + e.getMessage(), DataCenter.class,
+                    guestConfig.getDataCenterId());
         }
     }
 
+
+    public HostVO getNetScalerControlCenterForNetwork(Network guestConfig) {
+        long zoneId = guestConfig.getDataCenterId();
+        return _hostDao.findByTypeNameAndZoneId(zoneId, "NetscalerControlCenter", Type.NetScalerControlCenter);
+    }
+
+    public HostVO allocateNCCResourceForNetwork(Network guestConfig) throws ConfigurationException {
+        Map<String, String> _configs;
+        List<NetScalerControlCenterVO> ncc =  _netscalerControlCenterDao.listAll();
+        HostVO hostVO = null;
+        Map<String, Object> params ;
+        if(ncc.size() > 0) {
+            NetScalerControlCenterVO nccVO = ncc.get(0);
+            String ipAddress = nccVO.getNccip();
+            Map hostDetails = new HashMap<String, String>();
+            String hostName =  "NetscalerControlCenter";
+            hostDetails.put("name", hostName);
+            hostDetails.put("guid", UUID.randomUUID().toString());
+            hostDetails.put("zoneId", Long.toString(guestConfig.getDataCenterId()));
+            hostDetails.put("ip", ipAddress);
+            hostDetails.put("username", nccVO.getUsername());
+            hostDetails.put("password", nccVO.getPassword());
+            hostDetails.put("deviceName", "netscaler control center");
+            hostDetails.put("cmdTimeOut", Long.toString(NumbersUtil.parseInt(_configDao.getValue(Config.NCCCmdTimeOut.key()), 600000)));
+            ServerResource resource = new NetScalerControlCenterResource();
+            resource.configure(hostName, hostDetails);
+            final Host host = _resourceMgr.addHost(guestConfig.getDataCenterId(), resource, Host.Type.NetScalerControlCenter, hostDetails);
+            hostVO = _hostDao.findById(host.getId());
+        }
+        return hostVO;
+    }
+
+    public boolean manageGuestNetworkWithNetscalerControlCenter(boolean add, Network guestConfig, NetworkOffering offering) throws ResourceUnavailableException, InsufficientCapacityException, ConfigurationException {
+
+        if (guestConfig.getTrafficType() != TrafficType.Guest) {
+            s_logger.trace("External load balancer can only be used for guest networks.");
+            return false;
+        }
+
+        long zoneId = guestConfig.getDataCenterId();
+        DataCenterVO zone = _dcDao.findById(zoneId);
+        HostVO netscalerControlCenter = null;
+
+        if (add) {
+            HostVO lbDeviceVO = null;
+            // on restart network, device could have been allocated already, skip allocation if a device is assigned
+            lbDeviceVO = getNetScalerControlCenterForNetwork(guestConfig);
+            if (lbDeviceVO == null) {
+                // allocate a load balancer device for the network
+                lbDeviceVO = allocateNCCResourceForNetwork(guestConfig);
+                if (lbDeviceVO == null) {
+                    String msg = "failed to allocate Netscaler ControlCenter Resource for the zone in the network " + guestConfig.getId();
+                    s_logger.error(msg);
+                    throw new InsufficientNetworkCapacityException(msg, DataCenter.class, guestConfig.getDataCenterId());
+                }
+            }
+            netscalerControlCenter = _hostDao.findById(lbDeviceVO.getId());
+            s_logger.debug("Allocated Netscaler Control Center device:" + lbDeviceVO.getId() + " for the network: " + guestConfig.getId());
+        } else {
+            // find the load balancer device allocated for the network
+
+            HostVO lbDeviceVO = null;
+            // on restart network, device could have been allocated already, skip allocation if a device is assigned
+            lbDeviceVO = getNetScalerControlCenterForNetwork(guestConfig);
+            if (lbDeviceVO == null) {
+                s_logger.warn("Network shutdwon requested on external load balancer element, which did not implement the network."
+                    + " Either network implement failed half way through or already network shutdown is completed. So just returning.");
+                return true;
+            }
+
+            netscalerControlCenter = _hostDao.findById(lbDeviceVO.getId());
+            assert (netscalerControlCenter != null) : "There is no device assigned to this network how did shutdown network ended up here??";
+        }
+        JSONObject networkDetails = new JSONObject();
+        JSONObject networkPayload = new JSONObject();
+
+        String selfIp = null;
+        try {
+            networkDetails.put("id", guestConfig.getId());
+            networkDetails.put("vlan", guestConfig.getBroadcastUri());
+            networkDetails.put("cidr", guestConfig.getCidr());
+            networkDetails.put("gateway", guestConfig.getGateway());
+            networkDetails.put("servicepackage_id", offering.getServicePackage());
+            networkDetails.put("zone_id", zoneId);
+            networkDetails.put("account_id", guestConfig.getAccountId());
+            networkDetails.put("add", Boolean.toString(add));
+            selfIp = _ipAddrMgr.acquireGuestIpAddress(guestConfig, null);
+            if (selfIp == null) {
+                String msg = "failed to acquire guest IP address so not implementing the network on the NetscalerControlCenter";
+                s_logger.error(msg);
+                throw new InsufficientNetworkCapacityException(msg, Network.class, guestConfig.getId());
+            }
+            networkDetails.put("snip", selfIp);
+            //TODO region is hardcoded make it dynamic
+            networkDetails.put("region_id", 1);
+            networkDetails.put("name", guestConfig.getName());
+            networkPayload.put("network", networkDetails);
+        } catch (JSONException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        NetScalerImplementNetworkCommand cmd = new NetScalerImplementNetworkCommand(zoneId, netscalerControlCenter.getId(), networkPayload.toString());
+        Answer answer = _agentMgr.easySend(netscalerControlCenter.getId(), cmd);
+         if(add) {
+             //TODO After getting the answer check with the job id and do poll on the job and then save the selfip or acquired guest ip to the Nics table
+             if(answer != null ) {
+                 if (add) {
+                     // Insert a new NIC for this guest network to reserve the self IP
+                     _networkService.savePlaceholderNic(guestConfig, selfIp, null, null);
+                 }
+             }
+         } else {
+          // release the self-ip obtained from guest network
+             /*Nic selfipNic = getPlaceholderNic(guestConfig);
+             _nicDao.remove(selfipNic.getId());*/
+             // release the load balancer allocated for the network
+             return true;
+             //write code to remove the self nic or the clean up work
+         }
+        // Send a command to the external load balancer to implement or shutdown the guest network
+/*        long guestVlanTag = Long.parseLong(BroadcastDomainType.getValue(guestConfig.getBroadcastUri()));
+        String selfIp = null;
+        String guestVlanNetmask = NetUtils.cidr2Netmask(guestConfig.getCidr());
+        Integer networkRate = _networkModel.getNetworkRate(guestConfig.getId(), null);
+
+        if (add) {
+            // on restart network, network could have already been implemented. If already implemented then return
+            Nic selfipNic = getPlaceholderNic(guestConfig);
+            if (selfipNic != null) {
+                return true;
+            }
+
+            // Acquire a self-ip address from the guest network IP address range
+            selfIp = _ipAddrMgr.acquireGuestIpAddress(guestConfig, null);
+            if (selfIp == null) {
+                String msg = "failed to acquire guest IP address so not implementing the network on the external load balancer ";
+                s_logger.error(msg);
+                throw new InsufficientNetworkCapacityException(msg, Network.class, guestConfig.getId());
+            }
+        } else {
+            // get the self-ip used by the load balancer
+            Nic selfipNic = getPlaceholderNic(guestConfig);
+            if (selfipNic == null) {
+                s_logger.warn("Network shutdwon requested on external load balancer element, which did not implement the network."
+                    + " Either network implement failed half way through or already network shutdown is completed. So just returning.");
+                return true;
+            }
+            selfIp = selfipNic.getIp4Address();
+        }
+*/
+        // It's a hack, using isOneToOneNat field for indicate if it's inline or not
+/*        boolean inline = _networkMgr.isNetworkInlineMode(guestConfig);
+        IpAddressTO ip =
+            new IpAddressTO(guestConfig.getAccountId(), null, add, false, true, String.valueOf(guestVlanTag), selfIp, guestVlanNetmask, null, networkRate, inline);
+        IpAddressTO[] ips = new IpAddressTO[1];
+        ips[0] = ip;
+        IpAssocCommand cmd = new IpAssocCommand(ips);
+        Answer answer = _agentMgr.easySend(netscalerControlCenter.getId(), cmd);
+*/
+/*        if (answer == null || !answer.getResult()) {
+            String action = add ? "implement" : "shutdown";
+            String answerDetails = (answer != null) ? answer.getDetails() : null;
+            answerDetails = (answerDetails != null) ? " due to " + answerDetails : "";
+            String msg = "External load balancer was unable to " + action + " the guest network on the external load balancer in zone " + zone.getName() + answerDetails;
+            s_logger.error(msg);
+            throw new ResourceUnavailableException(msg, Network.class, guestConfig.getId());
+        }
+
+        if (add) {
+            // Insert a new NIC for this guest network to reserve the self IP
+            _networkMgr.savePlaceholderNic(guestConfig, selfIp, null, null);
+        } else {
+            // release the self-ip obtained from guest network
+            Nic selfipNic = getPlaceholderNic(guestConfig);
+            _nicDao.remove(selfipNic.getId());
+
+            // release the load balancer allocated for the network
+            boolean releasedLB = freeLoadBalancerForNetwork(guestConfig);
+            if (!releasedLB) {
+                String msg = "Failed to release the external load balancer used for the network: " + guestConfig.getId();
+                s_logger.error(msg);
+            }
+        }
+
+        if (s_logger.isDebugEnabled()) {
+            Account account = _accountDao.findByIdIncludingRemoved(guestConfig.getAccountId());
+            String action = add ? "implemented" : "shut down";
+            s_logger.debug("External load balancer has " + action + " the guest network for account " + account.getAccountName() + "(id = " + account.getAccountId() +
+                ") with VLAN tag " + guestVlanTag);
+        }*/
+
+        return true;
+    }
+
     @Override
     public boolean prepare(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context)
         throws ConcurrentOperationException, InsufficientNetworkCapacityException, ResourceUnavailableException {
@@ -218,11 +459,24 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl
         }
 
         try {
-            return manageGuestNetworkWithExternalLoadBalancer(false, guestConfig);
+
+            NetworkOffering networkOffering = _networkOfferingDao.findById(guestConfig.getNetworkOfferingId());
+            if(networkOffering.getServicePackage() == null) {
+                return manageGuestNetworkWithExternalLoadBalancer(true, guestConfig);
+            } else {
+                // if the network offering has service package implement it with Netscaler Control Center
+                return manageGuestNetworkWithNetscalerControlCenter(false, guestConfig, networkOffering);
+                //return true;
+            }
+            //return manageGuestNetworkWithExternalLoadBalancer(false, guestConfig);
         } catch (InsufficientCapacityException capacityException) {
             // TODO: handle out of capacity exception gracefully in case of multple providers available
             return false;
+        } catch (ConfigurationException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
         }
+        return false;
     }
 
     @Override
@@ -528,6 +782,8 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl
         cmdList.add(DeleteNetscalerLoadBalancerCmd.class);
         cmdList.add(ListNetscalerLoadBalancerNetworksCmd.class);
         cmdList.add(ListNetscalerLoadBalancersCmd.class);
+        cmdList.add(RegisterServicePackageCmd.class);
+        cmdList.add(RegisterNetscalerControlCenterCmd.class);
 
         return cmdList;
     }
@@ -645,7 +901,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl
                 }
             }
         }
-        return false;
+        return true;
     }
 
     @Override
@@ -1046,4 +1302,71 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl
         }
         return true;
     }
+
+    @Override
+    public NetScalerServicePackageResponse registerNetscalerServicePackage(RegisterServicePackageCmd cmd) {
+        NetScalerServicePackageVO servicePackage = new NetScalerServicePackageVO(cmd);
+        NetScalerServicePackageResponse response = null;
+        _netscalerServicePackageDao.persist(servicePackage);
+        response = new NetScalerServicePackageResponse(servicePackage);
+        return response;
+    }
+
+    @Override
+    public NetScalerServicePackageResponse deleteNetscalerServicePackage(RegisterServicePackageCmd cmd) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public NetScalerServicePackageResponse listNetscalerServicePackage(RegisterServicePackageCmd cmd) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public NetScalerServicePackageResponse createNetscalerServicePackageResponse(NetScalerServicePackageVO servicePackageVO) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    @DB
+    public NetScalerControlCenterVO registerNetscalerControlCenter(RegisterNetscalerControlCenterCmd cmd) {
+
+        final RegisterNetscalerControlCenterCmd cmdinfo = cmd;
+        String ipAddress = cmd.getIpaddress();
+        Map hostDetails = new HashMap<String, String>();
+        String hostName =  "NetscalerControlCenter";
+        hostDetails.put("name", hostName);
+        hostDetails.put("guid", UUID.randomUUID().toString());
+        List<DataCenterVO> dcVO = _dcDao.listEnabledZones();
+        if(dcVO.size() == 0) {
+            throw new CloudRuntimeException("There is no single enabled zone. Please add a zone, enable it and then add Netscaler ControlCenter");
+        }
+        hostDetails.put("zoneId", "1");
+        hostDetails.put("ip", ipAddress);
+        hostDetails.put("username", cmd.getUsername());
+        hostDetails.put("password", cmd.getPassword());
+        hostDetails.put("deviceName", "Netscaler ControlCenter");
+        ServerResource resource = new NetScalerControlCenterResource();
+        try {
+
+            resource.configure(hostName, hostDetails);
+            return Transaction.execute(new TransactionCallback<NetScalerControlCenterVO>() {
+                @Override
+                public NetScalerControlCenterVO doInTransaction(TransactionStatus status) {
+                    NetScalerControlCenterVO nccVO = new NetScalerControlCenterVO(cmdinfo.getUsername(), cmdinfo.getPassword(),
+                            cmdinfo.getIpaddress(), cmdinfo.getNumretries());
+                    _netscalerControlCenterDao.persist(nccVO);
+                    /*DetailVO hostDetail = new DetailVO(host.getId(), ApiConstants.NETSCALER_CONTROLCENTER_ID , String.valueOf(nccVO.getId()));
+                    _hostDetailDao.persist(hostDetail);*/
+                    return nccVO;
+                }
+            });
+        } catch (ConfigurationException e) {
+            resource = null;
+            throw new CloudRuntimeException(e.getMessage());
+        }
+    }
 }
diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerLoadBalancerElementService.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerLoadBalancerElementService.java
index ea4ab93..81c5b7c 100644
--- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerLoadBalancerElementService.java
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerLoadBalancerElementService.java
@@ -23,7 +23,12 @@ import com.cloud.api.commands.ConfigureNetscalerLoadBalancerCmd;
 import com.cloud.api.commands.DeleteNetscalerLoadBalancerCmd;
 import com.cloud.api.commands.ListNetscalerLoadBalancerNetworksCmd;
 import com.cloud.api.commands.ListNetscalerLoadBalancersCmd;
+import com.cloud.api.commands.RegisterNetscalerControlCenterCmd;
+import com.cloud.api.commands.RegisterServicePackageCmd;
 import com.cloud.api.response.NetscalerLoadBalancerResponse;
+import com.cloud.api.response.NetScalerServicePackageResponse;
+import com.cloud.network.NetScalerControlCenterVO;
+import com.cloud.network.NetScalerServicePackageVO;
 import com.cloud.network.Network;
 import com.cloud.network.dao.ExternalLoadBalancerDeviceVO;
 import com.cloud.utils.component.PluggableService;
@@ -71,4 +76,19 @@ public interface NetscalerLoadBalancerElementService extends PluggableService {
      * @return NetscalerLoadBalancerResponse
      */
     public NetscalerLoadBalancerResponse createNetscalerLoadBalancerResponse(ExternalLoadBalancerDeviceVO lbDeviceVO);
+
+    /**
+     * creates API response object for netscaler load balancers
+     * @param lbDeviceVO external load balancer VO object
+     * @return NetscalerLoadBalancerResponse
+     */
+    public NetScalerServicePackageResponse registerNetscalerServicePackage(RegisterServicePackageCmd cmd);
+
+    public NetScalerServicePackageResponse deleteNetscalerServicePackage(RegisterServicePackageCmd cmd);
+
+    public NetScalerServicePackageResponse listNetscalerServicePackage(RegisterServicePackageCmd cmd);
+
+    public NetScalerServicePackageResponse createNetscalerServicePackageResponse(NetScalerServicePackageVO servicePackageVO);
+
+    public NetScalerControlCenterVO registerNetscalerControlCenter(RegisterNetscalerControlCenterCmd registerNetscalerControlCenterCmd);
 }
diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetScalerControlCenterResource.java b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetScalerControlCenterResource.java
new file mode 100644
index 0000000..15342dc
--- /dev/null
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetScalerControlCenterResource.java
@@ -0,0 +1,4026 @@
+// 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.network.resource;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.BasicClientConnectionManager;
+import org.apache.http.util.EntityUtils;
+import org.apache.log4j.Logger;
+import org.bouncycastle.openssl.PEMWriter;
+import org.json.JSONObject;
+
+import com.citrix.netscaler.nitro.exception.nitro_exception;
+import com.citrix.netscaler.nitro.resource.base.base_response;
+import com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction;
+import com.citrix.netscaler.nitro.resource.config.autoscale.autoscalepolicy;
+import com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleprofile;
+import com.citrix.netscaler.nitro.resource.config.basic.server_service_binding;
+import com.citrix.netscaler.nitro.resource.config.basic.service_lbmonitor_binding;
+import com.citrix.netscaler.nitro.resource.config.basic.servicegroup;
+import com.citrix.netscaler.nitro.resource.config.basic.servicegroup_lbmonitor_binding;
+import com.citrix.netscaler.nitro.resource.config.gslb.gslbservice;
+import com.citrix.netscaler.nitro.resource.config.gslb.gslbservice_lbmonitor_binding;
+import com.citrix.netscaler.nitro.resource.config.gslb.gslbsite;
+import com.citrix.netscaler.nitro.resource.config.gslb.gslbsite_gslbservice_binding;
+import com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver;
+import com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver_domain_binding;
+import com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver_gslbservice_binding;
+import com.citrix.netscaler.nitro.resource.config.lb.lbmetrictable;
+import com.citrix.netscaler.nitro.resource.config.lb.lbmetrictable_metric_binding;
+import com.citrix.netscaler.nitro.resource.config.lb.lbmonitor;
+import com.citrix.netscaler.nitro.resource.config.lb.lbmonitor_metric_binding;
+import com.citrix.netscaler.nitro.resource.config.lb.lbvserver;
+import com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding;
+import com.citrix.netscaler.nitro.resource.config.lb.lbvserver_servicegroup_binding;
+import com.citrix.netscaler.nitro.resource.config.network.inat;
+import com.citrix.netscaler.nitro.resource.config.network.rnat;
+import com.citrix.netscaler.nitro.resource.config.network.vlan;
+import com.citrix.netscaler.nitro.resource.config.network.vlan_interface_binding;
+import com.citrix.netscaler.nitro.resource.config.network.vlan_nsip_binding;
+import com.citrix.netscaler.nitro.resource.config.ns.nsconfig;
+import com.citrix.netscaler.nitro.resource.config.ns.nsip;
+import com.citrix.netscaler.nitro.resource.config.ns.nstimer;
+import com.citrix.netscaler.nitro.resource.config.ns.nstimer_autoscalepolicy_binding;
+import com.citrix.netscaler.nitro.resource.config.ssl.sslcertkey;
+import com.citrix.netscaler.nitro.resource.config.ssl.sslcertkey_sslvserver_binding;
+import com.citrix.netscaler.nitro.resource.config.ssl.sslcertlink;
+import com.citrix.netscaler.nitro.resource.config.ssl.sslvserver_sslcertkey_binding;
+import com.citrix.netscaler.nitro.resource.stat.lb.lbvserver_stats;
+import com.citrix.netscaler.nitro.service.nitro_service;
+import com.citrix.netscaler.nitro.util.filtervalue;
+import com.citrix.sdx.nitro.resource.config.ns.ns;
+import com.citrix.sdx.nitro.resource.config.xen.xen_nsvpx_image;
+import com.google.common.collect.Lists;
+import com.google.gson.Gson;
+
+import org.apache.cloudstack.api.ApiConstants;
+
+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.NetScalerImplementNetworkCommand;
+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.UnsupportedAnswer;
+import com.cloud.agent.api.routing.CreateLoadBalancerApplianceCommand;
+import com.cloud.agent.api.routing.DestroyLoadBalancerApplianceCommand;
+import com.cloud.agent.api.routing.GlobalLoadBalancerConfigAnswer;
+import com.cloud.agent.api.routing.GlobalLoadBalancerConfigCommand;
+import com.cloud.agent.api.routing.HealthCheckLBConfigAnswer;
+import com.cloud.agent.api.routing.HealthCheckLBConfigCommand;
+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.SetStaticNatRulesAnswer;
+import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
+import com.cloud.agent.api.routing.SiteLoadBalancerConfig;
+import com.cloud.agent.api.to.IpAddressTO;
+import com.cloud.agent.api.to.LoadBalancerTO;
+import com.cloud.agent.api.to.LoadBalancerTO.AutoScalePolicyTO;
+import com.cloud.agent.api.to.LoadBalancerTO.AutoScaleVmGroupTO;
+import com.cloud.agent.api.to.LoadBalancerTO.AutoScaleVmProfileTO;
+import com.cloud.agent.api.to.LoadBalancerTO.ConditionTO;
+import com.cloud.agent.api.to.LoadBalancerTO.CounterTO;
+import com.cloud.agent.api.to.LoadBalancerTO.DestinationTO;
+import com.cloud.agent.api.to.LoadBalancerTO.HealthCheckPolicyTO;
+import com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO;
+import com.cloud.agent.api.to.StaticNatRuleTO;
+import com.cloud.host.Host;
+import com.cloud.host.Host.Type;
+import com.cloud.network.lb.LoadBalancingRule.LbSslCert;
+import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType;
+import com.cloud.resource.ServerResource;
+import com.cloud.serializer.GsonHelper;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.exception.ExecutionException;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.utils.security.CertificateHelper;
+import com.cloud.utils.ssh.SshHelper;
+
+/*class NitroError {
+    static final int NS_RESOURCE_EXISTS = 273;
+    static final int NS_RESOURCE_NOT_EXISTS = 258;
+    static final int NS_NO_SERIVCE = 344;
+    static final int NS_OPERATION_NOT_PERMITTED = 257;
+    static final int NS_INTERFACE_ALREADY_BOUND_TO_VLAN = 2080;
+    static final int NS_GSLB_DOMAIN_ALREADY_BOUND = 1842;
+}*/
+
+public class NetScalerControlCenterResource implements ServerResource {
+
+    public final static int DEFAULT_SNMP_PORT = 161;
+    // deployment configuration
+    private String _name;
+    private String _zoneId;
+    private String _physicalNetworkId;
+    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 boolean _isSdx;
+    private boolean _cloudManaged;
+    private String _deviceName;
+    private String _publicIP;
+    private String _publicIPNetmask;
+    private String _publicIPGateway;
+    private String _publicIPVlan;
+    private String _sessionid;
+    public static final int DEFAULT_PORT = 443;
+    private static final Gson s_gson = GsonHelper.getGson();
+    private static final Logger s_logger = Logger.getLogger(NetScalerControlCenterResource.class);
+    protected Gson _gson;
+    private final String _objectNamePathSep = "-";
+    final String protocol="https";
+
+    // interface to interact with VPX and MPX devices
+    com.citrix.netscaler.nitro.service.nitro_service _netscalerService;
+
+    // interface to interact with service VM of the SDX appliance
+    com.citrix.sdx.nitro.service.nitro_service _netscalerSdxService;
+
+    base_response apiCallResult;
+
+    public NetScalerControlCenterResource() {
+        _gson = GsonHelper.getGsonLogger();
+    }
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+        JSONObject jsonResponse = null;
+        try {
+            _name = (String)params.get("name");
+            if (_name == null) {
+                throw new ConfigurationException("Unable to find name in the configuration parameters");
+            }
+
+            _zoneId = (String)params.get("zoneId");
+            if (_zoneId == null) {
+                throw new ConfigurationException("Unable to find zone Id  in the configuration parameters");
+            }
+
+/*            _physicalNetworkId = (String)params.get("physicalNetworkId");
+            if (_physicalNetworkId == null) {
+                throw new ConfigurationException("Unable to find physical network id in the configuration parameters");
+            }
+*/
+            _ip = (String)params.get("ip");
+            if (_ip == null) {
+                throw new ConfigurationException("Unable to find IP address in the configuration parameters");
+            }
+
+            _username = (String)params.get("username");
+            if (_username == null) {
+                throw new ConfigurationException("Unable to find username in the configuration parameters");
+            }
+
+            _password = (String)params.get("password");
+            if (_password == null) {
+                throw new ConfigurationException("Unable to find password in the configuration parameters");
+            }
+
+            _numRetries = NumbersUtil.parseInt((String)params.get("numretries"), 2);
+
+            _guid = (String)params.get("guid");
+            if (_guid == null) {
+                throw new ConfigurationException("Unable to find the guid in the configuration parameters");
+            }
+
+            _deviceName = (String)params.get("deviceName");
+            if (_deviceName == null) {
+                throw new ConfigurationException("Unable to find the device name in the configuration parameters");
+            }
+
+            // validate device configuration parameters
+            String response = login();
+            if(response == null) {
+                throw new ConfigurationException("No Response Received from the NetScalerControlCenter Device");
+            } else {
+                jsonResponse = new JSONObject(response);
+              org.json.JSONArray loginResponse = jsonResponse.getJSONArray("login");
+              //loginResponse.getJSONObject(0);
+              _sessionid = jsonResponse.getJSONArray("login").getJSONObject(0).getString("sessionid");
+            }
+            // Make GET request with the new session to verify
+            s_logger.debug("Making Request to get all Service packages");
+            getServicePackages();
+            return true;
+        } catch (Exception e) {
+            throw new ConfigurationException(e.getMessage());
+        }
+    }
+
+    public void getServicePackages() throws ExecutionException {
+            String result = null;
+            try {
+                // If a previous session was open, log it out.
+                //logout();
+                //http://10.102.31.78/nitro/v2/config/login
+                URI agentUri = null;
+                //String url = protocol + "://" + _ip +"/nitro/v2/config/login";
+                agentUri =
+                        new URI("https", null, _ip, DEFAULT_PORT,
+                                "/admin/v1/servicepackages", null, null);
+
+                org.json.JSONObject jsonBody = new JSONObject();
+                org.json.JSONObject jsonCredentials = new JSONObject();
+                //String loginBody= "{ \"login\": {\"username\":\"" + _username  +"\", \"password\":\"" + _password +"\" }}";
+/*                jsonCredentials.put("username", _username);
+                jsonCredentials.put("password", _password);
+                jsonBody.put("login", jsonCredentials);
+*/
+                result = getHttpRequest(jsonBody.toString(), agentUri, _sessionid);
+                s_logger.debug("List of Service Packages in NCC:: " + result);
+                //return result;
+                } catch (URISyntaxException e) {
+                    String errMsg = "Could not generate URI for Hyper-V agent";
+                    s_logger.error(errMsg, e);
+
+                } catch (Exception e) {
+                throw new ExecutionException("Failed to log in to NCC device at " + _ip + " due to " + e.getMessage());
+            }
+            //return result;
+    }
+
+    private void logout() throws ExecutionException {
+        try {
+            if (!_isSdx) {
+                if (_netscalerService != null) {
+                    _netscalerService.logout();
+                }
+            } else {
+                if (_netscalerSdxService != null) {
+                    _netscalerSdxService.logout();
+                }
+            }
+        } catch (Exception e) {
+            // Ignore logout exceptions
+        }
+    }
+
+    private String login() throws ExecutionException {
+        String result = null;
+        try {
+            // If a previous session was open, log it out.
+            //logout();
+            //http://10.102.31.78/nitro/v2/config/login
+            URI agentUri = null;
+            //String url = protocol + "://" + _ip +"/nitro/v2/config/login";
+            agentUri =
+                    new URI("https", null, _ip, DEFAULT_PORT,
+                            "/nitro/v2/config/" + "login", null, null);
+            org.json.JSONObject jsonBody = new JSONObject();
+            org.json.JSONObject jsonCredentials = new JSONObject();
+            //String loginBody= "{ \"login\": {\"username\":\"" + _username  +"\", \"password\":\"" + _password +"\" }}";
+            jsonCredentials.put("username", _username);
+            jsonCredentials.put("password", _password);
+            jsonBody.put("login", jsonCredentials);
+
+            result = postHttpRequest(jsonBody.toString(), agentUri, _sessionid);
+            s_logger.debug("NCC Device got Added:: " + result);
+            return result;
+            } catch (URISyntaxException e) {
+                String errMsg = "Could not generate URI for Hyper-V agent";
+                s_logger.error(errMsg, e);
+
+            } catch (Exception e) {
+            throw new ExecutionException("Failed to log in to NCC device at " + _ip + " due to " + e.getMessage());
+        }
+        return result;
+    }
+
+    @Override
+    public StartupCommand[] initialize() {
+        StartupExternalLoadBalancerCommand cmd = new StartupExternalLoadBalancerCommand(Host.Type.NetScalerControlCenter);
+        cmd.setName(_name);
+        cmd.setDataCenter(_zoneId);
+        cmd.setPod("");
+        cmd.setPrivateIpAddress(_ip);
+        cmd.setStorageIpAddress("");
+        cmd.setVersion(NetScalerControlCenterResource.class.getPackage().getImplementationVersion());
+        cmd.setGuid(_guid);
+        return new StartupCommand[] {cmd};
+    }
+
+    @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, numRetries);
+        } else if (cmd instanceof CreateLoadBalancerApplianceCommand) {
+            return execute((CreateLoadBalancerApplianceCommand)cmd, numRetries);
+        } else if (cmd instanceof DestroyLoadBalancerApplianceCommand) {
+            return execute((DestroyLoadBalancerApplianceCommand)cmd, numRetries);
+        } else if (cmd instanceof SetStaticNatRulesCommand) {
+            return execute((SetStaticNatRulesCommand)cmd, numRetries);
+        } else if (cmd instanceof GlobalLoadBalancerConfigCommand) {
+            return execute((GlobalLoadBalancerConfigCommand)cmd, numRetries);
+        } else if (cmd instanceof HealthCheckLBConfigCommand) {
+            return execute((HealthCheckLBConfigCommand)cmd, numRetries);
+        } else if (cmd instanceof NetScalerImplementNetworkCommand ) {
+            return execute((NetScalerImplementNetworkCommand)cmd, numRetries);
+        }
+        else {
+            return Answer.createUnsupportedCommandAnswer(cmd);
+        }
+    }
+
+    private Answer execute(ReadyCommand cmd) {
+        return new ReadyAnswer(cmd);
+    }
+
+    protected Answer execute(MaintainCommand cmd) {
+        return new MaintainAnswer(cmd);
+    }
+
+    private synchronized Answer execute(NetScalerImplementNetworkCommand cmd, int numRetries) {
+        String result = null;
+        try {
+            // If a previous session was open, log it out.
+            //logout();
+            //http://10.102.31.78/nitro/v2/config/login
+            URI agentUri = null;
+            //String url = protocol + "://" + _ip +"/nitro/v2/config/login";
+            //url: <ip>/cs/cca/networks
+            agentUri =
+                    new URI("https", null, _ip, DEFAULT_PORT,
+                            "/cs/cca/networks", null, null);
+            org.json.JSONObject jsonBody = new JSONObject(cmd.getDetails());
+            s_logger.debug("Sending Network Implement to NCC:: " + jsonBody);
+            result = postHttpRequest(jsonBody.toString(), agentUri, _sessionid);
+            s_logger.debug("Result of Network Implement to NCC:: " + result);
+            //return result;
+            } catch (URISyntaxException e) {
+                String errMsg = "Could not generate URI for Hyper-V agent";
+                s_logger.error(errMsg, e);
+            } catch (Exception e) {
+            }
+
+        return Answer.createUnsupportedCommandAnswer(cmd);
+    }
+
+    private synchronized Answer execute(IpAssocCommand cmd,  int numRetries) {
+        if (_isSdx) {
+            return Answer.createUnsupportedCommandAnswer(cmd);
+        }
+
+        String[] results = new String[cmd.getIpAddresses().length];
+        int i = 0;
+        try {
+            IpAddressTO[] ips = cmd.getIpAddresses();
+            for (IpAddressTO ip : ips) {
+                long guestVlanTag = Long.parseLong(ip.getBroadcastUri());
+                String vlanSelfIp = ip.getVlanGateway();
+                String vlanNetmask = ip.getVlanNetmask();
+
+                if (ip.isAdd()) {
+                    // Add a new guest VLAN and its subnet and bind it to private interface
+                    addGuestVlanAndSubnet(guestVlanTag, vlanSelfIp, vlanNetmask, true);
+                } else {
+                    // Check and delete guest VLAN with this tag, self IP, and netmask
+                    deleteGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask);
+                }
+
+                saveConfiguration();
+                results[i++] = ip.getPublicIp() + " - success";
+                String action = ip.isAdd() ? "associate" : "remove";
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Netscaler load balancer " + _ip + " successfully executed IPAssocCommand to " + action + " IP " + ip);
+                }
+            }
+        } catch (ExecutionException e) {
+            s_logger.error("Netscaler loadbalancer " + _ip + " failed to execute IPAssocCommand due to " + e.getMessage());
+            if (shouldRetry(numRetries)) {
+                return retry(cmd, numRetries);
+            } else {
+                results[i++] = IpAssocAnswer.errorResult;
+            }
+        }
+
+        return new IpAssocAnswer(cmd, results);
+    }
+
+    private Answer execute(HealthCheckLBConfigCommand cmd, int numRetries) {
+
+        List<LoadBalancerTO> hcLB = new ArrayList<LoadBalancerTO>();
+        try {
+
+            if (_isSdx) {
+                return Answer.createUnsupportedCommandAnswer(cmd);
+            }
+
+            LoadBalancerTO[] loadBalancers = cmd.getLoadBalancers();
+
+            if (loadBalancers == null) {
+                return new HealthCheckLBConfigAnswer(hcLB);
+            }
+
+            for (LoadBalancerTO loadBalancer : loadBalancers) {
+                HealthCheckPolicyTO[] healthCheckPolicies = loadBalancer.getHealthCheckPolicies();
+                if ((healthCheckPolicies != null) && (healthCheckPolicies.length > 0) && (healthCheckPolicies[0] != null)) {
+                    String nsVirtualServerName = generateNSVirtualServerName(loadBalancer.getSrcIp(), loadBalancer.getSrcPort());
+
+                    com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding[] serviceBindings =
+                            com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.get(_netscalerService, nsVirtualServerName);
+
+                    if (serviceBindings != null) {
+                        for (DestinationTO destination : loadBalancer.getDestinations()) {
+                            String nsServiceName = generateNSServiceName(destination.getDestIp(), destination.getDestPort());
+                            for (com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding binding : serviceBindings) {
+                                if (nsServiceName.equalsIgnoreCase(binding.get_servicename())) {
+                                    destination.setMonitorState(binding.get_curstate());
+                                    break;
+                                }
+                            }
+                        }
+                        hcLB.add(loadBalancer);
+                    }
+                }
+            }
+
+        } catch (ExecutionException e) {
+            s_logger.error("Failed to execute HealthCheckLBConfigCommand due to ", e);
+            if (shouldRetry(numRetries)) {
+                return retry(cmd, numRetries);
+            } else {
+                return new HealthCheckLBConfigAnswer(hcLB);
+            }
+        } catch (Exception e) {
+            s_logger.error("Failed to execute HealthCheckLBConfigCommand due to ", e);
+            if (shouldRetry(numRetries)) {
+                return retry(cmd, numRetries);
+            } else {
+                return new HealthCheckLBConfigAnswer(hcLB);
+            }
+        }
+        return new HealthCheckLBConfigAnswer(hcLB);
+    }
+
+    private synchronized Answer execute(LoadBalancerConfigCommand cmd, int numRetries) {
+        try {
+            if (_isSdx) {
+                return Answer.createUnsupportedCommandAnswer(cmd);
+            }
+
+            LoadBalancerTO[] loadBalancers = cmd.getLoadBalancers();
+            if (loadBalancers == null) {
+                return new Answer(cmd);
+            }
+
+            for (LoadBalancerTO loadBalancer : loadBalancers) {
+                String srcIp = loadBalancer.getSrcIp();
+                int srcPort = loadBalancer.getSrcPort();
+                String lbProtocol = getNetScalerProtocol(loadBalancer);
+                String lbAlgorithm = loadBalancer.getAlgorithm();
+                String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort);
+                String nsMonitorName = generateNSMonitorName(srcIp, srcPort);
+                LbSslCert sslCert = loadBalancer.getSslCert();
+
+                if (loadBalancer.isAutoScaleVmGroupTO()) {
+                    applyAutoScaleConfig(loadBalancer);
+                    // Continue to process all the rules.
+                    continue;
+                }
+                boolean hasMonitor = false;
+                boolean deleteMonitor = false;
+                boolean destinationsToAdd = false;
+                boolean deleteCert = false;
+                for (DestinationTO destination : loadBalancer.getDestinations()) {
+                    if (!destination.isRevoked()) {
+                        destinationsToAdd = true;
+                        break;
+                    }
+                }
+
+                if (!loadBalancer.isRevoked() && destinationsToAdd) {
+
+                    // create a load balancing virtual server
+                    addLBVirtualServer(nsVirtualServerName, srcIp, srcPort, lbAlgorithm, lbProtocol, loadBalancer.getStickinessPolicies(), null);
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Created load balancing virtual server " + nsVirtualServerName + " on the Netscaler device");
+                    }
+
+                    // create a new monitor
+                    HealthCheckPolicyTO[] healthCheckPolicies = loadBalancer.getHealthCheckPolicies();
+                    if ((healthCheckPolicies != null) && (healthCheckPolicies.length > 0) && (healthCheckPolicies[0] != null)) {
+
+                        for (HealthCheckPolicyTO healthCheckPolicyTO : healthCheckPolicies) {
+                            if (!healthCheckPolicyTO.isRevoked()) {
+                                addLBMonitor(nsMonitorName, lbProtocol, healthCheckPolicyTO);
+                                hasMonitor = true;
+                            } else {
+                                deleteMonitor = true;
+                                hasMonitor = false;
+                            }
+                        }
+
+                    }
+
+                    for (DestinationTO destination : loadBalancer.getDestinations()) {
+
+                        String nsServerName = generateNSServerName(destination.getDestIp());
+                        String nsServiceName = generateNSServiceName(destination.getDestIp(), destination.getDestPort());
+                        if (!destination.isRevoked()) {
+                            // add a new destination to deployed load balancing rule
+
+                            // add a new server
+                            if (!nsServerExists(nsServerName)) {
+                                com.citrix.netscaler.nitro.resource.config.basic.server nsServer = new com.citrix.netscaler.nitro.resource.config.basic.server();
+                                nsServer.set_name(nsServerName);
+                                nsServer.set_ipaddress(destination.getDestIp());
+                                apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.add(_netscalerService, nsServer);
+                                if ((apiCallResult.errorcode != 0) && (apiCallResult.errorcode != NitroError.NS_RESOURCE_EXISTS)) {
+                                    throw new ExecutionException("Failed to add server " + destination.getDestIp() + " due to" + apiCallResult.message);
+                                }
+                            }
+
+                            // create a new service using the server added
+                            if (!nsServiceExists(nsServiceName)) {
+                                com.citrix.netscaler.nitro.resource.config.basic.service newService = new com.citrix.netscaler.nitro.resource.config.basic.service();
+                                newService.set_name(nsServiceName);
+                                newService.set_port(destination.getDestPort());
+                                newService.set_servername(nsServerName);
+                                newService.set_state("ENABLED");
+                                if(lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO)) {
+                                    newService.set_servicetype(NetUtils.HTTP_PROTO);
+                                } else {
+                                    newService.set_servicetype(lbProtocol);
+                                }
+
+                                apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.service.add(_netscalerService, newService);
+                                if (apiCallResult.errorcode != 0) {
+                                    throw new ExecutionException("Failed to create service " + nsServiceName + " using server " + nsServerName + " due to" +
+                                            apiCallResult.message);
+                                }
+                            }
+
+                            //bind service to load balancing virtual server
+                            if (!nsServiceBindingExists(nsVirtualServerName, nsServiceName)) {
+                                com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding svcBinding =
+                                        new com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding();
+                                svcBinding.set_name(nsVirtualServerName);
+                                svcBinding.set_servicename(nsServiceName);
+                                apiCallResult = com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.add(_netscalerService, svcBinding);
+
+                                if (apiCallResult.errorcode != 0) {
+                                    throw new ExecutionException("Failed to bind service: " + nsServiceName + " to the lb virtual server: " + nsVirtualServerName +
+                                            " on Netscaler device");
+                                }
+                            }
+
+                            // After binding the service to the LB Vserver
+                            // successfully, bind the created monitor to the
+                            // service.
+                            if (hasMonitor) {
+                                if (!isServiceBoundToMonitor(nsServiceName, nsMonitorName)) {
+                                    bindServiceToMonitor(nsServiceName, nsMonitorName);
+                                }
+                            } else {
+                                // check if any monitor created by CS is already
+                                // existing, if yes, unbind it from services and
+                                // delete it.
+                                if (nsMonitorExist(nsMonitorName)) {
+                                    // unbind the service from the monitor and
+                                    // delete the monitor
+                                    unBindServiceToMonitor(nsServiceName, nsMonitorName);
+                                    deleteMonitor = true;
+                                }
+
+                            }
+
+                            if (sslCert != null && lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO)) {
+                                if (sslCert.isRevoked()) {
+                                    deleteCert = true;
+                                } else {
+
+                                    // If there is a chain, that should go first to the NS
+
+                                    String previousCertKeyName = null;
+
+                                    if (sslCert.getChain() != null) {
+                                        List<Certificate> chainList = CertificateHelper.parseChain(sslCert.getChain());
+                                        // go from ROOT to intermediate CAs
+                                        for (Certificate intermediateCert : Lists.reverse(chainList)) {
+
+                                            String fingerPrint = CertificateHelper.generateFingerPrint(intermediateCert);
+                                            String intermediateCertKeyName = generateSslCertKeyName(fingerPrint);
+                                            String intermediateCertFileName = intermediateCertKeyName + ".pem";
+
+                                            if (!SSL.isSslCertKeyPresent(_netscalerService, intermediateCertKeyName)) {
+                                                intermediateCert.getEncoded();
+                                                StringWriter textWriter = new StringWriter();
+                                                PEMWriter pemWriter = new PEMWriter(textWriter);
+                                                pemWriter.writeObject(intermediateCert);
+                                                pemWriter.flush();
+
+                                                SSL.uploadCert(_ip, _username, _password, intermediateCertFileName, textWriter.toString().getBytes());
+                                                SSL.createSslCertKey(_netscalerService, intermediateCertFileName, null, intermediateCertKeyName, null);
+                                            }
+
+                                            if (previousCertKeyName != null && !SSL.certLinkExists(_netscalerService, intermediateCertKeyName, previousCertKeyName)) {
+                                                SSL.linkCerts(_netscalerService, intermediateCertKeyName, previousCertKeyName);
+                                            }
+
+                                            previousCertKeyName = intermediateCertKeyName;
+                                        }
+                                    }
+
+                                    String certFilename = generateSslCertName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
+                                    String keyFilename = generateSslKeyName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
+                                    String certKeyName = generateSslCertKeyName(sslCert.getFingerprint());
+
+                                    ByteArrayOutputStream certDataStream = new ByteArrayOutputStream();
+                                    certDataStream.write(sslCert.getCert().getBytes());
+
+                                    if (!SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) {
+
+                                        SSL.uploadCert(_ip, _username, _password, certFilename, certDataStream.toByteArray());
+                                        SSL.uploadKey(_ip, _username, _password, keyFilename, sslCert.getKey().getBytes());
+                                        SSL.createSslCertKey(_netscalerService, certFilename, keyFilename, certKeyName, sslCert.getPassword());
+                                    }
+
+                                    if (previousCertKeyName != null && !SSL.certLinkExists(_netscalerService, certKeyName, previousCertKeyName)) {
+                                        SSL.linkCerts(_netscalerService, certKeyName, previousCertKeyName);
+                                    }
+
+                                    SSL.bindCertKeyToVserver(_netscalerService, certKeyName, nsVirtualServerName);
+                                }
+
+                            }
+
+                            if (s_logger.isDebugEnabled()) {
+                                s_logger.debug("Successfully added LB destination: " + destination.getDestIp() + ":" + destination.getDestPort() + " to load balancer " +
+                                        srcIp + ":" + srcPort);
+                            }
+
+                        } else {
+                            // remove a destination from the deployed load balancing rule
+                            com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding[] serviceBindings =
+                                    com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.get(_netscalerService, nsVirtualServerName);
+                            if (serviceBindings != null) {
+                                for (com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding binding : serviceBindings) {
+                                    if (nsServiceName.equalsIgnoreCase(binding.get_servicename())) {
+                                        // delete the binding
+                                        apiCallResult = com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.delete(_netscalerService, binding);
+                                        if (apiCallResult.errorcode != 0) {
+                                            throw new ExecutionException("Failed to delete the binding between the virtual server: " + nsVirtualServerName +
+                                                    " and service:" + nsServiceName + " due to" + apiCallResult.message);
+                                        }
+
+                                        // check if service is bound to any other virtual server
+                                        if (!isServiceBoundToVirtualServer(nsServiceName)) {
+                                            // no lb virtual servers are bound to this service so delete it
+                                            apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.service.delete(_netscalerService, nsServiceName);
+                                            if (apiCallResult.errorcode != 0) {
+                                                throw new ExecutionException("Failed to delete service: " + nsServiceName + " due to " + apiCallResult.message);
+                                            }
+                                        }
+
+                                        // delete the server if there is no associated services
+                                        server_service_binding[] services = server_service_binding.get(_netscalerService, nsServerName);
+                                        if ((services == null) || (services.length == 0)) {
+                                            apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.delete(_netscalerService, nsServerName);
+                                            if (apiCallResult.errorcode != 0) {
+                                                throw new ExecutionException("Failed to remove server:" + nsServerName + " due to " + apiCallResult.message);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    // delete the implemented load balancing rule and its destinations
+                    lbvserver lbserver = getVirtualServerIfExisits(nsVirtualServerName);
+                    if (lbserver != null) {
+                        //unbind the all services associated with this virtual server
+                        com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding[] serviceBindings =
+                                com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.get(_netscalerService, nsVirtualServerName);
+
+                        if (serviceBindings != null) {
+                            for (com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding binding : serviceBindings) {
+                                String serviceName = binding.get_servicename();
+                                apiCallResult = com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.delete(_netscalerService, binding);
+                                if (apiCallResult.errorcode != 0) {
+                                    throw new ExecutionException("Failed to unbind service from the lb virtual server: " + nsVirtualServerName + " due to " +
+                                            apiCallResult.message);
+                                }
+
+                                com.citrix.netscaler.nitro.resource.config.basic.service svc =
+                                        com.citrix.netscaler.nitro.resource.config.basic.service.get(_netscalerService, serviceName);
+                                String nsServerName = svc.get_servername();
+
+                                // check if service is bound to any other virtual server
+                                if (!isServiceBoundToVirtualServer(serviceName)) {
+                                    // no lb virtual servers are bound to this service so delete it
+                                    apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.service.delete(_netscalerService, serviceName);
+                                    if (apiCallResult.errorcode != 0) {
+                                        throw new ExecutionException("Failed to delete service: " + serviceName + " due to " + apiCallResult.message);
+                                    }
+                                }
+
+                                //delete the server if no more services attached
+                                server_service_binding[] services = server_service_binding.get(_netscalerService, nsServerName);
+                                if ((services == null) || (services.length == 0)) {
+                                    apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.delete(_netscalerService, nsServerName);
+                                    if (apiCallResult.errorcode != 0) {
+                                        throw new ExecutionException("Failed to remove server:" + nsServerName + " due to " + apiCallResult.message);
+                                    }
+                                }
+                            }
+                        }
+                        removeLBVirtualServer(nsVirtualServerName);
+                        deleteMonitor = true;
+                        deleteCert = true;
+                    }
+                }
+                if (deleteMonitor) {
+                    removeLBMonitor(nsMonitorName);
+                }
+                if (sslCert != null && deleteCert) {
+
+                    String certFilename = generateSslCertName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
+                    String keyFilename = generateSslKeyName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
+                    String certKeyName = generateSslCertKeyName(sslCert.getFingerprint());
+
+                    // unbind before deleting
+                    if (nsVirtualServerExists(nsVirtualServerName) &&
+                            SSL.isSslCertKeyPresent(_netscalerService, certKeyName) &&
+                            SSL.isBoundToVserver(_netscalerService, certKeyName, nsVirtualServerName)) {
+                        SSL.unbindCertKeyFromVserver(_netscalerService, certKeyName, nsVirtualServerName);
+                    }
+
+                    if (SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) {
+
+                        SSL.deleteSslCertKey(_netscalerService, certKeyName);
+                        SSL.deleteCertFile(_ip, _username, _password, certFilename);
+                        SSL.deleteKeyFile(_ip, _username, _password, keyFilename);
+                    }
+
+                    /*
+                     * Check and delete intermediate certs:
+                     * we can delete an intermediate cert if no other
+                     * cert references it as the athority
+                     */
+
+                    if (sslCert.getChain() != null) {
+                        List<Certificate> chainList = CertificateHelper.parseChain(sslCert.getChain());
+                        //go from intermediate CAs to ROOT
+                        for (Certificate intermediateCert : chainList) {
+
+                            String fingerPrint = CertificateHelper.generateFingerPrint(intermediateCert);
+                            String intermediateCertKeyName = generateSslCertKeyName(fingerPrint);
+                            String intermediateCertFileName = intermediateCertKeyName + ".pem";
+
+                            if (SSL.isSslCertKeyPresent(_netscalerService, intermediateCertKeyName) &&
+                                    !SSL.isCaforCerts(_netscalerService, intermediateCertKeyName)) {
+                                SSL.deleteSslCertKey(_netscalerService, intermediateCertKeyName);
+                                SSL.deleteCertFile(_ip, _username, _password, intermediateCertFileName);
+                            } else {
+                                break;// if this cert has another certificate as a child then stop at this point because we need the whole chain
+                            }
+
+                        }
+                    }
+                }
+
+            }
+
+            if (s_logger.isInfoEnabled()) {
+                s_logger.info("Successfully executed resource LoadBalancerConfigCommand: " + _gson.toJson(cmd));
+            }
+
+            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);
+            }
+        } catch (Exception 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 Answer execute(CreateLoadBalancerApplianceCommand cmd, int numRetries) {
+
+        if (!_isSdx) {
+            return Answer.createUnsupportedCommandAnswer(cmd);
+        }
+
+        try {
+            String vpxName = "Cloud-VPX-" + cmd.getLoadBalancerIP();
+            String username = "admin";
+            String password = "admin";
+
+            ns ns_obj = new ns();
+            ns_obj.set_name(vpxName);
+            ns_obj.set_ip_address(cmd.getLoadBalancerIP());
+            ns_obj.set_netmask(cmd.getNetmask());
+            ns_obj.set_gateway(cmd.getGateway());
+            ns_obj.set_username(username);
+            ns_obj.set_password(password);
+
+            // configure VPX instances with defaults
+            ns_obj.set_license("Standard");
+            ns_obj.set_vm_memory_total(new Double(2048));
+            ns_obj.set_throughput(new Double(1000));
+            ns_obj.set_pps(new Double(1000000));
+            ns_obj.set_number_of_ssl_cores(0);
+            ns_obj.set_profile_name("ns_nsroot_profile");
+
+            // use the first VPX image of the available VPX images on the SDX to create an instance of VPX
+            // TODO: should enable the option to choose the template while adding the SDX device in to CloudStack
+            xen_nsvpx_image[] vpxImages = xen_nsvpx_image.get(_netscalerSdxService);
+            if (!(vpxImages != null && vpxImages.length >= 1)) {
+                new Answer(cmd, new ExecutionException("Failed to create VPX instance on the netscaler SDX device " + _ip +
+                        " as there are no VPX images on SDX to use for creating VPX."));
+            }
+            String imageName = vpxImages[0].get_file_name();
+            ns_obj.set_image_name(imageName);
+
+            String publicIf = _publicInterface;
+            String privateIf = _privateInterface;
+
+            // enable only the interfaces that will be used by VPX
+            enableVPXInterfaces(_publicInterface, _privateInterface, ns_obj);
+
+            // create new VPX instance
+            ns newVpx = ns.add(_netscalerSdxService, ns_obj);
+
+            if (newVpx == null) {
+                return new Answer(cmd, new ExecutionException("Failed to create VPX instance on the netscaler SDX device " + _ip));
+            }
+
+            // wait for VPX instance to start-up
+            long startTick = System.currentTimeMillis();
+            long startWaitMilliSeconds = 600000;
+            while (!newVpx.get_instance_state().equalsIgnoreCase("up") && System.currentTimeMillis() - startTick < startWaitMilliSeconds) {
+                try {
+                    Thread.sleep(10000);
+                } catch (InterruptedException e) {
+                }
+                ns refreshNsObj = new ns();
+                refreshNsObj.set_id(newVpx.get_id());
+                newVpx = ns.get(_netscalerSdxService, refreshNsObj);
+            }
+
+            // if vpx instance never came up then error out
+            if (!newVpx.get_instance_state().equalsIgnoreCase("up")) {
+                return new Answer(cmd, new ExecutionException("Failed to start VPX instance " + vpxName + " created on the netscaler SDX device " + _ip));
+            }
+
+            // wait till NS service in side VPX is actually ready
+            startTick = System.currentTimeMillis();
+            boolean nsServiceUp = false;
+            long nsServiceWaitMilliSeconds = 60000;
+            while (System.currentTimeMillis() - startTick < nsServiceWaitMilliSeconds) {
+                try {
+                    nitro_service _netscalerService = new nitro_service(cmd.getLoadBalancerIP(), "https");
+                    _netscalerService.set_certvalidation(false);
+                    _netscalerService.set_hostnameverification(false);
+                    _netscalerService.set_credential(username, password);
+                    apiCallResult = _netscalerService.login();
+                    if (apiCallResult.errorcode == 0) {
+                        nsServiceUp = true;
+                        break;
+                    }
+                } catch (Exception e) {
+                    Thread.sleep(10000);
+                    continue;
+                }
+            }
+
+            if (!nsServiceUp) {
+                return new Answer(cmd, new ExecutionException("Failed to create VPX instance " + vpxName + " on the netscaler SDX device " + _ip));
+            }
+
+            if (s_logger.isInfoEnabled()) {
+                s_logger.info("Successfully provisioned VPX instance " + vpxName + " on the Netscaler SDX device " + _ip);
+            }
+
+            // physical interfaces on the SDX range from 10/1 to 10/8 & 1/1 to 1/8 of which two different port or same port can be used for public and private interfaces
+            // However the VPX instances created will have interface range start from 10/1 but will only have as many interfaces enabled while creating the VPX instance
+            // So due to this, we need to map public & private interface on SDX to correct public & private interface of VPX
+
+            int publicIfnum = Integer.parseInt(_publicInterface.substring(_publicInterface.lastIndexOf("/") + 1));
+            int privateIfnum = Integer.parseInt(_privateInterface.substring(_privateInterface.lastIndexOf("/") + 1));
+
+            if (_publicInterface.startsWith("10/") && _privateInterface.startsWith("10/")) {
+                if (publicIfnum == privateIfnum) {
+                    publicIf = "10/1";
+                    privateIf = "10/1";
+                } else if (publicIfnum > privateIfnum) {
+                    privateIf = "10/1";
+                    publicIf = "10/2";
+                } else {
+                    publicIf = "10/1";
+                    privateIf = "10/2";
+                }
+            } else if (_publicInterface.startsWith("1/") && _privateInterface.startsWith("1/")) {
+                if (publicIfnum == privateIfnum) {
+                    publicIf = "1/1";
+                    privateIf = "1/1";
+                } else if (publicIfnum > privateIfnum) {
+                    privateIf = "1/1";
+                    publicIf = "1/2";
+                } else {
+                    publicIf = "1/1";
+                    privateIf = "1/2";
+                }
+            } else if (_publicInterface.startsWith("1/") && _privateInterface.startsWith("10/")) {
+                publicIf = "1/1";
+                privateIf = "10/1";
+            } else if (_publicInterface.startsWith("10/") && _privateInterface.startsWith("1/")) {
+                publicIf = "10/1";
+                privateIf = "1/1";
+            }
+
+            return new CreateLoadBalancerApplianceAnswer(cmd, true, "provisioned VPX instance", "NetscalerVPXLoadBalancer", "Netscaler", new NetScalerControlCenterResource(),
+                    publicIf, privateIf, _username, _password);
+        } catch (Exception e) {
+            if (shouldRetry(numRetries)) {
+                return retry(cmd, numRetries);
+            }
+            return new CreateLoadBalancerApplianceAnswer(cmd, false, "failed to provisioned VPX instance due to " + e.getMessage(), null, null, null, null, null, null,
+                    null);
+        }
+    }
+
+    private Answer execute(GlobalLoadBalancerConfigCommand gslbCmd, int numRetries) {
+
+        String lbMethod = gslbCmd.getLoadBalancerMethod();
+        String persistenceType = gslbCmd.getPersistenceType();
+        String serviceType = gslbCmd.getServiceType();
+        boolean forRevoke = gslbCmd.isForRevoke();
+        long gslbId = gslbCmd.getGslbId();
+        List<SiteLoadBalancerConfig> sites = gslbCmd.getSiteDetails();
+
+        String domainName = gslbCmd.getDomainName();
+        String vserverName = GSLB.generateVirtualServerName(domainName);
+
+        try {
+
+            if (!forRevoke) { //check if the global load balancer rule is being added
+
+                // Add a GSLB virtual server
+                GSLB.createVirtualServer(_netscalerService, vserverName, lbMethod, persistenceType, gslbId, serviceType);
+
+                if (sites != null) { // check if there are any sites that are participating in global load balancing
+                    for (SiteLoadBalancerConfig site : sites) {
+
+                        String sitePrivateIP = site.getGslbProviderPrivateIp();
+                        String sitePublicIP = site.getGslbProviderPublicIp();
+                        String servicePublicIp = site.getServicePublicIp();
+                        String servicePublicPort = site.getServicePort();
+                        String siteName = GSLB.generateUniqueSiteName(sitePrivateIP, sitePublicIP, site.getDataCenterId());
+
+                        // Add/Delete GSLB local and remote sites that are part of GSLB virtual server
+                        if (!site.forRevoke()) {
+                            String siteType = (site.isLocal()) ? "LOCAL" : "REMOTE";
+                            if (GSLB.getSiteObject(_netscalerService, siteName) != null) {
+                                GSLB.updateSite(_netscalerService, siteType, siteName, site.getGslbProviderPrivateIp(), site.getGslbProviderPublicIp());
+                            } else {
+                                GSLB.createSite(_netscalerService, siteName, siteType, site.getGslbProviderPrivateIp(), site.getGslbProviderPublicIp());
+                            }
+                        }
+
+                        // Add/Delete GSLB service corresponding the service running on each site
+                        String serviceName = GSLB.generateUniqueServiceName(siteName, servicePublicIp, servicePublicPort);
+                        String monitorName = GSLB.generateGslbServiceMonitorName(servicePublicIp);
+                        if (!site.forRevoke()) {
+                            // create a 'gslbservice' object
+                            GSLB.createService(_netscalerService, serviceName, site.getServiceType(), servicePublicIp, servicePublicPort, siteName);
+
+                            // Bind 'gslbservice' service object to GSLB virtual server
+                            GSLB.createVserverServiceBinding(_netscalerService, serviceName, vserverName, site.getWeight());
+
+                            // create a monitor for the service running on the site
+                            GSLB.createGslbServiceMonitor(_netscalerService, servicePublicIp, serviceName);
+
+                            // bind the monitor to the GSLB service
+                            GSLB.createGslbServiceGslbMonitorBinding(_netscalerService, monitorName, serviceName);
+
+                        } else {
+
+                            // delete GSLB service and GSLB monitor binding
+                            GSLB.deleteGslbServiceGslbMonitorBinding(_netscalerService, monitorName, serviceName);
+
+                            // Unbind GSLB service with GSLB virtual server
+                            GSLB.deleteVserverServiceBinding(_netscalerService, serviceName, vserverName);
+
+                            GSLB.getServiceObject(_netscalerService, serviceName);
+                            GSLB.deleteService(_netscalerService, serviceName);
+
+                            // delete the GSLB service monitor
+                            GSLB.deleteGslbServiceMonitor(_netscalerService, monitorName);
+                        }
+
+                        if (site.forRevoke()) { // delete the site if its for revoke
+                            GSLB.deleteSite(_netscalerService, siteName);
+                        }
+                    }
+                }
+
+                // Bind GSLB vserver to domain
+                GSLB.createVserverDomainBinding(_netscalerService, vserverName, domainName);
+
+            } else {  // global load balancer rule is being deleted, so clean up all objects created
+
+                // remove binding between virtual server and the domain name
+                GSLB.deleteVserverDomainBinding(_netscalerService, vserverName, domainName);
+
+                if (sites != null) {
+                    for (SiteLoadBalancerConfig site : sites) {
+
+                        String sitePrivateIP = site.getGslbProviderPrivateIp();
+                        String sitePublicIP = site.getGslbProviderPublicIp();
+                        String servicePublicIp = site.getServicePublicIp();
+                        String servicePublicPort = site.getServicePort();
+                        String siteName = GSLB.generateUniqueSiteName(sitePrivateIP, sitePublicIP, site.getDataCenterId());
+                        String serviceName = GSLB.generateUniqueServiceName(siteName, servicePublicIp, servicePublicPort);
+                        String monitorName = GSLB.generateGslbServiceMonitorName(servicePublicIp);
+
+                        // delete GSLB service and GSLB monitor binding
+                        GSLB.deleteGslbServiceGslbMonitorBinding(_netscalerService, monitorName, serviceName);
+
+                        // remove binding between virtual server and services
+                        GSLB.deleteVserverServiceBinding(_netscalerService, serviceName, vserverName);
+
+                        // delete service object
+                        GSLB.deleteService(_netscalerService, serviceName);
+
+                        // delete GSLB site object
+                        GSLB.deleteSite(_netscalerService, siteName);
+
+                        // delete the GSLB service monitor
+                        GSLB.deleteGslbServiceMonitor(_netscalerService, monitorName);
+                    }
+                }
+
+                // delete GSLB virtual server
+                GSLB.deleteVirtualServer(_netscalerService, vserverName);
+            }
+
+            saveConfiguration();
+
+        } catch (Exception e) {
+            String errMsg = "Failed to apply GSLB configuration due to " + e.getMessage();
+            if (shouldRetry(numRetries)) {
+                return retry(gslbCmd, numRetries);
+            }
+            return new GlobalLoadBalancerConfigAnswer(false, errMsg);
+        }
+
+        return new GlobalLoadBalancerConfigAnswer(true, "Successfully applied GSLB configuration.");
+    }
+
+    /*
+     * convenience class to create/update/delete/get the GSLB specific NetScaler objects
+     *     - gslbsite
+     *     - gslbvserver
+     *     - gslbservice
+     *     - vserver-service binding
+     *     - vserver-domain bindings
+     */
+    private static class GSLB {
+
+        // create a 'gslbsite' object representing a site
+        private static void createSite(nitro_service client, String siteName, String siteType, String siteIP, String sitePublicIP) throws ExecutionException {
+            try {
+                gslbsite site;
+                site = getSiteObject(client, siteName);
+
+                boolean isUpdateSite = false;
+                if (site == null) {
+                    site = new gslbsite();
+                } else {
+                    isUpdateSite = true;
+                }
+
+                assert ("LOCAL".equalsIgnoreCase(siteType) || "REMOTE".equalsIgnoreCase(siteType));
+                site.set_sitetype(siteType);
+                site.set_sitename(siteName);
+                site.set_siteipaddress(siteIP);
+                site.set_publicip(sitePublicIP);
+                site.set_metricexchange("ENABLED");
+                site.set_nwmetricexchange("ENABLED");
+                site.set_sessionexchange("ENABLED");
+                if (isUpdateSite) {
+                    gslbsite.update(client, site);
+                } else {
+                    gslbsite.add(client, site);
+                }
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Successfully created GSLB site: " + siteName);
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to create GSLB site: " + siteName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // delete 'gslbsite' object representing a site
+        private static void deleteSite(nitro_service client, String siteName) throws ExecutionException {
+            try {
+                gslbsite site = getSiteObject(client, siteName);
+                if (site != null) {
+                    gslbsite_gslbservice_binding[] serviceBindings = gslbsite_gslbservice_binding.get(client, siteName);
+                    if (serviceBindings != null && serviceBindings.length > 0) {
+                        if (s_logger.isDebugEnabled()) {
+                            s_logger.debug("There are services associated with GSLB site: " + siteName + " so ignoring site deletion");
+                        }
+                    }
+                    gslbsite.delete(client, siteName);
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Successfully deleted GSLB site: " + siteName);
+                    }
+                } else {
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.warn("Ignoring delete request for non existing  GSLB site: " + siteName);
+                    }
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to delete GSLB site: " + siteName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // update 'gslbsite' object representing a site
+        private static void updateSite(nitro_service client, String siteType, String siteName, String siteIP, String sitePublicIP) throws ExecutionException {
+            try {
+                gslbsite site;
+                site = getSiteObject(client, siteName);
+                if (site == null) {
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.warn("Ignoring update request for non existing  GSLB site: " + siteName);
+                    }
+                    return;
+                }
+                assert ("LOCAL".equalsIgnoreCase(siteType) || "REMOTE".equalsIgnoreCase(siteType));
+                site.set_sitetype(siteType);
+                site.set_sitename(siteName);
+                site.set_siteipaddress(siteIP);
+                site.set_publicip(sitePublicIP);
+                site.set_metricexchange("ENABLED");
+                site.set_nwmetricexchange("ENABLED");
+                site.set_sessionexchange("ENABLED");
+                gslbsite.update(client, site);
+
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Successfully updated GSLB site: " + siteName);
+                }
+
+            } catch (Exception e) {
+                String errMsg = "Failed to update GSLB site: " + siteName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // create a 'gslbvserver' object representing a globally load balanced service
+        private static void
+        createVirtualServer(nitro_service client, String vserverName, String lbMethod, String persistenceType, long persistenceId, String serviceType)
+                throws ExecutionException {
+            try {
+                gslbvserver vserver;
+                vserver = getVserverObject(client, vserverName);
+
+                boolean isUpdateSite = false;
+                if (vserver == null) {
+                    vserver = new gslbvserver();
+                } else {
+                    isUpdateSite = true;
+                }
+
+                vserver.set_name(vserverName);
+                if ("RoundRobin".equalsIgnoreCase(lbMethod)) {
+                    vserver.set_lbmethod("ROUNDROBIN");
+                } else if ("LeastConn".equalsIgnoreCase(lbMethod)) {
+                    vserver.set_lbmethod("LEASTCONNECTION");
+                } else if ("Proximity".equalsIgnoreCase(lbMethod)) {
+                    vserver.set_lbmethod("RTT");
+                } else {
+                    throw new ExecutionException("Unsupported LB method");
+                }
+                vserver.set_persistencetype(persistenceType);
+                if ("SOURCEIP".equalsIgnoreCase(persistenceType)) {
+                    vserver.set_persistenceid(persistenceId);
+                }
+                vserver.set_servicetype(serviceType);
+                vserver.set_state("ENABLED");
+                vserver.set_cookietimeout(null);
+                vserver.set_domainname(null);
+                if (isUpdateSite) {
+                    // both netmask and LB method can not be specified while update so set to null
+                    vserver.set_netmask(null);
+                    vserver.set_v6netmasklen(null);
+                    gslbvserver.update(client, vserver);
+                } else {
+                    gslbvserver.add(client, vserver);
+                }
+
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Successfully added GSLB virtual server: " + vserverName);
+                }
+
+            } catch (Exception e) {
+                String errMsg = "Failed to add GSLB virtual server: " + vserverName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // delete 'gslbvserver' object representing a globally load balanced service
+        private static void deleteVirtualServer(nitro_service client, String vserverName) throws ExecutionException {
+            try {
+                gslbvserver vserver = getVserverObject(client, vserverName);
+                if (vserver != null) {
+                    gslbvserver.delete(client, vserver);
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Successfully deleted GSLB virtual server: " + vserverName);
+                    }
+                } else {
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.warn("Ignoring delete request for non existing  GSLB virtual server: " + vserverName);
+                    }
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to delete GSLB virtual server: " + vserverName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // enable 'gslbvserver' object representing a globally load balanced service
+        private static void enableVirtualServer(nitro_service client, String vserverName) throws ExecutionException {
+            try {
+                gslbvserver vserver = getVserverObject(client, vserverName);
+                if (vserver != null) {
+                    gslbvserver.enable(client, vserver);
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to enable GSLB virtual server: " + vserverName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // disable 'gslbvserver' object representing a globally load balanced service
+        private static void disableVirtualServer(nitro_service client, String vserverName) throws ExecutionException {
+            try {
+                gslbvserver vserver = getVserverObject(client, vserverName);
+                if (vserver != null) {
+                    gslbvserver.disable(client, vserver);
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to disable GSLB virtual server: " + vserverName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // update 'gslbvserver' object representing a globally load balanced service
+        private static void updateVirtualServer(nitro_service client, String vserverName, String lbMethod, String persistenceType, String serviceType)
+                throws ExecutionException {
+            try {
+                gslbvserver vServer = getVserverObject(client, vserverName);
+                if (vServer != null) {
+                    vServer.set_lbmethod(lbMethod);
+                    vServer.set_persistencetype(persistenceType);
+                    vServer.set_servicetype(serviceType);
+                    gslbvserver.update(client, vServer);
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Successfully updated GSLB virtual server: " + vserverName);
+                    }
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to update GSLB virtual server: " + vserverName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // create, delete, update, get the GSLB services
+        private static void createService(nitro_service client, String serviceName, String serviceType, String serviceIp, String servicePort, String siteName)
+                throws ExecutionException {
+            try {
+                gslbservice service;
+                service = getServiceObject(client, serviceName);
+                String gslbServerName = generateGslbServerName(serviceIp);
+
+                if (!gslbServerExists(client, gslbServerName)) {
+                    base_response apiCallResult;
+                    com.citrix.netscaler.nitro.resource.config.basic.server nsServer = new com.citrix.netscaler.nitro.resource.config.basic.server();
+                    nsServer.set_name(gslbServerName);
+                    nsServer.set_ipaddress(serviceIp);
+                    apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.add(client, nsServer);
+                    if ((apiCallResult.errorcode != 0) && (apiCallResult.errorcode != NitroError.NS_RESOURCE_EXISTS)) {
+                        throw new ExecutionException("Failed to add server " + gslbServerName + " due to" + apiCallResult.message);
+                    }
+                }
+
+                boolean isUpdateSite = false;
+                if (service == null) {
+                    service = new gslbservice();
+                } else {
+                    isUpdateSite = true;
+                }
+
+                service.set_sitename(siteName);
+                service.set_servername(gslbServerName);
+                int port = Integer.parseInt(servicePort);
+                service.set_port(port);
+                service.set_servicename(serviceName);
+                service.set_servicetype(serviceType);
+                if (isUpdateSite) {
+                    service.set_viewip(null);
+                    service.set_viewname(null);
+                    gslbservice.update(client, service);
+                } else {
+                    gslbservice.add(client, service);
+                }
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Successfully created service: " + serviceName + " at site: " + siteName);
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to created service: " + serviceName + " at site: " + siteName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        private static void deleteService(nitro_service client, String serviceName) throws ExecutionException {
+            try {
+                gslbservice service = getServiceObject(client, serviceName);
+                if (service != null) {
+                    gslbservice.delete(client, serviceName);
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Successfully deleted service: " + serviceName);
+                    }
+                } else {
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.warn("Ignoring delete request for non existing  service: " + serviceName);
+                    }
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to delete service: " + serviceName + " due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        private static void updateService(nitro_service client, String serviceName, String serviceType, String publicIp, String publicPort, String siteName)
+                throws ExecutionException {
+            try {
+                gslbservice service;
+                service = getServiceObject(client, serviceName);
+
+                if (service != null) {
+                    service.set_sitename(siteName);
+                    service.set_publicip(publicIp);
+                    service.set_publicport(Integer.getInteger(publicPort));
+                    service.set_servicename(serviceName);
+                    service.set_servicetype(serviceType);
+                    gslbservice.update(client, service);
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Successfully updated service: " + serviceName + " at site: " + siteName);
+                    }
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to update service: " + serviceName + " at site: " + siteName + "due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        private static void createVserverServiceBinding(nitro_service client, String serviceName, String vserverName, long weight) throws ExecutionException {
+            String errMsg;
+            try {
+                assert (weight >= 1 && weight <= 100);
+                gslbvserver_gslbservice_binding binding = new gslbvserver_gslbservice_binding();
+                binding.set_name(vserverName);
+                binding.set_servicename(serviceName);
+                binding.set_weight(weight);
+                gslbvserver_gslbservice_binding.add(client, binding);
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Successfully created service: " + serviceName + " and virtual server: " + vserverName + " binding");
+                }
+            } catch (nitro_exception ne) {
+                if (ne.getErrorCode() == 273) {
+                    return;
+                }
+                errMsg = "Failed to create service: " + serviceName + " and virtual server: " + vserverName + " binding due to " + ne.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            } catch (Exception e) {
+                errMsg = "Failed to create service: " + serviceName + " and virtual server: " + vserverName + " binding due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        private static void deleteVserverServiceBinding(nitro_service client, String serviceName, String vserverName) throws ExecutionException {
+            try {
+                gslbvserver_gslbservice_binding[] bindings = gslbvserver_gslbservice_binding.get(client, vserverName);
+                if (bindings != null) {
+                    for (gslbvserver_gslbservice_binding binding : bindings) {
+                        if (binding.get_servicename().equalsIgnoreCase(serviceName) && binding.get_name().equals(vserverName)) {
+                            gslbvserver_gslbservice_binding.delete(client, binding);
+                            if (s_logger.isDebugEnabled()) {
+                                s_logger.debug("Successfully deleted service: " + serviceName + " and virtual server: " + vserverName + " binding");
+                            }
+                            break;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to create service: " + serviceName + " and virtual server: " + vserverName + " binding due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        // create, delete GSLB virtual server and domain bindings
+        private static void createVserverDomainBinding(nitro_service client, String vserverName, String domainName) throws ExecutionException {
+            String errMsg;
+            try {
+                gslbvserver_domain_binding binding = new gslbvserver_domain_binding();
+                binding.set_domainname(domainName);
+                binding.set_name(vserverName);
+                gslbvserver_domain_binding.add(client, binding);
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Successfully added virtual server: " + vserverName + " domain name: " + domainName + " binding");
+                }
+                return;
+            } catch (nitro_exception e) {
+                if (e.getErrorCode() == NitroError.NS_GSLB_DOMAIN_ALREADY_BOUND) {
+                    return;
+                }
+                errMsg = e.getMessage();
+            } catch (Exception e) {
+                errMsg = e.getMessage();
+            }
+            errMsg = "Failed to create virtual server: " + vserverName + " domain name: " + domainName + " binding" + errMsg;
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug(errMsg);
+            }
+            throw new ExecutionException(errMsg);
+        }
+
+        private static void deleteVserverDomainBinding(nitro_service client, String vserverName, String domainName) throws ExecutionException {
+            try {
+                gslbvserver_domain_binding[] bindings = gslbvserver_domain_binding.get(client, vserverName);
+                if (bindings != null) {
+                    for (gslbvserver_domain_binding binding : bindings) {
+                        if (binding.get_domainname().equalsIgnoreCase(domainName)) {
+                            gslbvserver_domain_binding.delete(client, binding);
+                            if (s_logger.isDebugEnabled()) {
+                                s_logger.debug("Successfully deleted virtual server: " + vserverName + " and " + " domain: " + domainName + " binding");
+                            }
+                            break;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to delete virtual server: " + vserverName + " and domain " + domainName + " binding due to " + e.getMessage();
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        private static void createGslbServiceMonitor(nitro_service nsService, String servicePublicIp, String serviceName) throws ExecutionException {
+            try {
+                lbmonitor newmonitor = new lbmonitor();
+                String monitorName = generateGslbServiceMonitorName(servicePublicIp);
+                newmonitor.set_type("TCP");
+                newmonitor.set_servicename(serviceName);
+                newmonitor.set_monitorname(monitorName);
+                newmonitor.set_state("ENABLED");
+                lbmonitor.add(nsService, newmonitor);
+            } catch (nitro_exception ne) {
+                if (ne.getErrorCode() == NitroError.NS_RESOURCE_EXISTS) {
+                    return;
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to create GSLB monitor for service public ip" + servicePublicIp;
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(errMsg);
+                }
+                throw new ExecutionException(errMsg);
+            }
+        }
+
+        private static void deleteGslbServiceMonitor(nitro_service nsService, String monitorName) throws ExecutionException {
+            try {
+                lbmonitor serviceMonitor = lbmonitor.get(nsService, monitorName);
+                if (serviceMonitor != null) {
+                    lbmonitor.delete(nsService, serviceMonitor);
+                }
+            } catch (nitro_exception ne) {
+                if (ne.getErrorCode() != NitroError.NS_RESOURCE_NOT_EXISTS) {
+                    String errMsg = "Failed to delete monitor " + monitorName + " for GSLB service due to " + ne.getMessage();
+                    s_logger.debug(errMsg);
+                    throw new com.cloud.utils.exception.ExecutionException(errMsg);
+                }
+            } catch (Exception e) {
+                String errMsg = "Failed to delete monitor " + monitorName + " for GSLB service due to " + e.getMessage();
+                s_logger.debug(errMsg);
+                throw new com.cloud.utils.exception.ExecutionException(errMsg);
+            }
+        }
+
+        private static void createGslbServiceGslbMonitorBinding(nitro_service nsService, String monitorName, String serviceName) {
+            try {
+                gslbservice_lbmonitor_binding monitorBinding = new gslbservice_lbmonitor_binding();
+                monitorBinding.set_monitor_name(monitorName);
+                monitorBinding.set_servicename(serviceName);
+                gslbservice_lbmonitor_binding.add(nsService, monitorBinding);
+            } catch (Exception e) {
+                // TODO: Nitro API version 10.* is not compatible for NetScalers 9.*, so may fail
+                // against NetScaler version lesser than 10 hence ignore the exception
+                s_logger.warn("Failed to bind monitor to GSLB service due to " + e.getMessage());
+            }
+        }
+
+        private static void deleteGslbServiceGslbMonitorBinding(nitro_service nsService, String monitorName, String serviceName) {
+            try {
+                gslbservice_lbmonitor_binding[] monitorBindings = gslbservice_lbmonitor_binding.get(nsService, serviceName);
+                if (monitorBindings != null && monitorBindings.length > 0) {
+                    for (gslbservice_lbmonitor_binding binding : monitorBindings) {
+                        if (binding.get_monitor_name().equalsIgnoreCase(monitorName)) {
+                            s_logger.info("Found a binding between monitor " + binding.get_monitor_name() + " and " + binding.get_servicename());
+                            gslbservice_lbmonitor_binding.delete(nsService, binding);
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                s_logger.debug("Failed to delete GSLB monitor " + monitorName + " and GSLB service " + serviceName + " binding due to " + e.getMessage() +
+                        " but moving on ..., will be cleaned up as part of GSLB " + " service delete any way..");
+            }
+        }
+
+        // get 'gslbsite' object corresponding to a site name
+        private static gslbsite getSiteObject(nitro_service client, String siteName) {
+            try {
+                gslbsite site = gslbsite.get(client, siteName);
+                if (site != null) {
+                    return site;
+                }
+            } catch (Exception e) {
+
+            }
+            return null;
+        }
+
+        private static gslbvserver getVserverObject(nitro_service client, String vserverName) {
+            try {
+                gslbvserver vserver = gslbvserver.get(client, vserverName);
+                return vserver;
+            } catch (Exception e) {
+                return null;
+            }
+        }
+
+        private static gslbservice getServiceObject(nitro_service client, String serviceName) {
+            try {
+                gslbservice service = gslbservice.get(client, serviceName);
+                return service;
+            } catch (Exception e) {
+                return null;
+            }
+        }
+
+        private static String generateUniqueSiteName(String sitePrivateIp, String sitePublicIP, long dataCenterId) {
+            return "cloudsite" + String.valueOf(dataCenterId);
+        }
+
+        private static String generateVirtualServerName(String domainName) {
+            return "cloud-gslb-vserver-" + domainName;
+        }
+
+        private static String generateUniqueServiceName(String siteName, String publicIp, String publicPort) {
+            return "cloud-gslb-service-" + siteName + "-" + publicIp + "-" + publicPort;
+        }
+
+        private static String generateGslbServiceMonitorName(String publicIp) {
+            return "cloud-monitor-" + publicIp;
+        }
+
+        private static boolean gslbServerExists(nitro_service client, String serverName) throws ExecutionException {
+            try {
+                if (com.citrix.netscaler.nitro.resource.config.basic.server.get(client, serverName) != null) {
+                    return true;
+                } else {
+                    return false;
+                }
+            } catch (nitro_exception e) {
+                if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                    return false;
+                } else {
+                    throw new ExecutionException("Failed to verify Server " + serverName + " exists on the NetScaler device due to " + e.getMessage());
+                }
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to verify Server " + serverName + " exists on the NetScaler device due to " + e.getMessage());
+            }
+        }
+
+        private static String generateGslbServerName(String serverIP) {
+            return genGslbObjectName("Cloud-Server-", serverIP);
+        }
+
+        private static String genGslbObjectName(Object... args) {
+            StringBuffer buff = new StringBuffer();
+            for (int i = 0; i < args.length; i++) {
+                buff.append(args[i]);
+                if (i != args.length - 1) {
+                    buff.append("-");
+                }
+            }
+            return buff.toString();
+        }
+    }
+
+    /* SSL Termination */
+    private static class SSL {
+
+        private static final String SSL_CERT_PATH = "/nsconfig/ssl/";
+        private static final int SSH_PORT = 22;
+
+        private static boolean isSslCertKeyPresent(nitro_service ns, String certKeyName) throws ExecutionException {
+
+            String filter = "certkey:" + certKeyName;
+
+            try {
+                if (sslcertkey.count_filtered(ns, filter) > 0)
+                    return true;
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to get certkey " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to get certkey " + e.getMessage());
+            }
+
+            return false;
+        }
+
+        private static void deleteSslCertKey(nitro_service ns, String certKeyName) throws ExecutionException {
+            try {
+
+                sslcertkey certkey = new sslcertkey();
+                certkey.set_certkey(certKeyName);
+                sslcertkey.delete(ns, certkey);
+
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to delete certkey " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to delete certkey " + e.getMessage());
+            }
+
+        }
+
+        private static void deleteCertFile(String nsIp, String username, String password, String certFilename) throws Exception {
+            SshHelper.sshExecute(nsIp, SSH_PORT, username, null, password, "shell rm " + SSL_CERT_PATH + certFilename);
+        }
+
+        private static void deleteKeyFile(String nsIp, String username, String password, String keyFilename) throws Exception {
+            SshHelper.sshExecute(nsIp, SSH_PORT, username, null, password, "shell rm " + SSL_CERT_PATH + keyFilename);
+        }
+
+        private static void createSslCertKey(nitro_service ns, String certFilename, String keyFilename, String certKeyName, String password) throws ExecutionException {
+            s_logger.debug("Adding cert to netscaler");
+            try {
+                sslcertkey certkey = new sslcertkey();
+                certkey.set_certkey(certKeyName);
+                certkey.set_cert(SSL_CERT_PATH + certFilename);
+
+                if (keyFilename != null)
+                    certkey.set_key(SSL_CERT_PATH + keyFilename);
+
+                if (password != null) {
+                    certkey.set_passplain(password);
+                }
+
+                certkey.perform_operation(ns);
+
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to add certkey binding " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to add certkey binding " + e.getMessage());
+            }
+
+        }
+
+        public static void updateCertKey(nitro_service ns, String certKeyName, String cert, String key, String password) throws ExecutionException {
+            try {
+                sslcertkey certkey = sslcertkey.get(ns, certKeyName);
+                if (cert != null)
+                    certkey.set_cert(cert);
+                if (key != null)
+                    certkey.set_key(cert);
+                if (password != null)
+                    certkey.set_passplain(cert);
+
+                sslcertkey.change(ns, certkey);
+
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to update ssl on load balancer due to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to update ssl on load balancer due to " + e.getMessage());
+            }
+        }
+
+        private static void bindCertKeyToVserver(nitro_service ns, String certKeyName, String vserver) throws ExecutionException {
+            s_logger.debug("Adding cert to netscaler");
+
+            try {
+                sslvserver_sslcertkey_binding cert_binding = new sslvserver_sslcertkey_binding();
+                cert_binding.set_certkeyname(certKeyName);
+                cert_binding.set_vservername(vserver);
+                cert_binding.perform_operation(ns);
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to bind certkey to vserver due to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to bind certkey to vserver due to " + e.getMessage());
+            }
+        }
+
+        private static void unbindCertKeyFromVserver(nitro_service ns, String certKeyName, String vserver) throws ExecutionException {
+            try {
+
+                sslvserver_sslcertkey_binding cert_binding = new sslvserver_sslcertkey_binding();
+                cert_binding.set_certkeyname(certKeyName);
+                cert_binding.set_vservername(vserver);
+                sslvserver_sslcertkey_binding.delete(ns, cert_binding);
+
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to unbind certkey to vserver due to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to unbind certkey to vserver due to " + e.getMessage());
+            }
+
+        }
+
+        private static void uploadCert(String nsIp, String user, String password, String certFilename, byte[] certData) throws ExecutionException {
+            try {
+                SshHelper.scpTo(nsIp, SSH_PORT, user, null, password, SSL_CERT_PATH, certData, certFilename, null);
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to copy private key to device " + e.getMessage());
+            }
+        }
+
+        private static void uploadKey(String nsIp, String user, String password, String keyFilename, byte[] keyData) throws ExecutionException {
+            try {
+                SshHelper.scpTo(nsIp, SSH_PORT, user, null, password, SSL_CERT_PATH, keyData, keyFilename, null);
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to copy private key to device " + e.getMessage());
+            }
+        }
+
+        private static void enableSslFeature(nitro_service ns, boolean isSdx) throws ExecutionException {
+            if (isSdx) {
+                return;
+            }
+            try {
+                base_response result = ns.enable_features(new String[] {"SSL"});
+                if (result.errorcode != 0)
+                    throw new ExecutionException("Unable to enable SSL on LB");
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to enable ssl feature on load balancer due to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to enable ssl feature on load balancer due to " + e.getMessage());
+            }
+        }
+
+        public static boolean checkSslFeature(nitro_service ns) throws ExecutionException {
+            try {
+                String[] features = ns.get_enabled_features();
+                if (features != null) {
+                    for (String feature : features) {
+                        if (feature.equalsIgnoreCase("SSL")) {
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to check ssl feature on load balancer due to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to check ssl feature on load balancer due to " + e.getMessage());
+            }
+        }
+
+        public static boolean certLinkExists(nitro_service ns, String userCertName, String caCertName) throws ExecutionException {
+            try {
+                // check if there is a link from userCertName to caCertName
+
+                sslcertkey userCert = sslcertkey.get(ns, userCertName);
+                String nsCaCert = userCert.get_linkcertkeyname();
+
+                if (nsCaCert != null && nsCaCert.equals(caCertName))
+                    return true;
+
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage());
+            }
+            return false;
+        }
+
+        public static void linkCerts(nitro_service ns, String userCertName, String caCertName) throws ExecutionException {
+            try {
+
+                // the assumption is that that both userCertName and caCertName are present on NS
+
+                sslcertkey caCert = sslcertkey.get(ns, caCertName);
+                sslcertkey userCert = sslcertkey.get(ns, userCertName);
+
+                sslcertkey linkResource = new sslcertkey();
+
+                // link user cert to CA cert
+                linkResource.set_certkey(userCert.get_certkey());
+                linkResource.set_linkcertkeyname(caCert.get_certkey());
+                sslcertkey.link(ns, linkResource);
+
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage());
+            }
+
+        }
+
+        public static boolean isCaforCerts(nitro_service ns, String caCertName) throws ExecutionException {
+            // check if this certificate  serves as a CA for other certificates
+            try {
+                sslcertlink[] childLinks = sslcertlink.get_filtered(ns, "linkcertkeyname:" + caCertName);
+                if (childLinks != null && childLinks.length > 0) {
+                    return true;
+                }
+
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage());
+            }
+            return false;
+
+        }
+
+        public static boolean isBoundToVserver(nitro_service ns, String certKeyName, String nsVirtualServerName) throws ExecutionException {
+            try {
+
+                sslcertkey_sslvserver_binding[] cert_vs_binding = sslcertkey_sslvserver_binding.get_filtered(ns, certKeyName, "vservername:" + nsVirtualServerName);
+                if (cert_vs_binding != null && cert_vs_binding.length > 0) {
+                    return true;
+                }
+
+            } catch (nitro_exception e) {
+                throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage());
+            } catch (Exception e) {
+                throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage());
+            }
+            return false;
+
+        }
+    }
+
+    private void enableVPXInterfaces(String publicIf, String privateIf, ns nsObj) {
+        // enable VPX to use 10 gigabit Ethernet interfaces if public/private interface
+        // on SDX is a 10Gig interface
+        if (publicIf.equals("10/1") || privateIf.equals("10/1")) {
+            nsObj.set_if_10_1(new Boolean(true));
+        }
+
+        if (publicIf.equals("10/2") || privateIf.equals("10/2")) {
+            nsObj.set_if_10_2(new Boolean(true));
+        }
+
+        if (publicIf.equals("10/3") || privateIf.equals("10/3")) {
+            nsObj.set_if_10_3(new Boolean(true));
+        }
+
+        if (publicIf.equals("10/4") || privateIf.equals("10/4")) {
+            nsObj.set_if_10_4(new Boolean(true));
+        }
+
+        if (publicIf.equals("10/5") || privateIf.equals("10/5")) {
+            nsObj.set_if_10_5(new Boolean(true));
+        }
+
+        if (publicIf.equals("10/6") || privateIf.equals("10/6")) {
+            nsObj.set_if_10_6(new Boolean(true));
+        }
+
+        if (publicIf.equals("10/7") || privateIf.equals("10/7")) {
+            nsObj.set_if_10_7(new Boolean(true));
+        }
+
+        if (publicIf.equals("10/8") || privateIf.equals("10/8")) {
+            nsObj.set_if_10_8(new Boolean(true));
+        }
+
+        // enable VPX to use 1 gigabit Ethernet interfaces if public/private interface
+        // on SDX is a 1Gig interface
+        if (publicIf.equals("1/1") || privateIf.equals("1/1")) {
+            nsObj.set_if_1_1(new Boolean(true));
+        }
+
+        if (publicIf.equals("1/2") || privateIf.equals("1/2")) {
+            nsObj.set_if_1_2(new Boolean(true));
+        }
+
+        if (publicIf.equals("1/3") || privateIf.equals("1/3")) {
+            nsObj.set_if_1_3(new Boolean(true));
+        }
+
+        if (publicIf.equals("1/4") || privateIf.equals("1/4")) {
+            nsObj.set_if_1_4(new Boolean(true));
+        }
+
+        if (publicIf.equals("1/5") || privateIf.equals("1/5")) {
+            nsObj.set_if_1_5(new Boolean(true));
+        }
+
+        if (publicIf.equals("1/6") || privateIf.equals("1/6")) {
+            nsObj.set_if_1_6(new Boolean(true));
+        }
+
+        if (publicIf.equals("1/7") || privateIf.equals("1/7")) {
+            nsObj.set_if_1_7(new Boolean(true));
+        }
+
+        if (publicIf.equals("1/8") || privateIf.equals("1/8")) {
+            nsObj.set_if_1_8(new Boolean(true));
+        }
+    }
+
+    private synchronized Answer execute(DestroyLoadBalancerApplianceCommand cmd, int numRetries) {
+        String vpxName = "Cloud-VPX-" + cmd.getLoadBalancerIP();
+        if (!_isSdx) {
+            return Answer.createUnsupportedCommandAnswer(cmd);
+        }
+
+        try {
+            ns vpxToDelete = null;
+            ns[] vpxInstances = ns.get(_netscalerSdxService);
+            for (ns vpx : vpxInstances) {
+                if (vpx.get_name().equals(vpxName)) {
+                    vpxToDelete = vpx;
+                    break;
+                }
+            }
+
+            if (vpxToDelete == null) {
+                String msg = "There is no VPX instance " + vpxName + " on the Netscaler SDX device " + _ip + " to delete";
+                s_logger.warn(msg);
+                return new DestroyLoadBalancerApplianceAnswer(cmd, true, msg);
+            }
+
+            // destroy the VPX instance
+            ns nsDelObj = new ns();
+            nsDelObj.set_id(vpxToDelete.get_id());
+            vpxToDelete = ns.delete(_netscalerSdxService, nsDelObj);
+            String msg = "Deleted VPX instance " + vpxName + " on Netscaler SDX " + _ip + " successfully.";
+            s_logger.info(msg);
+            return new DestroyLoadBalancerApplianceAnswer(cmd, true, msg);
+        } catch (Exception e) {
+            if (shouldRetry(numRetries)) {
+                return retry(cmd, numRetries);
+            }
+            return new DestroyLoadBalancerApplianceAnswer(cmd, false, "Failed to delete VPX instance " + vpxName + " on Netscaler SDX " + _ip);
+        }
+    }
+
+    private synchronized Answer execute(SetStaticNatRulesCommand cmd, int numRetries) {
+
+        if (_isSdx) {
+            return Answer.createUnsupportedCommandAnswer(cmd);
+        }
+
+        String[] results = new String[cmd.getRules().length];
+        int i = 0;
+        boolean endResult = true;
+
+        try {
+            for (StaticNatRuleTO rule : cmd.getRules()) {
+                String srcIp = rule.getSrcIp();
+                String dstIP = rule.getDstIp();
+                String iNatRuleName = generateInatRuleName(srcIp, dstIP);
+                String rNatRuleName = generateRnatRuleName(srcIp, dstIP);
+                inat iNatRule = null;
+                rnat rnatRule = null;
+
+                if (!rule.revoked()) {
+                    try {
+                        iNatRule = inat.get(_netscalerService, iNatRuleName);
+                    } catch (nitro_exception e) {
+                        if (e.getErrorCode() != NitroError.NS_RESOURCE_NOT_EXISTS) {
+                            throw e;
+                        }
+                    }
+
+                    if (iNatRule == null) {
+                        iNatRule = new inat();
+                        iNatRule.set_name(iNatRuleName);
+                        iNatRule.set_publicip(srcIp);
+                        iNatRule.set_privateip(dstIP);
+                        iNatRule.set_usnip("OFF");
+                        iNatRule.set_usip("ON");
+                        try {
+                            apiCallResult = inat.add(_netscalerService, iNatRule);
+                        } catch (nitro_exception e) {
+                            if (e.getErrorCode() != NitroError.NS_RESOURCE_EXISTS) {
+                                throw e;
+                            }
+                        }
+                        s_logger.debug("Created Inat rule on the Netscaler device " + _ip + " to enable static NAT from " + srcIp + " to " + dstIP);
+                    }
+                    try {
+                        rnat[] rnatRules = rnat.get(_netscalerService);
+                        if (rnatRules != null) {
+                            for (rnat rantrule : rnatRules) {
+                                if (rantrule.get_network().equalsIgnoreCase(rNatRuleName)) {
+                                    rnatRule = rantrule;
+                                    break;
+                                }
+                            }
+                        }
+                    } catch (nitro_exception e) {
+                        throw e;
+                    }
+
+                    if (rnatRule == null) {
+                        rnatRule = new rnat();
+                        rnatRule.set_natip(srcIp);
+                        rnatRule.set_network(dstIP);
+                        rnatRule.set_netmask("255.255.255.255");
+                        try {
+                            apiCallResult = rnat.update(_netscalerService, rnatRule);
+                        } catch (nitro_exception e) {
+                            if (e.getErrorCode() != NitroError.NS_RESOURCE_EXISTS) {
+                                throw e;
+                            }
+                        }
+                        s_logger.debug("Created Rnat rule on the Netscaler device " + _ip + " to enable revese static NAT from " + dstIP + " to " + srcIp);
+                    }
+                } else {
+                    try {
+                        inat.delete(_netscalerService, iNatRuleName);
+                        rnat[] rnatRules = rnat.get(_netscalerService);
+                        if (rnatRules != null) {
+                            for (rnat rantrule : rnatRules) {
+                                if (rantrule.get_network().equalsIgnoreCase(dstIP)) {
+                                    rnatRule = rantrule;
+                                    rnat.clear(_netscalerService, rnatRule);
+                                    break;
+                                }
+                            }
+                        }
+                    } catch (nitro_exception e) {
+                        if (e.getErrorCode() != NitroError.NS_RESOURCE_NOT_EXISTS) {
+                            throw e;
+                        }
+                    }
+                    s_logger.debug("Deleted Inat rule on the Netscaler device " + _ip + " to remove static NAT from " + srcIp + " to " + dstIP);
+                }
+
+                saveConfiguration();
+                results[i++] = "Static nat rule from " + srcIp + " to " + dstIP + " successfully " + (rule.revoked() ? " revoked." : " created.");
+            }
+        } catch (Exception e) {
+            if (shouldRetry(numRetries)) {
+                return retry(cmd, numRetries);
+            }
+            results[i++] = "Configuring static nat rule failed due to " + e.getMessage();
+            endResult = false;
+            return new SetStaticNatRulesAnswer(cmd, results, endResult);
+        }
+
+        return new SetStaticNatRulesAnswer(cmd, results, endResult);
+    }
+
+    private synchronized Answer execute(ExternalNetworkResourceUsageCommand cmd, int numRetries) {
+        try {
+            if (!_isSdx) {
+                return getPublicIpBytesSentAndReceived(cmd);
+            } else {
+                return Answer.createUnsupportedCommandAnswer(cmd);
+            }
+        } catch (ExecutionException e) {
+            if (shouldRetry(numRetries)) {
+                return retry(cmd, numRetries);
+            } else {
+                return new ExternalNetworkResourceUsageAnswer(cmd, e);
+            }
+        }
+    }
+
+    private void addSubnetIP(String snip, String netmask) throws ExecutionException {
+        try {
+            nsip selfIp = new nsip();
+            selfIp.set_ipaddress(snip);
+            selfIp.set_netmask(netmask);
+            selfIp.set_type("SNIP");
+            apiCallResult = nsip.add(_netscalerService, selfIp);
+            if (apiCallResult.errorcode != 0) {
+                throw new ExecutionException("Failed to add SNIP object on the Netscaler device due to " + apiCallResult.message);
+            }
+        } catch (nitro_exception e) {
+            throw new ExecutionException("Failed to add SNIP object on the Netscaler device due to " + e.getMessage());
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to add SNIP object on the Netscaler device due to " + e.getMessage());
+        }
+    }
+
+    private void addGuestVlanAndSubnet(long vlanTag, String vlanSelfIp, String vlanNetmask, boolean guestVlan) throws ExecutionException {
+        try {
+            // add vlan object for guest VLAN
+            if (!nsVlanExists(vlanTag)) {
+                try {
+                    vlan vlanObj = new vlan();
+                    vlanObj.set_id(vlanTag);
+                    apiCallResult = vlan.add(_netscalerService, vlanObj);
+                    if (apiCallResult.errorcode != 0) {
+                        throw new ExecutionException("Failed to add new vlan with tag:" + vlanTag + "on the NetScaler device due to " + apiCallResult.message);
+                    }
+                } catch (nitro_exception e) {
+                    throw new ExecutionException("Failed to add new vlan with tag:" + vlanTag + "on the NetScaler device due to " + e.getMessage());
+                }
+            }
+
+            // add subnet IP object for this guest network
+            if (!nsSnipExists(vlanSelfIp)) {
+                try {
+                    nsip selfIp = new nsip();
+                    selfIp.set_ipaddress(vlanSelfIp);
+                    selfIp.set_netmask(vlanNetmask);
+                    selfIp.set_type("SNIP");
+                    apiCallResult = nsip.add(_netscalerService, selfIp);
+                    if (apiCallResult.errorcode != 0) {
+                        throw new ExecutionException("Failed to add SNIP object for the guest network on the Netscaler device due to " + apiCallResult.message);
+                    }
+                } catch (nitro_exception e) {
+                    throw new ExecutionException("Failed to add SNIP object for the guest network on the Netscaler device due to " + e.getMessage());
+                }
+            }
+
+            // bind the vlan object to subnet IP object
+            if (!nsVlanNsipBindingExists(vlanTag, vlanSelfIp)) {
+                try {
+                    vlan_nsip_binding ipVlanBinding = new vlan_nsip_binding();
+                    ipVlanBinding.set_id(vlanTag);
+                    ipVlanBinding.set_ipaddress(vlanSelfIp);
+                    ipVlanBinding.set_netmask(vlanNetmask);
+                    apiCallResult = vlan_nsip_binding.add(_netscalerService, ipVlanBinding);
+                    if (apiCallResult.errorcode != 0) {
+                        throw new ExecutionException("Failed to bind VLAN with tag:" + vlanTag + " to the subnet due to " + apiCallResult.message);
+                    }
+                } catch (nitro_exception e) {
+                    throw new ExecutionException("Failed to bind VLAN with tage:" + vlanTag + " to the subnet due to " + e.getMessage());
+                }
+            }
+
+            // bind vlan object to the private interface
+            try {
+                vlan_interface_binding vlanBinding = new vlan_interface_binding();
+                if (guestVlan) {
+                    vlanBinding.set_ifnum(_privateInterface);
+                } else {
+                    vlanBinding.set_ifnum(_publicInterface);
+                }
+                vlanBinding.set_tagged(true);
+                vlanBinding.set_id(vlanTag);
+                apiCallResult = vlan_interface_binding.add(_netscalerService, vlanBinding);
+                if (apiCallResult.errorcode != 0) {
+                    String vlanInterface = guestVlan ? _privateInterface : _publicInterface;
+                    throw new ExecutionException("Failed to bind vlan with tag:" + vlanTag + " with the interface " + vlanInterface + " due to " + apiCallResult.message);
+                }
+            } catch (nitro_exception e) {
+                if (!(e.getErrorCode() == NitroError.NS_INTERFACE_ALREADY_BOUND_TO_VLAN)) {
+                    throw new ExecutionException("Failed to bind VLAN " + vlanTag + " with interface on the Netscaler device due to " + e.getMessage());
+                }
+            }
+        } catch (nitro_exception e) {
+            throw new ExecutionException("Failed to implement guest network on the Netscaler device due to " + e.getMessage());
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to implement guest network on the Netscaler device due to " + e.getMessage());
+        }
+    }
+
+    private void deleteGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask) throws ExecutionException {
+        try {
+
+            // Delete all servers and associated services from this guest VLAN
+            deleteServersInGuestVlan(vlanTag, vlanSelfIp, vlanNetmask);
+
+            // unbind vlan to the private interface
+            try {
+                vlan_interface_binding vlanIfBinding = new vlan_interface_binding();
+                vlanIfBinding.set_id(vlanTag);
+                vlanIfBinding.set_ifnum(_privateInterface);
+                vlanIfBinding.set_tagged(true);
+                apiCallResult = vlan_interface_binding.delete(_netscalerService, vlanIfBinding);
+                if (apiCallResult.errorcode != 0) {
+                    throw new ExecutionException("Failed to unbind vlan:" + vlanTag + " with the private interface due to " + apiCallResult.message);
+                }
+            } catch (nitro_exception e) {
+                // if Vlan to interface binding does not exist then ignore the exception and proceed
+                if (!(e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS)) {
+                    throw new ExecutionException("Failed to unbind vlan from the interface while shutdown of guest network on the Netscaler device due to " +
+                            e.getMessage());
+                }
+            }
+
+            // unbind the vlan to subnet
+            try {
+                vlan_nsip_binding vlanSnipBinding = new vlan_nsip_binding();
+                vlanSnipBinding.set_netmask(vlanNetmask);
+                vlanSnipBinding.set_ipaddress(vlanSelfIp);
+                vlanSnipBinding.set_id(vlanTag);
+                apiCallResult = vlan_nsip_binding.delete(_netscalerService, vlanSnipBinding);
+                if (apiCallResult.errorcode != 0) {
+                    throw new ExecutionException("Failed to unbind vlan:" + vlanTag + " with the subnet due to " + apiCallResult.message);
+                }
+            } catch (nitro_exception e) {
+                // if Vlan to subnet binding does not exist then ignore the exception and proceed
+                if (!(e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS)) {
+                    throw new ExecutionException("Failed to unbind vlan:" + vlanTag + " with the subnet due to " + e.getMessage());
+                }
+            }
+
+            // remove subnet IP
+            try {
+                nsip _vlanSelfIp = new nsip();
+                _vlanSelfIp.set_ipaddress(vlanSelfIp);
+
+                nsip subnetIp = nsip.get(_netscalerService, _vlanSelfIp);
+                apiCallResult = nsip.delete(_netscalerService, subnetIp);
+                if (apiCallResult.errorcode != 0) {
+                    throw new ExecutionException("Failed to remove subnet ip:" + vlanSelfIp + " from the NetScaler device due to" + apiCallResult.message);
+                }
+            } catch (nitro_exception e) {
+                // if subnet SNIP does not exist then ignore the exception and proceed
+                if (!(e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS)) {
+                    throw new ExecutionException("Failed to remove subnet ip:" + vlanSelfIp + " from the NetScaler device due to" + e.getMessage());
+                }
+            }
+
+            // remove the vlan from the NetScaler device
+            if (nsVlanExists(vlanTag)) {
+                // remove vlan
+                apiCallResult = com.citrix.netscaler.nitro.resource.config.network.vlan.delete(_netscalerService, vlanTag);
+                if (apiCallResult.errorcode != 0) {
+                    throw new ExecutionException("Failed to remove vlan with tag:" + vlanTag + "due to" + apiCallResult.message);
+                }
+            }
+        } catch (nitro_exception e) {
+            throw new ExecutionException("Failed to delete guest vlan network on the Netscaler device due to " + e.getMessage());
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to delete guest vlan network on the Netscaler device due to " + e.getMessage());
+        }
+    }
+
+    private boolean nsVlanExists(long vlanTag) throws ExecutionException {
+        try {
+            if (vlan.get(_netscalerService, new Long(vlanTag)) != null) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return false;
+            } else {
+                throw new ExecutionException("Failed to verify  VLAN exists on the NetScaler device due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify  VLAN exists on the NetScaler device due to " + e.getMessage());
+        }
+    }
+
+    private boolean nsSnipExists(String subnetIp) throws ExecutionException {
+        try {
+            nsip _subnetIp = new nsip();
+            _subnetIp.set_ipaddress(subnetIp);
+
+            nsip snip = nsip.get(_netscalerService, _subnetIp);
+            return (snip != null);
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return false;
+            } else {
+                throw new ExecutionException("Failed to verify if SNIP exists on the NetScaler device due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify if SNIP exists on the NetScaler device due to " + e.getMessage());
+        }
+    }
+
+    private boolean nsServerExists(String serverName) throws ExecutionException {
+        try {
+            if (com.citrix.netscaler.nitro.resource.config.basic.server.get(_netscalerService, serverName) != null) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return false;
+            } else {
+                throw new ExecutionException("Failed to verify Server " + serverName + " exists on the NetScaler device due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify Server " + serverName + " exists on the NetScaler device due to " + e.getMessage());
+        }
+    }
+
+    private boolean nsVirtualServerExists(String vserverName) throws ExecutionException {
+        try {
+            if (com.citrix.netscaler.nitro.resource.config.lb.lbvserver.get(_netscalerService, vserverName) != null) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return false;
+            } else {
+                throw new ExecutionException("Failed to verify VServer " + vserverName + " exists on the NetScaler device due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify VServer " + vserverName + " exists on the NetScaler device due to " + e.getMessage());
+        }
+    }
+
+    private boolean nsVlanNsipBindingExists(long vlanTag, String vlanSelfIp) throws ExecutionException {
+        try {
+            vlan_nsip_binding[] vlanNsipBindings = vlan_nsip_binding.get(_netscalerService, vlanTag);
+            if (vlanNsipBindings != null && vlanNsipBindings[0] != null && vlanNsipBindings[0].get_ipaddress().equalsIgnoreCase(vlanSelfIp)) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return false;
+            } else {
+                throw new ExecutionException("Failed to verify Vlan " + vlanTag + " to SNIP " + vlanSelfIp + " binding exists due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify Vlan " + vlanTag + " to SNIP " + vlanSelfIp + " binding exists due to " + e.getMessage());
+        }
+    }
+
+    private lbvserver getVirtualServerIfExisits(String lbVServerName) throws ExecutionException {
+        try {
+            return lbvserver.get(_netscalerService, lbVServerName);
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return null;
+            } else {
+                throw new ExecutionException(e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException(e.getMessage());
+        }
+    }
+
+    private lbmonitor getMonitorIfExisits(String lbMonitorName) throws ExecutionException {
+        try {
+            return lbmonitor.get(_netscalerService, lbMonitorName);
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return null;
+            } else {
+                throw new ExecutionException(e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException(e.getMessage());
+        }
+    }
+
+    private boolean isServiceBoundToVirtualServer(String serviceName) throws ExecutionException {
+        try {
+            lbvserver[] lbservers = lbvserver.get(_netscalerService);
+            for (lbvserver vserver : lbservers) {
+                filtervalue[] filter = new filtervalue[1];
+                filter[0] = new filtervalue("servicename", serviceName);
+                lbvserver_service_binding[] result = lbvserver_service_binding.get_filtered(_netscalerService, vserver.get_name(), filter);
+                if (result != null && result.length > 0) {
+                    return true;
+                }
+            }
+            return false;
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify service " + serviceName + " is bound to any virtual server due to " + e.getMessage());
+        }
+    }
+
+    private boolean isServiceBoundToMonitor(String nsServiceName, String nsMonitorName) throws ExecutionException {
+
+        filtervalue[] filter = new filtervalue[1];
+        filter[0] = new filtervalue("monitor_name", nsMonitorName);
+        service_lbmonitor_binding[] result;
+        try {
+            result = service_lbmonitor_binding.get_filtered(_netscalerService, nsServiceName, filter);
+            if (result != null && result.length > 0) {
+                return true;
+            }
+
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify service " + nsServiceName + " is bound to any monitor due to " + e.getMessage());
+        }
+        return false;
+    }
+
+    private boolean nsMonitorExist(String nsMonitorname) throws ExecutionException {
+        if (getMonitorIfExisits(nsMonitorname) != null)
+            return true;
+        else
+            return false;
+    }
+
+    private boolean nsServiceExists(String serviceName) throws ExecutionException {
+        try {
+            if (com.citrix.netscaler.nitro.resource.config.basic.service.get(_netscalerService, serviceName) != null) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_NO_SERIVCE) {
+                return false;
+            } else {
+                throw new ExecutionException("Failed to verify service " + serviceName + " exists due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify service " + serviceName + " exists due to " + e.getMessage());
+        }
+    }
+
+    private boolean nsServiceBindingExists(String lbVirtualServer, String serviceName) throws ExecutionException {
+        try {
+            com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding[] serviceBindings =
+                    com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.get(_netscalerService, lbVirtualServer);
+            if (serviceBindings != null) {
+                for (com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding binding : serviceBindings) {
+                    if (serviceName.equalsIgnoreCase(binding.get_servicename())) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        } catch (nitro_exception e) {
+            throw new ExecutionException("Failed to verify lb vserver " + lbVirtualServer + "and service " + serviceName + " binding exists due to " + e.getMessage());
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify lb vserver " + lbVirtualServer + "and service " + serviceName + " binding exists due to " + e.getMessage());
+        }
+    }
+
+    private boolean isServiceGroupBoundToVirtualServer(String nsVirtualServerName, String serviceGroupName) throws ExecutionException {
+
+        new lbvserver_servicegroup_binding();
+
+        try {
+            lbvserver_servicegroup_binding[] result =
+                    lbvserver_servicegroup_binding.get_filtered(_netscalerService, nsVirtualServerName, "servicegroupname:" + serviceGroupName);
+            if (result != null && result.length > 0) {
+                return true;
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to verify lb vserver " + nsVirtualServerName + "and servicegrop " + serviceGroupName + " binding exists due to " +
+                    e.getMessage());
+        }
+        return false;
+
+    }
+
+    private boolean nsServiceGroupExists(String lbVServerName) throws ExecutionException {
+        try {
+            return servicegroup.get(_netscalerService, lbVServerName) != null;
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return false; // service group does not exist
+            } else {
+                throw new ExecutionException(e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException(e.getMessage());
+        }
+    }
+
+    private void deleteServersInGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask) throws ExecutionException {
+        try {
+            com.citrix.netscaler.nitro.resource.config.basic.server[] serverList = com.citrix.netscaler.nitro.resource.config.basic.server.get(_netscalerService);
+
+            if (serverList == null) {
+                return;
+            }
+
+            // remove the server and services associated with guest vlan
+            for (com.citrix.netscaler.nitro.resource.config.basic.server server : serverList) {
+                // check if server belong to same subnet as one associated with vlan
+                if (NetUtils.sameSubnet(vlanSelfIp, server.get_ipaddress(), vlanNetmask)) {
+                    // first remove services associated with this server
+                    com.citrix.netscaler.nitro.resource.config.basic.service serveicesList[] =
+                            com.citrix.netscaler.nitro.resource.config.basic.service.get(_netscalerService);
+                    if (serveicesList != null) {
+                        for (com.citrix.netscaler.nitro.resource.config.basic.service svc : serveicesList) {
+                            if (svc.get_servername().equals(server.get_ipaddress())) {
+                                apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.service.delete(_netscalerService, svc.get_name());
+                                if (apiCallResult.errorcode != 0) {
+                                    throw new ExecutionException("Failed to remove service:" + svc.get_name());
+                                }
+                            }
+                        }
+                    }
+                    // remove the server
+                    // don't delete server which has no ip address (these servers are created by NS for autoscale
+                    if (server.get_ipaddress() != null) {
+                        apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.delete(_netscalerService, server.get_name());
+                        if (apiCallResult.errorcode != 0) {
+                            throw new ExecutionException("Failed to remove server:" + server.get_name());
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to delete server and services in the guest vlan:" + vlanTag + " on the Netscaler device due to: " + e.getMessage());
+        }
+    }
+
+    private String getNetScalerProtocol(LoadBalancerTO loadBalancer) throws ExecutionException {
+        String port = Integer.toString(loadBalancer.getSrcPort());
+        String lbProtocol = loadBalancer.getLbProtocol();
+        StickinessPolicyTO[] stickyPolicies = loadBalancer.getStickinessPolicies();
+        String nsProtocol = "TCP";
+
+        if (lbProtocol == null)
+            lbProtocol = loadBalancer.getProtocol();
+
+        if ((stickyPolicies != null) && (stickyPolicies.length > 0) && (stickyPolicies[0] != null)) {
+            StickinessPolicyTO stickinessPolicy = stickyPolicies[0];
+            if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName()) ||
+                    (StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName()))) {
+                nsProtocol = "HTTP";
+                return nsProtocol;
+            }
+        }
+
+        if (lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO) || lbProtocol.equalsIgnoreCase(NetUtils.HTTP_PROTO))
+            return lbProtocol.toUpperCase();
+
+        if (port.equals(NetUtils.HTTP_PORT)) {
+            nsProtocol = "HTTP";
+        } else if (NetUtils.TCP_PROTO.equalsIgnoreCase(lbProtocol)) {
+            nsProtocol = "TCP";
+        } else if (NetUtils.UDP_PROTO.equalsIgnoreCase(lbProtocol)) {
+            nsProtocol = "UDP";
+        }
+
+        return nsProtocol;
+    }
+
+    private void addLBVirtualServer(String virtualServerName, String publicIp, int publicPort, String lbAlgorithm, String protocol, StickinessPolicyTO[] stickyPolicies,
+            AutoScaleVmGroupTO vmGroupTO) throws ExecutionException {
+        try {
+            String lbMethod;
+            if ("roundrobin".equalsIgnoreCase(lbAlgorithm)) {
+                lbMethod = "ROUNDROBIN";
+            } else if ("leastconn".equalsIgnoreCase(lbAlgorithm)) {
+                lbMethod = "LEASTCONNECTION";
+            } else if ("source".equalsIgnoreCase(lbAlgorithm)) {
+                lbMethod = "SOURCEIPHASH";
+            } else {
+                throw new ExecutionException("Got invalid load balancing algorithm: " + lbAlgorithm + " in the load balancing rule");
+            }
+
+            boolean vserverExisis = false;
+            lbvserver vserver = getVirtualServerIfExisits(virtualServerName);
+            if (vserver != null) {
+                if (!vserver.get_servicetype().equalsIgnoreCase(protocol)) {
+                    throw new ExecutionException("Can not update virtual server:" + virtualServerName + " as current protocol:" + vserver.get_servicetype() +
+                            " of virtual server is different from the " + " intended protocol:" + protocol);
+                }
+                vserverExisis = true;
+            }
+            // Use new vserver always for configuration
+            vserver = new lbvserver();
+            vserver.set_name(virtualServerName);
+            vserver.set_ipv46(publicIp);
+            vserver.set_port(publicPort);
+            vserver.set_servicetype(protocol);
+            vserver.set_lbmethod(lbMethod);
+
+            // netmask can only be set for source IP load balancer algorithm
+            if (!lbMethod.equalsIgnoreCase("SOURCEIPHASH")) {
+                vserver.set_netmask(null);
+                vserver.set_v6netmasklen(null);
+            }
+
+            if ((stickyPolicies != null) && (stickyPolicies.length > 0) && (stickyPolicies[0] != null)) {
+                long timeout = 2;// netscaler default 2 min
+                String cookieName = null;
+                StickinessPolicyTO stickinessPolicy = stickyPolicies[0];
+
+                // get the session persistence parameters
+                List<Pair<String, String>> paramsList = stickinessPolicy.getParams();
+                for (Pair<String, String> param : paramsList) {
+                    if ("holdtime".equalsIgnoreCase(param.first())) {
+                        timeout = Long.parseLong(param.second());
+                    } else if ("name".equalsIgnoreCase(param.first())) {
+                        cookieName = param.second();
+                    }
+                }
+
+                // configure virtual server based on the persistence method
+                if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
+                    vserver.set_persistencetype("COOKIEINSERT");
+                } else if (StickinessMethodType.SourceBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
+                    vserver.set_persistencetype("SOURCEIP");
+                } else if (StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
+                    vserver.set_persistencetype("RULE");
+                    vserver.set_rule("HTTP.REQ.HEADER(\"COOKIE\").VALUE(0).typecast_nvlist_t('=',';').value(\"" + cookieName + "\")");
+                    vserver.set_resrule("HTTP.RES.HEADER(\"SET-COOKIE\").VALUE(0).typecast_nvlist_t('=',';').value(\"" + cookieName + "\")");
+                } else {
+                    throw new ExecutionException("Got invalid session persistence method: " + stickinessPolicy.getMethodName() + " in the load balancing rule");
+                }
+
+                // set session persistence timeout
+                vserver.set_timeout(timeout);
+            } else {
+                // delete the LB stickyness policy
+                vserver.set_persistencetype("NONE");
+            }
+
+            if (vserverExisis) {
+                apiCallResult = lbvserver.update(_netscalerService, vserver);
+            } else {
+                apiCallResult = lbvserver.add(_netscalerService, vserver);
+            }
+            if (apiCallResult.errorcode != 0) {
+                throw new ExecutionException("Failed to create new load balancing virtual server:" + virtualServerName + " due to " + apiCallResult.message);
+            }
+
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Created load balancing virtual server " + virtualServerName + " on the Netscaler device");
+            }
+        } catch (nitro_exception e) {
+            throw new ExecutionException("Failed to create new virtual server:" + virtualServerName + " due to " + e.getMessage());
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to create new virtual server:" + virtualServerName + " due to " + e.getMessage());
+        }
+    }
+
+    private void removeLBVirtualServer(String virtualServerName) throws ExecutionException {
+        try {
+            lbvserver vserver = lbvserver.get(_netscalerService, virtualServerName);
+            if (vserver == null) {
+                return;
+            }
+            apiCallResult = lbvserver.delete(_netscalerService, vserver);
+            if (apiCallResult.errorcode != 0) {
+                throw new ExecutionException("Failed to delete virtual server:" + virtualServerName + " due to " + apiCallResult.message);
+            }
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return;
+            } else {
+                throw new ExecutionException("Failed remove virtual server:" + virtualServerName + " due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to remove virtual server:" + virtualServerName + " due to " + e.getMessage());
+        }
+    }
+
+    // Monitor related methods
+    private void addLBMonitor(String nsMonitorName, String lbProtocol, HealthCheckPolicyTO hcp) throws ExecutionException {
+        try {
+            // check if the monitor exists
+            boolean csMonitorExisis = false;
+            lbmonitor csMonitor = getMonitorIfExisits(nsMonitorName);
+            if (csMonitor != null) {
+                if (!csMonitor.get_type().equalsIgnoreCase(lbProtocol)) {
+                    throw new ExecutionException("Can not update monitor :" + nsMonitorName + " as current protocol:" + csMonitor.get_type() +
+                            " of monitor is different from the " + " intended protocol:" + lbProtocol);
+                }
+                csMonitorExisis = true;
+            }
+            if (!csMonitorExisis) {
+                lbmonitor csMon = new lbmonitor();
+                csMon.set_monitorname(nsMonitorName);
+                csMon.set_type(lbProtocol);
+                if (lbProtocol.equalsIgnoreCase("HTTP")) {
+                    csMon.set_httprequest(hcp.getpingPath());
+                    s_logger.trace("LB Protocol is HTTP,  Applying  ping path on HealthCheck Policy");
+                } else {
+                    s_logger.debug("LB Protocol is not HTTP, Skipping to apply  ping path on HealthCheck Policy");
+                }
+
+                csMon.set_interval(hcp.getHealthcheckInterval());
+                csMon.set_retries(Math.max(hcp.getHealthcheckThresshold(), hcp.getUnhealthThresshold()) + 1);
+                csMon.set_resptimeout(hcp.getResponseTime());
+                csMon.set_failureretries(hcp.getUnhealthThresshold());
+                csMon.set_successretries(hcp.getHealthcheckThresshold());
+                s_logger.debug("Monitor properites going to get created :interval :: " + csMon.get_interval() + "respTimeOUt:: " + csMon.get_resptimeout() +
+                        "failure retires(unhealththresshold) :: " + csMon.get_failureretries() + "successtries(healththresshold) ::" + csMon.get_successretries());
+                lbmonitor.add(_netscalerService, csMon);
+            } else {
+                s_logger.debug("Monitor :" + nsMonitorName + " is already existing. Skipping to delete and create it");
+            }
+        } catch (nitro_exception e) {
+            throw new ExecutionException("Failed to create new monitor :" + nsMonitorName + " due to " + e.getMessage());
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to create new monitor :" + nsMonitorName + " due to " + e.getMessage());
+        }
+    }
+
+    private void bindServiceToMonitor(String nsServiceName, String nsMonitorName) throws ExecutionException {
+
+        try {
+            com.citrix.netscaler.nitro.resource.config.basic.service serviceObject = new com.citrix.netscaler.nitro.resource.config.basic.service();
+            serviceObject = com.citrix.netscaler.nitro.resource.config.basic.service.get(_netscalerService, nsServiceName);
+            if (serviceObject != null) {
+                com.citrix.netscaler.nitro.resource.config.basic.service_lbmonitor_binding serviceMonitor =
+                        new com.citrix.netscaler.nitro.resource.config.basic.service_lbmonitor_binding();
+                serviceMonitor.set_monitor_name(nsMonitorName);
+                serviceMonitor.set_name(nsServiceName);
+                serviceMonitor.set_monstate("ENABLED");
+                s_logger.debug("Trying to bind  the monitor :" + nsMonitorName + " to the service :" + nsServiceName);
+                com.citrix.netscaler.nitro.resource.config.basic.service_lbmonitor_binding.add(_netscalerService, serviceMonitor);
+                s_logger.debug("Successfully binded the monitor :" + nsMonitorName + " to the service :" + nsServiceName);
+            }
+        } catch (nitro_exception e) {
+            throw new ExecutionException("Failed to create new monitor :" + nsMonitorName + " due to " + e.getMessage());
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to create new monitor :" + nsMonitorName + " due to " + e.getMessage());
+        }
+    }
+
+    private void unBindServiceToMonitor(String nsServiceName, String nsMonitorName) throws ExecutionException {
+
+        try {
+            com.citrix.netscaler.nitro.resource.config.basic.service serviceObject = new com.citrix.netscaler.nitro.resource.config.basic.service();
+            serviceObject = com.citrix.netscaler.nitro.resource.config.basic.service.get(_netscalerService, nsServiceName);
+
+            if (serviceObject != null) {
+                com.citrix.netscaler.nitro.resource.config.basic.service_lbmonitor_binding serviceMonitor =
+                        new com.citrix.netscaler.nitro.resource.config.basic.service_lbmonitor_binding();
+                serviceMonitor.set_monitor_name(nsMonitorName);
+                serviceMonitor.set_name(nsServiceName);
+                s_logger.debug("Trying to unbind  the monitor :" + nsMonitorName + " from the service :" + nsServiceName);
+                service_lbmonitor_binding.delete(_netscalerService, serviceMonitor);
+                s_logger.debug("Successfully unbinded the monitor :" + nsMonitorName + " from the service :" + nsServiceName);
+            }
+
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return;
+            } else {
+                throw new ExecutionException("Failed to unbind monitor :" + nsMonitorName + "from the service :" + nsServiceName + "due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to unbind monitor :" + nsMonitorName + "from the service :" + nsServiceName + "due to " + e.getMessage());
+        }
+
+    }
+
+    private void removeLBMonitor(String nsMonitorName) throws ExecutionException {
+
+        try {
+            if (nsMonitorExist(nsMonitorName)) {
+                lbmonitor monitorObj = lbmonitor.get(_netscalerService, nsMonitorName);
+                monitorObj.set_respcode(null);
+                lbmonitor.delete(_netscalerService, monitorObj);
+                s_logger.info("Successfully deleted monitor : " + nsMonitorName);
+            }
+        } catch (nitro_exception e) {
+            if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) {
+                return;
+            } else {
+                throw new ExecutionException("Failed to delete monitor :" + nsMonitorName + " due to " + e.getMessage());
+            }
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to delete monitor :" + nsMonitorName + " due to " + e.getMessage());
+        }
+
+    }
+
+    public synchronized void applyAutoScaleConfig(LoadBalancerTO loadBalancer) throws Exception, ExecutionException {
+
+        AutoScaleVmGroupTO vmGroupTO = loadBalancer.getAutoScaleVmGroupTO();
+        if (!isAutoScaleSupportedInNetScaler()) {
+            throw new ExecutionException("AutoScale not supported in this version of NetScaler");
+        }
+        if (loadBalancer.isRevoked() || vmGroupTO.getState().equals("revoke")) {
+            removeAutoScaleConfig(loadBalancer);
+        } else {
+            createAutoScaleConfig(loadBalancer);
+        }
+        // AutoScale APIs are successful executed, now save the configuration.
+        saveConfiguration();
+        if (s_logger.isInfoEnabled()) {
+            s_logger.info("Successfully executed resource AutoScaleConfig");
+        }
+    }
+
+    @SuppressWarnings("static-access")
+    private synchronized boolean createAutoScaleConfig(LoadBalancerTO loadBalancerTO) throws ExecutionException, Exception {
+
+        String srcIp = loadBalancerTO.getSrcIp();
+        int srcPort = loadBalancerTO.getSrcPort();
+        String lbProtocol = getNetScalerProtocol(loadBalancerTO);
+        String lbAlgorithm = loadBalancerTO.getAlgorithm();
+        generateAutoScaleVmGroupIdentifier(loadBalancerTO);
+        String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort);
+        AutoScaleVmGroupTO vmGroupTO = loadBalancerTO.getAutoScaleVmGroupTO();
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Created load balancing virtual server " + nsVirtualServerName + " on the Netscaler device");
+        }
+        addLBVirtualServer(nsVirtualServerName, srcIp, srcPort, lbAlgorithm, lbProtocol, loadBalancerTO.getStickinessPolicies(), vmGroupTO);
+
+        String serviceGroupName = generateAutoScaleServiceGroupName(loadBalancerTO);
+        if (!nsServiceGroupExists(serviceGroupName)) {
+            // add servicegroup lb_autoscaleGroup -autoscale POLICY -memberPort 80
+            int memberPort = vmGroupTO.getMemberPort();
+            try {
+                servicegroup serviceGroup = new servicegroup();
+                serviceGroup.set_servicegroupname(serviceGroupName);
+                serviceGroup.set_servicetype(lbProtocol);
+                serviceGroup.set_autoscale("POLICY");
+                serviceGroup.set_memberport(memberPort);
+                servicegroup.add(_netscalerService, serviceGroup);
+            } catch (Exception e) {
+                throw e;
+            }
+        }
+
+        if (!isServiceGroupBoundToVirtualServer(nsVirtualServerName, serviceGroupName)) {
+            // Bind autoscale service group
+            // bind lb vserver lb lb_autoscaleGroup
+            lbvserver_servicegroup_binding vserver_servicegroup_binding = new lbvserver_servicegroup_binding();
+
+            try {
+                vserver_servicegroup_binding.set_name(nsVirtualServerName);
+                vserver_servicegroup_binding.set_servicegroupname(serviceGroupName);
+                lbvserver_servicegroup_binding.add(_netscalerService, vserver_servicegroup_binding);
+            } catch (Exception e) {
+                throw e;
+            }
+        }
+
+        // Create the autoscale config
+        if (!loadBalancerTO.getAutoScaleVmGroupTO().getState().equals("disabled")) {
+            // on restart of network, there might be vmgrps in disabled state, no need to create autoscale config for them
+            enableAutoScaleConfig(loadBalancerTO, false);
+        } else if (loadBalancerTO.getAutoScaleVmGroupTO().getState().equals("disabled")) {
+            disableAutoScaleConfig(loadBalancerTO, false);
+        }
+
+        return true;
+    }
+
+    @SuppressWarnings("static-access")
+    private synchronized boolean removeAutoScaleConfig(LoadBalancerTO loadBalancerTO) throws Exception, ExecutionException {
+        String srcIp = loadBalancerTO.getSrcIp();
+        int srcPort = loadBalancerTO.getSrcPort();
+        generateAutoScaleVmGroupIdentifier(loadBalancerTO);
+
+        String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort);
+        String serviceGroupName = generateAutoScaleServiceGroupName(loadBalancerTO);
+
+        if (loadBalancerTO.getAutoScaleVmGroupTO().getCurrentState().equals("enabled")) {
+            disableAutoScaleConfig(loadBalancerTO, false);
+        }
+
+        if (isServiceGroupBoundToVirtualServer(nsVirtualServerName, serviceGroupName)) {
+            // UnBind autoscale service group
+            // unbind lb vserver lb lb_autoscaleGroup
+            lbvserver_servicegroup_binding vserver_servicegroup_binding = new lbvserver_servicegroup_binding();
+            try {
+                vserver_servicegroup_binding.set_name(nsVirtualServerName);
+                vserver_servicegroup_binding.set_servicegroupname(serviceGroupName);
+                lbvserver_servicegroup_binding.delete(_netscalerService, vserver_servicegroup_binding);
+            } catch (Exception e) {
+                throw e;
+            }
+        }
+
+        if (nsServiceGroupExists(serviceGroupName)) {
+            // Remove autoscale service group
+            com.citrix.netscaler.nitro.resource.config.basic.servicegroup serviceGroup = new com.citrix.netscaler.nitro.resource.config.basic.servicegroup();
+            try {
+                serviceGroup.set_servicegroupname(serviceGroupName);
+                servicegroup.delete(_netscalerService, serviceGroup);
+            } catch (Exception e) {
+                throw e;
+            }
+        }
+
+        removeLBVirtualServer(nsVirtualServerName);
+
+        return true;
+    }
+
+    @SuppressWarnings("static-access")
+    private synchronized boolean enableAutoScaleConfig(LoadBalancerTO loadBalancerTO, boolean isCleanUp) throws Exception {
+        String vmGroupIdentifier = generateAutoScaleVmGroupIdentifier(loadBalancerTO);
+        String srcIp = loadBalancerTO.getSrcIp();
+        int srcPort = loadBalancerTO.getSrcPort();
+
+        String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort);
+        String serviceGroupName = generateAutoScaleServiceGroupName(loadBalancerTO);
+        String profileName = generateAutoScaleProfileName(vmGroupIdentifier);
+        String timerName = generateAutoScaleTimerName(vmGroupIdentifier);
+        String scaleDownActionName = generateAutoScaleScaleDownActionName(vmGroupIdentifier);
+        String scaleUpActionName = generateAutoScaleScaleUpActionName(vmGroupIdentifier);
+        String mtName = generateSnmpMetricTableName(vmGroupIdentifier);
+        String monitorName = generateSnmpMonitorName(vmGroupIdentifier);
+        AutoScaleVmGroupTO vmGroupTO = loadBalancerTO.getAutoScaleVmGroupTO();
+        AutoScaleVmProfileTO profileTO = vmGroupTO.getProfile();
+        List<AutoScalePolicyTO> policies = vmGroupTO.getPolicies();
+        int interval = vmGroupTO.getInterval();
+        profileTO.getCounterParamList();
+        String snmpCommunity = null;
+        int snmpPort = DEFAULT_SNMP_PORT;
+        long cur_prirotiy = 1;
+
+        // get the session persistence parameters
+        List<Pair<String, String>> paramsList = profileTO.getCounterParamList();
+        for (Pair<String, String> param : paramsList) {
+            if ("snmpcommunity".equalsIgnoreCase(param.first())) {
+                snmpCommunity = param.second();
+            } else if ("snmpport".equalsIgnoreCase(param.first())) {
+                snmpPort = Integer.parseInt(param.second());
+            }
+        }
+
+        try {
+            // Set min and max autoscale members;
+            // add lb vserver lb  http 10.102.31.100 80 -minAutoscaleMinMembers 3 -maxAutoscaleMembers 10
+            int minAutoScaleMembers = vmGroupTO.getMinMembers();
+            int maxAutoScaleMembers = vmGroupTO.getMaxMembers();
+            lbvserver vserver = new lbvserver();
+            try {
+                vserver.set_name(nsVirtualServerName);
+                vserver.set_minautoscalemembers(minAutoScaleMembers);
+                vserver.set_maxautoscalemembers(maxAutoScaleMembers);
+                lbvserver.update(_netscalerService, vserver);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            /* AutoScale Config */
+            // Add AutoScale Profile
+            // add autoscale profile lb_asprofile CLOUDSTACK -url -http:// 10.102.31.34:8080/client/api- -apiKey abcdef
+            // -sharedSecret xyzabc
+            String apiKey = profileTO.getAutoScaleUserApiKey();
+            String secretKey = profileTO.getAutoScaleUserSecretKey();
+            String url = profileTO.getCloudStackApiUrl();
+
+            autoscaleprofile autoscaleProfile = new autoscaleprofile();
+            try {
+                autoscaleProfile.set_name(profileName);
+                autoscaleProfile.set_type("CLOUDSTACK");
+                autoscaleProfile.set_apikey(apiKey);
+                autoscaleProfile.set_sharedsecret(secretKey);
+                autoscaleProfile.set_url(url);
+                autoscaleprofile.add(_netscalerService, autoscaleProfile);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            // Add Timer
+            nstimer timer = new nstimer();
+            try {
+                timer.set_name(timerName);
+                timer.set_interval(interval);
+                nstimer.add(_netscalerService, timer);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            // AutoScale Actions
+            Integer scaleUpQuietTime = null;
+            Integer scaleDownQuietTime = null;
+            for (AutoScalePolicyTO autoScalePolicyTO : policies) {
+                if (scaleUpQuietTime == null) {
+                    if (isScaleUpPolicy(autoScalePolicyTO)) {
+                        scaleUpQuietTime = autoScalePolicyTO.getQuietTime();
+                        if (scaleDownQuietTime != null) {
+                            break;
+                        }
+                    }
+                }
+                if (scaleDownQuietTime == null) {
+                    if (isScaleDownPolicy(autoScalePolicyTO)) {
+                        scaleDownQuietTime = autoScalePolicyTO.getQuietTime();
+                        if (scaleUpQuietTime != null) {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // Add AutoScale ScaleUp action
+            // add autoscale action lb_scaleUpAction provision -vserver lb -profilename lb_asprofile -params
+            // -lbruleid=1234&command=deployvm&zoneid=10&templateid=5&serviceofferingid=3- -quiettime 300
+            com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction scaleUpAction =
+                    new com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction();
+            try {
+                scaleUpAction.set_name(scaleUpActionName);
+                scaleUpAction.set_type("SCALE_UP"); // TODO: will this be called provision?
+                scaleUpAction.set_vserver(nsVirtualServerName); // Actions Vserver, the one that is autoscaled, with CS
+                // now both are same. Not exposed in API.
+                scaleUpAction.set_profilename(profileName);
+                if(scaleUpQuietTime != null) {
+                    scaleUpAction.set_quiettime(scaleUpQuietTime);
+                }
+                String scaleUpParameters =
+                        "command=deployVirtualMachine" + "&" + ApiConstants.ZONE_ID + "=" + profileTO.getZoneId() + "&" + ApiConstants.SERVICE_OFFERING_ID + "=" +
+                                profileTO.getServiceOfferingId() + "&" + ApiConstants.TEMPLATE_ID + "=" + profileTO.getTemplateId() + "&" + ApiConstants.DISPLAY_NAME + "=" +
+                                profileTO.getVmName() + "&" + ((profileTO.getNetworkId() == null) ? "" : (ApiConstants.NETWORK_IDS + "=" + profileTO.getNetworkId() + "&")) +
+                                ((profileTO.getOtherDeployParams() == null) ? "" : (profileTO.getOtherDeployParams() + "&")) + "lbruleid=" + loadBalancerTO.getUuid();
+                scaleUpAction.set_parameters(scaleUpParameters);
+                autoscaleaction.add(_netscalerService, scaleUpAction);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction scaleDownAction =
+                    new com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction();
+            Integer destroyVmGracePeriod = profileTO.getDestroyVmGraceperiod();
+            try {
+                scaleDownAction.set_name(scaleDownActionName);
+                scaleDownAction.set_type("SCALE_DOWN"); // TODO: will this be called de-provision?
+                scaleDownAction.set_vserver(nsVirtualServerName); // TODO: no global option as of now through Nitro.
+                // Testing cannot be done.
+                scaleDownAction.set_profilename(profileName);
+                scaleDownAction.set_quiettime(scaleDownQuietTime);
+                String scaleDownParameters = "command=destroyVirtualMachine" + "&" + "lbruleid=" + loadBalancerTO.getUuid();
+                scaleDownAction.set_parameters(scaleDownParameters);
+                scaleDownAction.set_vmdestroygraceperiod(destroyVmGracePeriod);
+                autoscaleaction.add(_netscalerService, scaleDownAction);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            /* Create min member policy */
+            String minMemberPolicyName = generateAutoScaleMinPolicyName(vmGroupIdentifier);
+            String minMemberPolicyExp =
+                    "SYS.VSERVER(\"" + nsVirtualServerName + "\").ACTIVESERVICES.LT(SYS.VSERVER(\"" + nsVirtualServerName + "\").MINAUTOSCALEMEMBERS)";
+            addAutoScalePolicy(timerName, minMemberPolicyName, cur_prirotiy++, minMemberPolicyExp, scaleUpActionName, interval, interval, isCleanUp);
+
+            /* Create max member policy */
+            String maxMemberPolicyName = generateAutoScaleMaxPolicyName(vmGroupIdentifier);
+            String maxMemberPolicyExp =
+                    "SYS.VSERVER(\"" + nsVirtualServerName + "\").ACTIVESERVICES.GT(SYS.VSERVER(\"" + nsVirtualServerName + "\").MAXAUTOSCALEMEMBERS)";
+            addAutoScalePolicy(timerName, maxMemberPolicyName, cur_prirotiy++, maxMemberPolicyExp, scaleDownActionName, interval, interval, isCleanUp);
+
+            /* Create Counters */
+            HashMap<String, Integer> snmpMetrics = new HashMap<String, Integer>();
+            for (AutoScalePolicyTO autoScalePolicyTO : policies) {
+                List<ConditionTO> conditions = autoScalePolicyTO.getConditions();
+                String policyExpression = "";
+                int snmpCounterNumber = 0;
+                for (ConditionTO conditionTO : conditions) {
+                    CounterTO counterTO = conditionTO.getCounter();
+                    String counterName = counterTO.getName();
+                    String operator = conditionTO.getRelationalOperator();
+                    long threshold = conditionTO.getThreshold();
+
+                    StringBuilder conditionExpression = new StringBuilder();
+                    Formatter formatter = new Formatter(conditionExpression, Locale.US);
+
+                    if (counterTO.getSource().equals("snmp")) {
+                        counterName = generateSnmpMetricName(counterName);
+                        if (snmpMetrics.size() == 0) {
+                            // Create Metric Table
+                            //add lb metricTable lb_metric_table
+                            lbmetrictable metricTable = new lbmetrictable();
+                            try {
+                                metricTable.set_metrictable(mtName);
+                                lbmetrictable.add(_netscalerService, metricTable);
+                            } catch (Exception e) {
+                                // Ignore Exception on cleanup
+                                if (!isCleanUp)
+                                    throw e;
+                            }
+
+                            // Create Monitor
+                            // add lb monitor lb_metric_table_mon LOAD -destPort 161 -snmpCommunity public -metricTable
+                            // lb_metric_table -interval <policy_interval == 80% >
+                            lbmonitor monitor = new lbmonitor();
+                            try {
+                                monitor.set_monitorname(monitorName);
+                                monitor.set_type("LOAD");
+                                monitor.set_destport(snmpPort);
+                                monitor.set_snmpcommunity(snmpCommunity);
+                                monitor.set_metrictable(mtName);
+                                monitor.set_interval((int)(interval * 0.8));
+                                lbmonitor.add(_netscalerService, monitor);
+                            } catch (Exception e) {
+                                // Ignore Exception on cleanup
+                                if (!isCleanUp)
+                                    throw e;
+                            }
+
+                            // Bind monitor to servicegroup.
+                            // bind lb monitor lb_metric_table_mon lb_autoscaleGroup -passive
+                            servicegroup_lbmonitor_binding servicegroup_monitor_binding = new servicegroup_lbmonitor_binding();
+                            try {
+                                servicegroup_monitor_binding.set_servicegroupname(serviceGroupName);
+                                servicegroup_monitor_binding.set_monitor_name(monitorName);
+
+                                // Use the monitor for autoscaling purpose only.
+                                // Don't mark service members down when metric breaches threshold
+                                servicegroup_monitor_binding.set_passive(true);
+
+                                servicegroup_lbmonitor_binding.add(_netscalerService, servicegroup_monitor_binding);
+                            } catch (Exception e) {
+                                // Ignore Exception on cleanup
+                                if (!isCleanUp)
+                                    throw e;
+                            }
+                        }
+
+                        boolean newMetric = !snmpMetrics.containsKey(counterName);
+                        if (newMetric) {
+                            snmpMetrics.put(counterName, snmpCounterNumber++);
+                        }
+
+                        if (newMetric) {
+                            // bind lb metricTable lb_metric_table mem 1.3.6.1.4.1.2021.11.9.0
+                            String counterOid = counterTO.getValue();
+                            lbmetrictable_metric_binding metrictable_metric_binding = new lbmetrictable_metric_binding();
+                            try {
+                                metrictable_metric_binding.set_metrictable(mtName);
+                                metrictable_metric_binding.set_metric(counterName);
+                                metrictable_metric_binding.set_Snmpoid(counterOid);
+                                lbmetrictable_metric_binding.add(_netscalerService, metrictable_metric_binding);
+                            } catch (Exception e) {
+                                // Ignore Exception on cleanup
+                                if (!isCleanUp)
+                                    throw e;
+                            }
+
+                            // bind lb monitor lb_metric_table_mon -metric cpu -metricThreshold 1
+                            lbmonitor_metric_binding monitor_metric_binding = new lbmonitor_metric_binding();
+                            ;
+                            try {
+                                monitor_metric_binding.set_monitorname(monitorName);
+                                monitor_metric_binding.set_metric(counterName);
+                                /*
+                                 * Setting it to max to make sure traffic is not affected due to 'LOAD' monitoring.
+                                 * For Ex. if CPU is tracked and CPU is greater than 80, it is still < than Integer.MAX_VALUE
+                                 * so traffic will continue to flow.
+                                 */
+                                monitor_metric_binding.set_metricthreshold(Integer.MAX_VALUE);
+                                lbmonitor_metric_binding.add(_netscalerService, monitor_metric_binding);
+                            } catch (Exception e) {
+                                // Ignore Exception on cleanup
+                                if (!isCleanUp)
+                                    throw e;
+                            }
+                        }
+                        // SYS.VSERVER("abcd").SNMP_TABLE(0).AVERAGE_VALUE.GT(80)
+                        int counterIndex = snmpMetrics.get(counterName); // TODO: temporary fix. later on counter name
+                        // will be added as a param to SNMP_TABLE.
+                        formatter.format("SYS.VSERVER(\"%s\").SNMP_TABLE(%d).AVERAGE_VALUE.%s(%d)", nsVirtualServerName, counterIndex, operator, threshold);
+                    } else if (counterTO.getSource().equals("netscaler")) {
+                        //SYS.VSERVER("abcd").RESPTIME.GT(10)
+                        formatter.format("SYS.VSERVER(\"%s\").%s.%s(%d)", nsVirtualServerName, counterTO.getValue(), operator, threshold);
+                    }
+                    if (policyExpression.length() != 0) {
+                        policyExpression += " && ";
+                    }
+                    policyExpression += conditionExpression;
+                }
+                policyExpression = "(" + policyExpression + ")";
+
+                String policyId = Long.toString(autoScalePolicyTO.getId());
+                String policyName = generateAutoScalePolicyName(vmGroupIdentifier, policyId);
+                String action = null;
+                if (isScaleUpPolicy(autoScalePolicyTO)) {
+                    action = scaleUpActionName;
+                    String scaleUpCondition =
+                            "SYS.VSERVER(\"" + nsVirtualServerName + "\").ACTIVESERVICES.LT(SYS.VSERVER(\"" + nsVirtualServerName + "\").MAXAUTOSCALEMEMBERS)";
+                    policyExpression = scaleUpCondition + " && " + policyExpression;
+                } else {
+                    action = scaleDownActionName;
+                    String scaleDownCondition =
+                            "SYS.VSERVER(\"" + nsVirtualServerName + "\").ACTIVESERVICES.GT(SYS.VSERVER(\"" + nsVirtualServerName + "\").MINAUTOSCALEMEMBERS)";
+                    policyExpression = scaleDownCondition + " && " + policyExpression;
+                }
+
+                addAutoScalePolicy(timerName, policyName, cur_prirotiy++, policyExpression, action, autoScalePolicyTO.getDuration(), interval, isCleanUp);
+
+            }
+        } catch (Exception ex) {
+            if (!isCleanUp) {
+                // Normal course, exception has occurred
+                disableAutoScaleConfig(loadBalancerTO, true);
+                throw ex;
+
+            } else {
+                // Programming error. Exception should never be thrown afterall.
+                throw ex;
+            }
+        }
+
+        return true;
+    }
+
+    @SuppressWarnings("static-access")
+    private synchronized boolean disableAutoScaleConfig(LoadBalancerTO loadBalancerTO, boolean isCleanUp) throws Exception {
+
+        String vmGroupIdentifier = generateAutoScaleVmGroupIdentifier(loadBalancerTO);
+
+        String profileName = generateAutoScaleProfileName(vmGroupIdentifier);
+        String timerName = generateAutoScaleTimerName(vmGroupIdentifier);
+        String scaleDownActionName = generateAutoScaleScaleDownActionName(vmGroupIdentifier);
+        String scaleUpActionName = generateAutoScaleScaleUpActionName(vmGroupIdentifier);
+        String mtName = generateSnmpMetricTableName(vmGroupIdentifier);
+        String monitorName = generateSnmpMonitorName(vmGroupIdentifier);
+        String serviceGroupName = generateAutoScaleServiceGroupName(loadBalancerTO);
+        AutoScaleVmGroupTO vmGroupTO = loadBalancerTO.getAutoScaleVmGroupTO();
+        List<AutoScalePolicyTO> policies = vmGroupTO.getPolicies();
+        String minMemberPolicyName = generateAutoScaleMinPolicyName(vmGroupIdentifier);
+        String maxMemberPolicyName = generateAutoScaleMaxPolicyName(vmGroupIdentifier);
+
+        try {
+
+            /* Delete min/max member policies */
+
+            removeAutoScalePolicy(timerName, minMemberPolicyName, isCleanUp);
+
+            removeAutoScalePolicy(timerName, maxMemberPolicyName, isCleanUp);
+
+            boolean isSnmp = false;
+            /* Create Counters */
+            for (AutoScalePolicyTO autoScalePolicyTO : policies) {
+                List<ConditionTO> conditions = autoScalePolicyTO.getConditions();
+                for (ConditionTO conditionTO : conditions) {
+                    CounterTO counterTO = conditionTO.getCounter();
+                    if (counterTO.getSource().equals("snmp")) {
+                        isSnmp = true;
+                        break;
+                    }
+                }
+                String policyId = Long.toString(autoScalePolicyTO.getId());
+                String policyName = generateAutoScalePolicyName(vmGroupIdentifier, policyId);
+
+                // Removing Timer policy
+                removeAutoScalePolicy(timerName, policyName, isCleanUp);
+            }
+
+            /* Delete AutoScale Config */
+            // Delete AutoScale ScaleDown action
+            com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction scaleDownAction =
+                    new com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction();
+            try {
+                scaleDownAction.set_name(scaleDownActionName);
+                autoscaleaction.delete(_netscalerService, scaleDownAction);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            // Delete AutoScale ScaleUp action
+            com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction scaleUpAction =
+                    new com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleaction();
+            try {
+                scaleUpAction.set_name(scaleUpActionName);
+                autoscaleaction.delete(_netscalerService, scaleUpAction);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            // Delete Timer
+            nstimer timer = new nstimer();
+            try {
+                timer.set_name(timerName);
+                nstimer.delete(_netscalerService, timer);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            // Delete AutoScale Profile
+            autoscaleprofile autoscaleProfile = new autoscaleprofile();
+            try {
+                autoscaleProfile.set_name(profileName);
+                autoscaleprofile.delete(_netscalerService, autoscaleProfile);
+            } catch (Exception e) {
+                // Ignore Exception on cleanup
+                if (!isCleanUp)
+                    throw e;
+            }
+
+            if (isSnmp) {
+                servicegroup_lbmonitor_binding servicegroup_monitor_binding = new servicegroup_lbmonitor_binding();
+                try {
+                    servicegroup_monitor_binding.set_monitor_name(monitorName);
+                    servicegroup_monitor_binding.set_servicegroupname(serviceGroupName);
+                    servicegroup_lbmonitor_binding.delete(_netscalerService, servicegroup_monitor_binding);
+                } catch (Exception e) {
+                    // Ignore Exception on cleanup
+                    if (!isCleanUp)
+                        throw e;
+                }
+
+                // Delete Monitor
+                // rm lb monitor lb_metric_table_mon
+                com.citrix.netscaler.nitro.resource.config.lb.lbmonitor monitor = new com.citrix.netscaler.nitro.resource.config.lb.lbmonitor();
+                try {
+                    monitor.set_monitorname(monitorName);
+                    monitor.set_type("LOAD");
+                    lbmonitor.delete(_netscalerService, monitor);
+                } catch (Exception e) {
+                    // Ignore Exception on cleanup
+                    if (!isCleanUp)
+                        throw e;
+                }
+
+                // Delete Metric Table
+                com.citrix.netscaler.nitro.resource.config.lb.lbmetrictable metricTable = new com.citrix.netscaler.nitro.resource.config.lb.lbmetrictable();
+                try {
+                    metricTable.set_metrictable(mtName);
+                    lbmetrictable.delete(_netscalerService, metricTable);
+                } catch (Exception e) {
+                    // Ignore Exception on cleanup
+                    if (!isCleanUp)
+                        throw e;
+                }
+            }
+        } catch (Exception ex) {
+            if (!isCleanUp) {
+                // Normal course, exception has occurred
+                enableAutoScaleConfig(loadBalancerTO, true);
+                throw ex;
+            } else {
+                // Programming error
+                throw ex;
+            }
+        }
+
+        return true;
+    }
+
+    private synchronized void addAutoScalePolicy(String timerName, String policyName, long priority, String policyExpression, String action, int duration, int interval,
+            boolean isCleanUp) throws Exception {
+        // Adding a autoscale policy
+        // add timer policy lb_policy_scaleUp_cpu_mem -rule - (SYS.CUR_VSERVER.METRIC_TABLE(cpu).AVG_VAL.GT(80)-
+        // -action lb_scaleUpAction
+        autoscalepolicy timerPolicy = new autoscalepolicy();
+        try {
+            timerPolicy.set_name(policyName);
+            timerPolicy.set_action(action);
+            timerPolicy.set_rule(policyExpression);
+            autoscalepolicy.add(_netscalerService, timerPolicy);
+        } catch (Exception e) {
+            // Ignore Exception on cleanup
+            if (!isCleanUp)
+                throw e;
+        }
+
+        // bind timer policy
+        // For now it is bound globally.
+        // bind timer trigger lb_astimer -policyName lb_policy_scaleUp -vserver lb -priority 1 -samplesize 5
+        // TODO: later bind to lbvserver. bind timer trigger lb_astimer -policyName lb_policy_scaleUp -vserver lb
+        // -priority 1 -samplesize 5
+        // -thresholdsize 5
+        nstimer_autoscalepolicy_binding timer_policy_binding = new nstimer_autoscalepolicy_binding();
+        int sampleSize = duration / interval;
+        try {
+            timer_policy_binding.set_name(timerName);
+            timer_policy_binding.set_policyname(policyName);
+            timer_policy_binding.set_samplesize(sampleSize);
+            timer_policy_binding.set_threshold(sampleSize); // We are not exposing this parameter as of now.
+            // i.e. n(m) is not exposed to CS user. So thresholdSize == sampleSize
+            timer_policy_binding.set_priority(priority);
+            nstimer_autoscalepolicy_binding.add(_netscalerService, timer_policy_binding);
+        } catch (Exception e) {
+            // Ignore Exception on cleanup
+            if (!isCleanUp)
+                throw e;
+        }
+    }
+
+    private void removeAutoScalePolicy(String timerName, String policyName, boolean isCleanUp) throws Exception {
+        // unbind timer policy
+        // unbbind timer trigger lb_astimer -policyName lb_policy_scaleUp
+        nstimer_autoscalepolicy_binding timer_policy_binding = new nstimer_autoscalepolicy_binding();
+        try {
+            timer_policy_binding.set_name(timerName);
+            timer_policy_binding.set_policyname(policyName);
+            nstimer_autoscalepolicy_binding.delete(_netscalerService, timer_policy_binding);
+        } catch (Exception e) {
+            // Ignore Exception on cleanup
+            if (!isCleanUp)
+                throw e;
+        }
+
+        // Removing Timer policy
+        // rm timer policy lb_policy_scaleUp_cpu_mem
+        autoscalepolicy timerPolicy = new autoscalepolicy();
+        try {
+            timerPolicy.set_name(policyName);
+            autoscalepolicy.delete(_netscalerService, timerPolicy);
+        } catch (Exception e) {
+            // Ignore Exception on cleanup
+            if (!isCleanUp)
+                throw e;
+        }
+
+    }
+
+    private boolean isAutoScaleSupportedInNetScaler() throws ExecutionException {
+        new autoscaleprofile();
+        try {
+            autoscaleprofile.get(_netscalerService);
+        } catch (Exception ex) {
+            // Looks like autoscale is not supported in this netscaler.
+            // TODO: Config team has introduce a new command to check
+            // the list of entities supported in a NetScaler. Can use that
+            // once it is present in AutoScale branch.
+            s_logger.warn("AutoScale is not supported in NetScaler");
+            return false;
+        }
+        return true;
+    }
+
+    private boolean isScaleUpPolicy(AutoScalePolicyTO autoScalePolicyTO) {
+        return autoScalePolicyTO.getAction().equals("scaleup");
+    }
+
+    private boolean isScaleDownPolicy(AutoScalePolicyTO autoScalePolicyTO) {
+        return autoScalePolicyTO.getAction().equals("scaledown");
+    }
+
+    private void saveConfiguration() throws ExecutionException {
+        try {
+            apiCallResult = nsconfig.save(_netscalerService);
+            if (apiCallResult.errorcode != 0) {
+                throw new ExecutionException("Error occured while saving configuration changes to Netscaler device due to " + apiCallResult.message);
+            }
+        } catch (nitro_exception e) {
+            throw new ExecutionException("Failed to save configuration changes to Netscaler device due to " + e.getMessage());
+        } catch (Exception e) {
+            throw new ExecutionException("Failed to save configuration changes to Netscaler device due to " + e.getMessage());
+        }
+    }
+
+    private ExternalNetworkResourceUsageAnswer getPublicIpBytesSentAndReceived(ExternalNetworkResourceUsageCommand cmd) throws ExecutionException {
+        ExternalNetworkResourceUsageAnswer answer = new ExternalNetworkResourceUsageAnswer(cmd);
+
+        try {
+            lbvserver_stats[] stats = lbvserver_stats.get(_netscalerService);
+
+            if (stats == null || stats.length == 0) {
+                return answer;
+            }
+
+            for (lbvserver_stats stat_entry : stats) {
+                String lbvserverName = stat_entry.get_name();
+                lbvserver vserver = lbvserver.get(_netscalerService, lbvserverName);
+                if (vserver != null) {
+                    String lbVirtualServerIp = vserver.get_ipv46();
+
+                    long[] bytesSentAndReceived = answer.ipBytes.get(lbVirtualServerIp);
+                    if (bytesSentAndReceived == null) {
+                        bytesSentAndReceived = new long[] {0, 0};
+                    }
+                    bytesSentAndReceived[0] += stat_entry.get_totalrequestbytes();
+                    bytesSentAndReceived[1] += stat_entry.get_totalresponsebytes();
+
+                    if (bytesSentAndReceived[0] >= 0 && bytesSentAndReceived[1] >= 0) {
+                        answer.ipBytes.put(lbVirtualServerIp, bytesSentAndReceived);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            s_logger.error("Failed to get bytes sent and recived statistics due to " + e);
+            throw new ExecutionException(e.getMessage());
+        }
+
+        return answer;
+    }
+
+    private Answer retry(Command cmd, int numRetries) {
+        int numRetriesRemaining = numRetries - 1;
+        s_logger.warn("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 Netscaler device at " + _ip + " due to " + e.getMessage());
+        }
+        return false;
+    }
+
+    private String generateInatRuleName(String srcIp, String dstIP) {
+        return genObjectName("Cloud-Inat", srcIp);
+    }
+
+    private String generateRnatRuleName(String srcIp, String dstIP) {
+        return genObjectName("Cloud-Rnat", srcIp);
+    }
+
+    private String generateNSVirtualServerName(String srcIp, long srcPort) {
+        return genObjectName("Cloud-VirtualServer", srcIp, srcPort);
+    }
+
+    private String generateNSMonitorName(String srcIp, long srcPort) {
+        // maximum length supported by NS is 31
+        return genObjectName("Cloud-Hc", srcIp, srcPort);
+    }
+
+    private String generateNSServerName(String serverIP) {
+        return genObjectName("Cloud-Server-", serverIP);
+    }
+
+    private String generateNSServiceName(String ip, long port) {
+        return genObjectName("Cloud-Service", ip, port);
+    }
+
+    private String generateAutoScaleVmGroupIdentifier(LoadBalancerTO lbTO) {
+        return lbTO.getSrcIp() + "-" + lbTO.getSrcPort();
+    }
+
+    private String generateAutoScaleServiceGroupName(LoadBalancerTO lbTO) {
+        /*
+         *  ServiceGroup name in NetScaler wont support long names. Providing special name.
+         *  Need for introducing uuid because every vmgroup creation should be distinguished.
+         *  Ex. (1) create a vm group, delete a vmgroup, create a vmgroup on same lb ip and port
+         *  This will reuse all vms from the original vm group in step (1)
+         */
+
+        return "Cloud" + lbTO.getAutoScaleVmGroupTO().getUuid().replace("-", "");
+    }
+
+    private String generateAutoScaleTimerName(String vmGroupIdentifier) {
+        return genObjectName("Cloud-AutoScale-Timer", vmGroupIdentifier);
+    }
+
+    private String generateAutoScaleProfileName(String vmGroupIdentifier) {
+        return genObjectName("Cloud-AutoScale-Profile", vmGroupIdentifier);
+    }
+
+    private String generateAutoScaleScaleUpActionName(String vmGroupIdentifier) {
+        return genObjectName("Cloud-AutoScale-ScaleUpAction", vmGroupIdentifier);
+    }
+
+    private String generateAutoScaleScaleDownActionName(String vmGroupIdentifier) {
+        return genObjectName("Cloud-AutoScale-ScaleDownAction", vmGroupIdentifier);
+    }
+
+    private String generateAutoScalePolicyName(String vmGroupIdentifier, String poilcyId) {
+        return genObjectName("Cloud-AutoScale-Policy", vmGroupIdentifier, poilcyId);
+    }
+
+    private String generateAutoScaleMinPolicyName(String vmGroupIdentifier) {
+        return genObjectName("Cloud-AutoScale-Policy-Min", vmGroupIdentifier);
+    }
+
+    private String generateAutoScaleMaxPolicyName(String vmGroupIdentifier) {
+        return genObjectName("Cloud-AutoScale-Policy-Max", vmGroupIdentifier);
+    }
+
+    private String generateSnmpMetricTableName(String vmGroupIdentifier) {
+        return genObjectName("Cloud-MTbl", vmGroupIdentifier);
+    }
+
+    private String generateSnmpMonitorName(String vmGroupIdentifier) {
+        return genObjectName("Cloud-Mon", vmGroupIdentifier);
+    }
+
+    private String generateSnmpMetricName(String counterName) {
+        return counterName.replace(' ', '_');
+    }
+
+    private String generateSslCertName(String fingerPrint) {
+        // maximum length supported by NS is 31
+        // the first 20 characters of the SHA-1 checksum are the unique id
+        String uniqueId = fingerPrint.replace(":", "").substring(0, 20);
+
+        return genObjectName("Cloud-Cert", uniqueId);
+    }
+
+    private String generateSslKeyName(String fingerPrint) {
+        String uniqueId = fingerPrint.replace(":", "").substring(0, 20);
+        return genObjectName("Cloud-Key", uniqueId);
+    }
+
+    private String generateSslCertKeyName(String fingerPrint) {
+        String uniqueId = fingerPrint.replace(":", "").substring(0, 20);
+        return genObjectName("Cloud-Cert", uniqueId);
+    }
+
+    private String genObjectName(Object... args) {
+        StringBuffer buff = new StringBuffer();
+        for (int i = 0; i < args.length; i++) {
+            buff.append(args[i]);
+            if (i != args.length - 1) {
+                buff.append(_objectNamePathSep);
+            }
+        }
+        return buff.toString();
+    }
+
+    @Override
+    public IAgentControl getAgentControl() {
+        return null;
+    }
+
+    @Override
+    public PingCommand getCurrentStatus(long id) {
+        return new PingCommand(Host.Type.NetScalerControlCenter, id);
+    }
+
+    @Override
+    public Type getType() {
+        return Host.Type.NetScalerControlCenter ;
+    }
+
+    @Override
+    public void setAgentControl(IAgentControl agentControl) {
+        return;
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    @Override
+    public boolean start() {
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        return true;
+    }
+
+    @Override
+    public void disconnected() {
+        return;
+    }
+
+    @Override
+    public void setName(String name) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void setConfigParams(Map<String, Object> params) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public Map<String, Object> getConfigParams() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public int getRunLevel() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public void setRunLevel(int level) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public String getSessionID() {
+        return _sessionid;
+    }
+    public static String cleanPassword(String logString) {
+        String cleanLogString = null;
+        if (logString != null) {
+            cleanLogString = logString;
+            String[] temp = logString.split(",");
+            int i = 0;
+            if (temp != null) {
+                while (i < temp.length) {
+                    temp[i] = StringUtils.cleanString(temp[i]);
+                    i++;
+                }
+                List<String> stringList = new ArrayList<String>();
+                Collections.addAll(stringList, temp);
+                cleanLogString = StringUtils.join(stringList, ",");
+            }
+        }
+        return cleanLogString;
+    }
+    public static HttpClient getHttpClient() {
+
+        HttpClient httpClient = null;
+        TrustStrategy easyStrategy = new TrustStrategy() {
+            @Override
+            public boolean isTrusted(X509Certificate[] chain, String authType)
+                    throws CertificateException {
+                return true;
+            }
+        };
+
+        try {
+            SSLSocketFactory sf = new SSLSocketFactory(easyStrategy, new AllowAllHostnameVerifier());
+            SchemeRegistry registry = new SchemeRegistry();
+            registry.register(new Scheme("https", DEFAULT_PORT, sf));
+            ClientConnectionManager ccm = new BasicClientConnectionManager(registry);
+            httpClient = new DefaultHttpClient(ccm);
+        } catch (KeyManagementException e) {
+            s_logger.error("failed to initialize http client " + e.getMessage());
+        } catch (UnrecoverableKeyException e) {
+            s_logger.error("failed to initialize http client " + e.getMessage());
+        } catch (NoSuchAlgorithmException e) {
+            s_logger.error("failed to initialize http client " + e.getMessage());
+        } catch (KeyStoreException e) {
+            s_logger.error("failed to initialize http client " + e.getMessage());
+        }
+        return httpClient;
+    }
+
+    public static String getHttpRequest(final String jsonCmd, final URI agentUri, String sessionID) {
+        // Using Apache's HttpClient for HTTP POST
+        // Java-only approach discussed at on StackOverflow concludes with
+        // comment to use Apache HttpClient
+        // http://stackoverflow.com/a/2793153/939250, but final comment is to
+        // use Apache.
+        String logMessage = StringEscapeUtils.unescapeJava(jsonCmd);
+        logMessage = cleanPassword(logMessage);
+        s_logger.debug("POST request to " + agentUri.toString()
+                + " with contents " + logMessage);
+
+        // Create request
+        HttpClient httpClient = getHttpClient();
+        String result = null;
+
+        // TODO: are there timeout settings and worker thread settings to tweak?
+        try {
+            //HttpPost request = new HttpPost(agentUri);
+            HttpGet request = new HttpGet(agentUri);
+
+            // JSON encode command
+            // Assumes command sits comfortably in a string, i.e. not used for
+            // large data transfers
+            StringEntity cmdJson = new StringEntity(jsonCmd);
+            request.addHeader("content-type", "application/json");
+            request.addHeader("Cookie", "SessId=" + sessionID);
+            //request.setEntity(cmdJson);
+            s_logger.debug("Sending cmd to " + agentUri.toString()
+                    + " cmd data:" + logMessage);
+            HttpResponse response = httpClient.execute(request);
+
+            // Unsupported commands will not route.
+            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
+                String errMsg = "Failed to send : HTTP error code : " + response.getStatusLine().getStatusCode();
+                s_logger.error(errMsg);
+                String unsupportMsg = "Unsupported command " + agentUri.getPath() + ".  Are you sure you got the right f of" + " server?";
+                Answer ans = new UnsupportedAnswer(null, unsupportMsg);
+                s_logger.error(ans);
+                result = s_gson.toJson(new Answer[] {ans});
+            } else if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+                String errMsg = "Failed send to " + agentUri.toString() + " : HTTP error code : " + response.getStatusLine().getStatusCode();
+                s_logger.error(errMsg);
+                return null;
+            } else {
+                result = EntityUtils.toString(response.getEntity());
+                String logResult = cleanPassword(StringEscapeUtils.unescapeJava(result));
+                s_logger.debug("Get response is " + logResult);
+            }
+        } catch (ClientProtocolException protocolEx) {
+            // Problem with HTTP message exchange
+            s_logger.error(protocolEx);
+        } catch (IOException connEx) {
+            // Problem with underlying communications
+            s_logger.error(connEx);
+        } finally {
+            httpClient.getConnectionManager().shutdown();
+        }
+        return result;
+    }
+
+    public static String postHttpRequest(final String jsonCmd, final URI agentUri, String sessionID) {
+        // Using Apache's HttpClient for HTTP POST
+        // Java-only approach discussed at on StackOverflow concludes with
+        // comment to use Apache HttpClient
+        // http://stackoverflow.com/a/2793153/939250, but final comment is to
+        // use Apache.
+        String logMessage = StringEscapeUtils.unescapeJava(jsonCmd);
+        logMessage = cleanPassword(logMessage);
+        s_logger.debug("POST request to " + agentUri.toString()
+                + " with contents " + logMessage);
+
+        // Create request
+        HttpClient httpClient = getHttpClient();
+/*        TrustStrategy easyStrategy = new TrustStrategy() {
+            @Override
+            public boolean isTrusted(X509Certificate[] chain, String authType)
+                    throws CertificateException {
+                return true;
+            }
+        };
+
+        try {
+            SSLSocketFactory sf = new SSLSocketFactory(easyStrategy, new AllowAllHostnameVerifier());
+            SchemeRegistry registry = new SchemeRegistry();
+            registry.register(new Scheme("https", DEFAULT_PORT, sf));
+            ClientConnectionManager ccm = new BasicClientConnectionManager(registry);
+            httpClient = new DefaultHttpClient(ccm);
+        } catch (KeyManagementException e) {
+            s_logger.error("failed to initialize http client " + e.getMessage());
+        } catch (UnrecoverableKeyException e) {
+            s_logger.error("failed to initialize http client " + e.getMessage());
+        } catch (NoSuchAlgorithmException e) {
+            s_logger.error("failed to initialize http client " + e.getMessage());
+        } catch (KeyStoreException e) {
+            s_logger.error("failed to initialize http client " + e.getMessage());
+        }
+*/
+        String result = null;
+
+        // TODO: are there timeout settings and worker thread settings to tweak?
+        try {
+            HttpPost request = new HttpPost(agentUri);
+
+            // JSON encode command
+            // Assumes command sits comfortably in a string, i.e. not used for
+            // large data transfers
+            StringEntity cmdJson = new StringEntity(jsonCmd);
+            request.addHeader("content-type", "application/json");
+            request.addHeader("Cookie", "SessId=" + sessionID);
+            request.setEntity(cmdJson);
+            s_logger.debug("Sending cmd to " + agentUri.toString()
+                    + " cmd data:" + logMessage + "SEssion id: " + sessionID);
+            HttpResponse response = httpClient.execute(request);
+
+            // Unsupported commands will not route.
+            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
+                String errMsg = "Failed to send : HTTP error code : " + response.getStatusLine().getStatusCode();
+                s_logger.error(errMsg);
+                String unsupportMsg = "Unsupported command " + agentUri.getPath() + ".  Are you sure you got the right type of" + " server?";
+                Answer ans = new UnsupportedAnswer(null, unsupportMsg);
+                s_logger.error(ans);
+                result = s_gson.toJson(new Answer[] {ans});
+            } else if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+                String errMsg = "Failed send to " + agentUri.toString() + " : HTTP error code : " + response.getStatusLine().getStatusCode();
+                s_logger.error(errMsg);
+                return null;
+            } else {
+                result = EntityUtils.toString(response.getEntity());
+                String logResult = cleanPassword(StringEscapeUtils.unescapeJava(result));
+                s_logger.debug("POST response is " + logResult);
+            }
+        } catch (ClientProtocolException protocolEx) {
+            // Problem with HTTP message exchange
+            s_logger.error(protocolEx);
+        } catch (IOException connEx) {
+            // Problem with underlying communications
+            s_logger.error(connEx);
+        } finally {
+            httpClient.getConnectionManager().shutdown();
+        }
+        return result;
+    }
+}
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index 551c61e..50e3e7a 100644
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -811,7 +811,14 @@ public enum Config {
             "600",
             "Time Interval to fetch the LB health check states (in sec)",
             null),
-
+    NCCCmdTimeOut(
+            "Advanced",
+            ManagementServer.class,
+            Long.class,
+            "ncc.command.timeout",
+            "600000", // 10 minutes
+            "Command Timeout Interval (in millisec)",
+            null),
     DirectAttachNetworkEnabled(
             "Advanced",
             ManagementServer.class,
diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
index 75267c7..f417283 100644
--- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
+++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
@@ -1112,7 +1112,12 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase
         if (!(startup[0] instanceof StartupExternalLoadBalancerCommand)) {
             return null;
         }
-        host.setType(Host.Type.ExternalLoadBalancer);
+        if(host.getName().equalsIgnoreCase("NetScalerControlCenter")) {
+            host.setType(Host.Type.NetScalerControlCenter);
+        }
+        else {
+            host.setType(Host.Type.ExternalLoadBalancer);
+        }
         return host;
     }
 
diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java
index b5d67c7..f47123d 100644
--- a/server/src/com/cloud/server/StatsCollector.java
+++ b/server/src/com/cloud/server/StatsCollector.java
@@ -396,6 +396,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.SecondaryStorageVM.toString());
                 sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.ExternalFirewall.toString());
                 sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.ExternalLoadBalancer.toString());
+                sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.NetScalerControlCenter.toString());
                 sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.L2Networking.toString());
                 sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.BaremetalDhcp.toString());
                 sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.BaremetalPxe.toString());
diff --git a/setup/db/db/schema-4930to41000.sql b/setup/db/db/schema-4930to41000.sql
index 59c452f..edc9d60 100644
--- a/setup/db/db/schema-4930to41000.sql
+++ b/setup/db/db/schema-4930to41000.sql
@@ -254,4 +254,27 @@ CREATE TABLE `cloud`.`firewall_rules_dcidrs`(
   UNIQUE KEY `unique_rule_dcidrs` (`firewall_rule_id`, `destination_cidr`),
   KEY `fk_firewall_dcidrs_firewall_rules` (`firewall_rule_id`),
   CONSTRAINT `fk_firewall_dcidrs_firewall_rules` FOREIGN KEY (`firewall_rule_id`) REFERENCES `firewall_rules` (`id`) ON DELETE CASCADE
-)ENGINE=InnoDB DEFAULT CHARSET=utf8;
\ No newline at end of file
+)ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `cloud`.`netscaler_servicepackages`;
+CREATE TABLE `cloud`.`netscaler_servicepackages` (
+  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `uuid` varchar(255) UNIQUE,
+  `name` varchar(255) UNIQUE COMMENT 'name of the service package',
+  `description` varchar(255) COMMENT 'description of the service package',
+  PRIMARY KEY  (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `cloud`.`external_netscaler_controlcenter`;
+CREATE TABLE `cloud`.`external_netscaler_controlcenter` (
+  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `uuid` varchar(255) UNIQUE,
+  `username` varchar(255) COMMENT 'username of the NCC',
+  `password` varchar(255) COMMENT 'password of NCC',
+  `ncc_ip` varchar(255) COMMENT 'IP of NCC Manager',
+  `num_retries` bigint unsigned NOT NULL default 2 COMMENT 'Number of retries in ncc for command failure',
+  PRIMARY KEY  (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+ALTER TABLE `cloud`.`sslcerts` ADD COLUMN `name` varchar(255) NULL default NULL COMMENT 'Name of the Certificate';
+ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `service_package_id` varchar(255) NULL default NULL COMMENT 'Netscaler ControlCenter Service Package';
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
"commits@cloudstack.apache.org" <commits@cloudstack.apache.org>.

Mime
View raw message