From 4f774d227ba0b3c18975bb39248a209cd2fe8fdf Mon Sep 17 00:00:00 2001 From: Vijay Date: Thu, 9 Aug 2012 14:03:24 +0530 Subject: [PATCH] Update for threshold parameter in NetScaler --- .../network/resource/NetscalerResource.java | 4608 ++++++++--------- deps/cloud-netscaler.jar | Bin 3289834 -> 3291866 bytes 2 files changed, 2304 insertions(+), 2304 deletions(-) diff --git a/core/src/com/cloud/network/resource/NetscalerResource.java b/core/src/com/cloud/network/resource/NetscalerResource.java index a32e2952e04..2bbcdb20eef 100644 --- a/core/src/com/cloud/network/resource/NetscalerResource.java +++ b/core/src/com/cloud/network/resource/NetscalerResource.java @@ -1,2304 +1,2304 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 -package com.cloud.network.resource; - -import 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.log4j.Logger; - -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.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.servicegroup; -import com.citrix.netscaler.nitro.resource.config.basic.servicegroup_lbmonitor_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.Interface; -import com.citrix.netscaler.nitro.resource.config.network.inat; -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.nshardware; -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.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.device_profile; -import com.citrix.sdx.nitro.resource.config.mps; -import com.citrix.sdx.nitro.resource.config.ns; -import com.citrix.sdx.nitro.resource.config.xen_vpx_image; -import com.cloud.agent.IAgentControl; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer; -import com.cloud.agent.api.ExternalNetworkResourceUsageCommand; -import com.cloud.agent.api.MaintainAnswer; -import com.cloud.agent.api.MaintainCommand; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.ReadyAnswer; -import com.cloud.agent.api.ReadyCommand; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupExternalLoadBalancerCommand; -import com.cloud.agent.api.routing.CreateLoadBalancerApplianceCommand; -import com.cloud.agent.api.routing.DestroyLoadBalancerApplianceCommand; -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.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.StickinessPolicyTO; -import com.cloud.agent.api.to.StaticNatRuleTO; -import com.cloud.api.ApiConstants; -import com.cloud.host.Host; -import com.cloud.host.Host.Type; -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.exception.ExecutionException; -import com.cloud.utils.net.NetUtils; -import com.google.gson.Gson; - -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; -} - -public class NetscalerResource implements ServerResource { - - // deployment configuration - private String _name; - private String _zoneId; - private String _physicalNetworkId; - public String _ip; - public String _username; - public 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 static final Logger s_logger = Logger.getLogger(NetscalerResource.class); - protected Gson _gson; - private String _objectNamePathSep = "-"; - - // 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; - - Long _timeout = new Long(100000); - base_response apiCallResult; - - public NetscalerResource() { - _gson = GsonHelper.getGsonLogger(); - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - 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"); - } - - _publicInterface = (String) params.get("publicinterface"); - if (_publicInterface == null) { - throw new ConfigurationException("Unable to find public interface in the configuration parameters"); - } - - _privateInterface = (String) params.get("privateinterface"); - if (_privateInterface == null) { - throw new ConfigurationException("Unable to find private interface 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"); - } - - _isSdx = _deviceName.equalsIgnoreCase("NetscalerSDXLoadBalancer"); - - _inline = Boolean.parseBoolean((String) params.get("inline")); - - if (((String) params.get("cloudmanaged")) != null) { - _cloudManaged = Boolean.parseBoolean((String) params.get("cloudmanaged")); - } - - // validate device configuration parameters - login(); - validateDeviceType(_deviceName); - validateInterfaces(_publicInterface, _privateInterface); - - // enable load balancing feature - enableLoadBalancingFeature(); - - // if the the device is cloud stack provisioned then make it part of the public network - if (_cloudManaged) { - _publicIP = (String) params.get("publicip"); - _publicIPGateway = (String) params.get("publicipgateway"); - _publicIPNetmask = (String) params.get("publicipnetmask"); - _publicIPVlan = (String) params.get("publicipvlan"); - if ("untagged".equalsIgnoreCase(_publicIPVlan)) { - // if public network is un-tagged just add subnet IP - addSubnetIP(_publicIP, _publicIPNetmask); - } else { - // if public network is tagged then add vlan and bind subnet IP to the vlan - addGuestVlanAndSubnet(Long.parseLong(_publicIPVlan), _publicIP, _publicIPNetmask, false); - } - } - - return true; - } catch (Exception e) { - throw new ConfigurationException(e.getMessage()); - } - } - - private void login() throws ExecutionException { - try { - if (!_isSdx) { - _netscalerService = new com.citrix.netscaler.nitro.service.nitro_service(_ip, "https"); - _netscalerService.set_credential(_username, _password); - _netscalerService.set_timeout(_timeout); - apiCallResult = _netscalerService.login(); - if (apiCallResult.errorcode != 0) { - throw new ExecutionException("Failed to log in to Netscaler device at " + _ip + " due to error " + apiCallResult.errorcode + " and message " + apiCallResult.message); - } - } else { - _netscalerSdxService = new com.citrix.sdx.nitro.service.nitro_service(_ip, "https"); - _netscalerSdxService.set_credential(_username, _password); - com.citrix.sdx.nitro.resource.base.login login = _netscalerSdxService.login(); - if (login == null) { - throw new ExecutionException("Failed to log in to Netscaler device at " + _ip + " due to error " + apiCallResult.errorcode + " and message " + apiCallResult.message); - } - } - } catch (nitro_exception e) { - throw new ExecutionException("Failed to log in to Netscaler device at " + _ip + " due to " + e.getMessage()); - } catch (Exception e) { - throw new ExecutionException("Failed to log in to Netscaler device at " + _ip + " due to " + e.getMessage()); - } - } - - private void enableLoadBalancingFeature() throws ExecutionException { - if (_isSdx) { - return; - } - try { - String[] features = _netscalerService.get_enabled_features(); - if (features != null) { - for (String feature : features) { - if (feature.equalsIgnoreCase("LB")) { - return; - } - } - } - - // enable load balancing on the device - String[] feature = new String[1]; - feature[0] = "LB"; - apiCallResult = _netscalerService.enable_features(feature); - if (apiCallResult.errorcode != 0) { - throw new ExecutionException("Enabling load balancing feature on the device failed."); - } - } catch (nitro_exception e) { - throw new ExecutionException("Enabling load balancing feature on the device failed due to " + e.getMessage()); - } catch (Exception e) { - throw new ExecutionException("Enabling load balancing feature on the device failed due to " + e.getMessage()); - } - } - - private void validateInterfaces(String publicInterface, String privateInterface) throws ExecutionException { - try { - if (!_isSdx && !_cloudManaged) { - Interface publicIf = Interface.get(_netscalerService, publicInterface); - Interface privateIf = Interface.get(_netscalerService, privateInterface); - if (publicIf != null || privateIf != null) { - return; - } else { - throw new ExecutionException("Invalid interface name specified for public/private interfaces."); - } - } - } catch (nitro_exception e) { - if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) { - throw new ExecutionException("Invalid interface name specified for public and private interfaces."); - } else { - throw new ExecutionException("Failed to verify public interface and private intefaces are valid due to " + e.getMessage()); - } - } catch (Exception e) { - throw new ExecutionException("Failed to verify public interface and private intefaces are valid due to " + e.getMessage()); - } - } - - private void validateDeviceType(String deviceType) throws ExecutionException { - try { - if (!_isSdx && !_cloudManaged) { - nshardware nsHw = com.citrix.netscaler.nitro.resource.config.ns.nshardware.get(_netscalerService); - if (nsHw == null) { - throw new ExecutionException("Failed to get the hardware description of the Netscaler device at " + _ip); - } else { - if ((_deviceName.equalsIgnoreCase("NetscalerMPXLoadBalancer") && nsHw.get_hwdescription().contains("MPX")) - || (_deviceName.equalsIgnoreCase("NetscalerVPXLoadBalancer") && nsHw.get_hwdescription().contains("NetScaler Virtual Appliance"))) { - return; - } - throw new ExecutionException("Netscalar device type specified does not match with the actuall device type."); - } - } else if (_isSdx) { - mps serviceVM = mps.get(_netscalerSdxService); - if (serviceVM != null) { - if (serviceVM.get_platform().contains("SDX") || serviceVM.get_product().contains("SDX")) { - return; - } else { - throw new ExecutionException("Netscalar device type specified does not match with the actuall device type."); - } - } else { - throw new ExecutionException("Failed to get the hardware details of the Netscaler device at " + _ip); - } - } - } catch (Exception e) { - throw new ExecutionException("Failed to verify device type specified when matching with actuall device type due to " + e.getMessage()); - } - } - - @Override - public StartupCommand[] initialize() { - StartupExternalLoadBalancerCommand cmd = new StartupExternalLoadBalancerCommand(); - cmd.setName(_name); - cmd.setDataCenter(_zoneId); - cmd.setPod(""); - cmd.setPrivateIpAddress(_ip); - cmd.setStorageIpAddress(""); - cmd.setVersion(""); - cmd.setGuid(_guid); - return new StartupCommand[] { cmd }; - } - - @Override - public Answer executeRequest(Command cmd) { - Answer ans = executeRequest(cmd, _numRetries); - return ans; - } - - 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 { - 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(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.valueOf(ip.getVlanId()); - 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 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); - - if (loadBalancer.isAutoScaleVmGroupTO()) { - applyAutoScaleConfig(loadBalancer); - return new Answer(cmd); - } - - boolean destinationsToAdd = 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"); - } - - 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"); - 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"); - } - } - 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); - } - } - } - - 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_feature_license("Standard"); - ns_obj.set_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); - - // use the first device profile available on the SDX to create an instance of VPX - device_profile[] profiles = device_profile.get(_netscalerSdxService); - if (!(profiles != null && profiles.length >= 1)) { - new Answer(cmd, new ExecutionException("Failed to create VPX instance on the netscaler SDX device " + _ip + - " as there are no admin profile to use for creating VPX.")); - } - String profileName = profiles[0].get_name(); - ns_obj.set_nsroot_profile(profileName); - - // 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_vpx_image[] vpxImages = xen_vpx_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) { - 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_ns_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_ns_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_credential(username, password); - _netscalerService.set_timeout(_timeout); - 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 NetscalerResource(), - 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 void enableVPXInterfaces(String publicIf, String privateIf, ns ns_obj) { - // 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")) { - ns_obj.set_if_10_1(new Boolean(true)); - } - - if (publicIf.equals("10/2") || privateIf.equals("10/2")) { - ns_obj.set_if_10_2(new Boolean(true)); - } - - if (publicIf.equals("10/3") || privateIf.equals("10/3")) { - ns_obj.set_if_10_3(new Boolean(true)); - } - - if (publicIf.equals("10/4") || privateIf.equals("10/4")) { - ns_obj.set_if_10_4(new Boolean(true)); - } - - if (publicIf.equals("10/5") || privateIf.equals("10/5")) { - ns_obj.set_if_10_5(new Boolean(true)); - } - - if (publicIf.equals("10/6") || privateIf.equals("10/6")) { - ns_obj.set_if_10_6(new Boolean(true)); - } - - if (publicIf.equals("10/7") || privateIf.equals("10/7")) { - ns_obj.set_if_10_7(new Boolean(true)); - } - - if (publicIf.equals("10/8") || privateIf.equals("10/8")) { - ns_obj.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")) { - ns_obj.set_if_1_1(new Boolean(true)); - } - - if (publicIf.equals("1/2") || privateIf.equals("1/2")) { - ns_obj.set_if_1_2(new Boolean(true)); - } - - if (publicIf.equals("1/3") || privateIf.equals("1/3")) { - ns_obj.set_if_1_3(new Boolean(true)); - } - - if (publicIf.equals("1/4") || privateIf.equals("1/4")) { - ns_obj.set_if_1_4(new Boolean(true)); - } - - if (publicIf.equals("1/5") || privateIf.equals("1/5")) { - ns_obj.set_if_1_5(new Boolean(true)); - } - - if (publicIf.equals("1/6") || privateIf.equals("1/6")) { - ns_obj.set_if_1_6(new Boolean(true)); - } - - if (publicIf.equals("1/7") || privateIf.equals("1/7")) { - ns_obj.set_if_1_7(new Boolean(true)); - } - - if (publicIf.equals("1/8") || privateIf.equals("1/8")) { - ns_obj.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); - inat iNatRule = 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); - } - } else { - try { - inat.delete(_netscalerService, iNatRuleName); - } 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 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 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 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 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 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 { - - lbvserver_servicegroup_binding vserver_servicegroup_binding = new lbvserver_servicegroup_binding(); - - try { - lbvserver_servicegroup_binding[] result = vserver_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 servicegroup getServiceGroupIfExisits(String lbVServerName) throws ExecutionException { - try { - return servicegroup.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 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 - 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.getProtocol(); - StickinessPolicyTO[] stickyPolicies = loadBalancer.getStickinessPolicies(); - String nsProtocol = "TCP"; - - 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 (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> paramsList = stickinessPolicy.getParams(); - for (Pair 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) { - s_logger.warn("Failed to create virtual server ", 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()); - } - } - - 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 (vmGroupTO.getState().equals("new")) { - assert !loadBalancer.isRevoked(); - createAutoScaleConfig(loadBalancer); - } - else if (loadBalancer.isRevoked() || vmGroupTO.getState().equals("revoke")) { - removeAutoScaleConfig(loadBalancer); - } - else if (vmGroupTO.getState().equals("enabled")) { - assert !loadBalancer.isRevoked(); - enableAutoScaleConfig(loadBalancer, false); - } - else if (vmGroupTO.getState().equals("disabled")) { - assert !loadBalancer.isRevoked(); - disableAutoScaleConfig(loadBalancer, false); - } else { - // /// This should never happen - throw new ExecutionException("Unknown vmGroup State :" + vmGroupTO.getState()); - } - } - - @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(); - String vmGroupIdentifier = 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(vmGroupIdentifier); - servicegroup serviceGroup = getServiceGroupIfExisits(serviceGroupName); - if (serviceGroup == null) { - // add servicegroup lb_autoscaleGroup -autoscale POLICY -memberPort 80 - int memberPort = vmGroupTO.getMemberPort(); - try { - 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); - vserver_servicegroup_binding.add(_netscalerService, vserver_servicegroup_binding); - } catch (Exception e) { - throw e; - } - } - - // Create the autoscale config - enableAutoScaleConfig(loadBalancerTO, false); - return true; - } - - @SuppressWarnings("static-access") - private synchronized boolean removeAutoScaleConfig(LoadBalancerTO loadBalancerTO) throws Exception, ExecutionException { - String srcIp = loadBalancerTO.getSrcIp(); - int srcPort = loadBalancerTO.getSrcPort(); - String vmGroupIdentifier = generateAutoScaleVmGroupIdentifier(loadBalancerTO); - - String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort); - String serviceGroupName = generateAutoScaleServiceGroupName(vmGroupIdentifier); - - if (loadBalancerTO.getAutoScaleVmGroupTO().getState().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); - vserver_servicegroup_binding.delete(_netscalerService, vserver_servicegroup_binding); - } catch (Exception e) { - throw e; - } - } - - if (getServiceGroupIfExisits(serviceGroupName) != null) { - // 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(vmGroupIdentifier); - 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 policies = vmGroupTO.getPolicies(); - int interval = vmGroupTO.getInterval(); - int snmpPort = profileTO.getSnmpPort(); - String snmpCommunity = profileTO.getSnmpCommunity(); - long cur_prirotiy = 1; - - 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); - vserver.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(); - - com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleprofile autoscaleProfile = new com.citrix.netscaler.nitro.resource.config.autoscale.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); - timer.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); - scaleUpAction.set_quiettime(scaleUpQuietTime); - String scaleUpParameters = "command=deployVirtualMachine" + "&" + - ApiConstants.ZONE_ID + "=" + profileTO.getZoneId() + "&" + - ApiConstants.SERVICE_OFFERING_ID + "=" + profileTO.getServiceOfferingId() + "&" + - ApiConstants.TEMPLATE_ID + "=" + profileTO.getTemplateId() + "&" + - ((profileTO.getOtherDeployParams() == null) ? "" : (profileTO.getOtherDeployParams() + "&")) + - "lbruleid=" + loadBalancerTO.getUuid(); - scaleUpAction.set_parameters(scaleUpParameters); - scaleUpAction.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); - scaleDownAction.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 snmpMetrics = new HashMap(); - for (AutoScalePolicyTO autoScalePolicyTO : policies) { - List 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); - metricTable.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 - 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)); - monitor.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); - // metrics, basically use it for autoscaling purpose only. - 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); - metrictable_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_lbmetrictable_binding monitor_metrictable_binding = new -// lbmonitor_lbmetrictable_binding(); - lbmonitor_metric_binding monitor_metric_binding = new lbmonitor_metric_binding(); - ; - try { - monitor_metric_binding.set_monitorname(monitorName); - monitor_metric_binding.set_metric(counterName); - monitor_metric_binding.set_metricthreshold(1); - monitor_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(vmGroupIdentifier); - AutoScaleVmGroupTO vmGroupTO = loadBalancerTO.getAutoScaleVmGroupTO(); - List 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 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); - scaleDownAction.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); - scaleUpAction.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); - timer.delete(_netscalerService, timer); - } catch (Exception e) { - // Ignore Exception on cleanup - if (!isCleanUp) - throw e; - } - - // Delete AutoScale Profile - com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleprofile autoscaleProfile = new com.citrix.netscaler.nitro.resource.config.autoscale.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"); - monitor.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); - metricTable.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); - timerPolicy.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_global("DEFAULT"); // vserver name is present in the expression, this is default -// now - timer_policy_binding.set_samplesize(sampleSize); - timer_policy_binding.set_thresholdsize(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); - timer_policy_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); - // timer_policy_binding.set_global("DEFAULT"); // by default only global bank - timer_policy_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); - timerPolicy.delete(_netscalerService, timerPolicy); - } catch (Exception e) { - // Ignore Exception on cleanup - if (!isCleanUp) - throw e; - } - - } - - private boolean isAutoScaleSupportedInNetScaler() throws ExecutionException { - autoscaleprofile autoscaleProfile = 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 generateNSVirtualServerName(String srcIp, long srcPort) { - return genObjectName("Cloud-VirtualServer", 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(String vmGroupIdentifier) { - return genObjectName("Cloud-AutoScale-SvcGrp", vmGroupIdentifier); - } - - 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 genObjectName(Object... args) { - String objectName = ""; - for (int i = 0; i < args.length; i++) { - objectName += args[i]; - if (i != args.length - 1) { - objectName += _objectNamePathSep; - } - } - return objectName; - } - - @Override - public IAgentControl getAgentControl() { - return null; - } - - @Override - public PingCommand getCurrentStatus(long id) { - return new PingCommand(Host.Type.ExternalLoadBalancer, id); - } - - @Override - public Type getType() { - return Host.Type.ExternalLoadBalancer; - } - - @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; - } -} +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.network.resource; + +import 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.log4j.Logger; + +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.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.servicegroup; +import com.citrix.netscaler.nitro.resource.config.basic.servicegroup_lbmonitor_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.Interface; +import com.citrix.netscaler.nitro.resource.config.network.inat; +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.nshardware; +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.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.device_profile; +import com.citrix.sdx.nitro.resource.config.mps; +import com.citrix.sdx.nitro.resource.config.ns; +import com.citrix.sdx.nitro.resource.config.xen_vpx_image; +import com.cloud.agent.IAgentControl; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer; +import com.cloud.agent.api.ExternalNetworkResourceUsageCommand; +import com.cloud.agent.api.MaintainAnswer; +import com.cloud.agent.api.MaintainCommand; +import com.cloud.agent.api.PingCommand; +import com.cloud.agent.api.ReadyAnswer; +import com.cloud.agent.api.ReadyCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupExternalLoadBalancerCommand; +import com.cloud.agent.api.routing.CreateLoadBalancerApplianceCommand; +import com.cloud.agent.api.routing.DestroyLoadBalancerApplianceCommand; +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.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.StickinessPolicyTO; +import com.cloud.agent.api.to.StaticNatRuleTO; +import com.cloud.api.ApiConstants; +import com.cloud.host.Host; +import com.cloud.host.Host.Type; +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.exception.ExecutionException; +import com.cloud.utils.net.NetUtils; +import com.google.gson.Gson; + +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; +} + +public class NetscalerResource implements ServerResource { + + // deployment configuration + private String _name; + private String _zoneId; + private String _physicalNetworkId; + public String _ip; + public String _username; + public 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 static final Logger s_logger = Logger.getLogger(NetscalerResource.class); + protected Gson _gson; + private String _objectNamePathSep = "-"; + + // 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; + + Long _timeout = new Long(100000); + base_response apiCallResult; + + public NetscalerResource () { + _gson = GsonHelper.getGsonLogger(); + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + 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"); + } + + _publicInterface = (String) params.get("publicinterface"); + if (_publicInterface == null) { + throw new ConfigurationException("Unable to find public interface in the configuration parameters"); + } + + _privateInterface = (String) params.get("privateinterface"); + if (_privateInterface == null) { + throw new ConfigurationException("Unable to find private interface 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"); + } + + _isSdx = _deviceName.equalsIgnoreCase("NetscalerSDXLoadBalancer"); + + _inline = Boolean.parseBoolean((String) params.get("inline")); + + if (((String) params.get("cloudmanaged")) != null) { + _cloudManaged = Boolean.parseBoolean((String) params.get("cloudmanaged")); + } + + // validate device configuration parameters + login(); + validateDeviceType(_deviceName); + validateInterfaces(_publicInterface, _privateInterface); + + //enable load balancing feature + enableLoadBalancingFeature(); + + //if the the device is cloud stack provisioned then make it part of the public network + if (_cloudManaged) { + _publicIP = (String) params.get("publicip"); + _publicIPGateway = (String) params.get("publicipgateway"); + _publicIPNetmask = (String) params.get("publicipnetmask"); + _publicIPVlan = (String) params.get("publicipvlan"); + if ("untagged".equalsIgnoreCase(_publicIPVlan)) { + // if public network is un-tagged just add subnet IP + addSubnetIP(_publicIP, _publicIPNetmask); + } else { + // if public network is tagged then add vlan and bind subnet IP to the vlan + addGuestVlanAndSubnet(Long.parseLong(_publicIPVlan), _publicIP, _publicIPNetmask, false); + } + } + + return true; + } catch (Exception e) { + throw new ConfigurationException(e.getMessage()); + } + } + + private void login() throws ExecutionException { + try { + if (!_isSdx) { + _netscalerService = new com.citrix.netscaler.nitro.service.nitro_service(_ip, "https"); + _netscalerService.set_credential(_username, _password); + _netscalerService.set_timeout(_timeout); + apiCallResult = _netscalerService.login(); + if (apiCallResult.errorcode != 0) { + throw new ExecutionException ("Failed to log in to Netscaler device at " + _ip + " due to error " + apiCallResult.errorcode + " and message " + apiCallResult.message); + } + } else { + _netscalerSdxService = new com.citrix.sdx.nitro.service.nitro_service(_ip, "https"); + _netscalerSdxService.set_credential(_username, _password); + com.citrix.sdx.nitro.resource.base.login login = _netscalerSdxService.login(); + if (login == null) { + throw new ExecutionException ("Failed to log in to Netscaler device at " + _ip + " due to error " + apiCallResult.errorcode + " and message " + apiCallResult.message); + } + } + } catch (nitro_exception e) { + throw new ExecutionException("Failed to log in to Netscaler device at " + _ip + " due to " + e.getMessage()); + } catch (Exception e) { + throw new ExecutionException("Failed to log in to Netscaler device at " + _ip + " due to " + e.getMessage()); + } + } + + private void enableLoadBalancingFeature() throws ExecutionException { + if (_isSdx) { + return; + } + try { + String[] features = _netscalerService.get_enabled_features(); + if (features != null) { + for (String feature : features) { + if (feature.equalsIgnoreCase("LB")) { + return; + } + } + } + + // enable load balancing on the device + String[] feature = new String[1]; + feature[0] = "LB"; + apiCallResult = _netscalerService.enable_features(feature); + if (apiCallResult.errorcode != 0) { + throw new ExecutionException("Enabling load balancing feature on the device failed."); + } + } catch (nitro_exception e) { + throw new ExecutionException("Enabling load balancing feature on the device failed due to " + e.getMessage()); + } catch (Exception e) { + throw new ExecutionException("Enabling load balancing feature on the device failed due to " + e.getMessage()); + } + } + + private void validateInterfaces(String publicInterface, String privateInterface) throws ExecutionException { + try { + if (!_isSdx && !_cloudManaged) { + Interface publicIf = Interface.get(_netscalerService, publicInterface); + Interface privateIf = Interface.get(_netscalerService, privateInterface); + if (publicIf != null || privateIf != null) { + return; + } else { + throw new ExecutionException("Invalid interface name specified for public/private interfaces."); + } + } + } catch (nitro_exception e) { + if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) { + throw new ExecutionException("Invalid interface name specified for public and private interfaces."); + } else { + throw new ExecutionException("Failed to verify public interface and private intefaces are valid due to " + e.getMessage()); + } + } catch (Exception e) { + throw new ExecutionException("Failed to verify public interface and private intefaces are valid due to " + e.getMessage()); + } + } + + private void validateDeviceType(String deviceType) throws ExecutionException { + try { + if (!_isSdx && !_cloudManaged) { + nshardware nsHw = com.citrix.netscaler.nitro.resource.config.ns.nshardware.get(_netscalerService); + if (nsHw == null) { + throw new ExecutionException("Failed to get the hardware description of the Netscaler device at " + _ip); + } else { + if ((_deviceName.equalsIgnoreCase("NetscalerMPXLoadBalancer") && nsHw.get_hwdescription().contains("MPX")) + || (_deviceName.equalsIgnoreCase("NetscalerVPXLoadBalancer") && nsHw.get_hwdescription().contains("NetScaler Virtual Appliance"))) { + return; + } + throw new ExecutionException("Netscalar device type specified does not match with the actuall device type."); + } + } else if (_isSdx) { + mps serviceVM = mps.get(_netscalerSdxService); + if (serviceVM != null) { + if (serviceVM.get_platform().contains("SDX") || serviceVM.get_product().contains("SDX")) { + return; + } else { + throw new ExecutionException("Netscalar device type specified does not match with the actuall device type."); + } + } else { + throw new ExecutionException("Failed to get the hardware details of the Netscaler device at " + _ip); + } + } + } catch (Exception e) { + throw new ExecutionException("Failed to verify device type specified when matching with actuall device type due to " + e.getMessage()); + } + } + + @Override + public StartupCommand[] initialize() { + StartupExternalLoadBalancerCommand cmd = new StartupExternalLoadBalancerCommand(); + cmd.setName(_name); + cmd.setDataCenter(_zoneId); + cmd.setPod(""); + cmd.setPrivateIpAddress(_ip); + cmd.setStorageIpAddress(""); + cmd.setVersion(""); + cmd.setGuid(_guid); + return new StartupCommand[]{cmd}; + } + + @Override + public Answer executeRequest(Command cmd) { + Answer ans = executeRequest(cmd, _numRetries); + return ans; + } + + 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 { + 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(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.valueOf(ip.getVlanId()); + 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 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); + + if(loadBalancer.isAutoScaleVmGroupTO()) { + applyAutoScaleConfig(loadBalancer); + return new Answer(cmd); + } + + boolean destinationsToAdd = 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"); + } + + 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"); + 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"); + } + } + 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); + } + } + } + + 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_feature_license("Standard"); + ns_obj.set_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); + + // use the first device profile available on the SDX to create an instance of VPX + device_profile[] profiles = device_profile.get(_netscalerSdxService); + if (!(profiles != null && profiles.length >= 1)) { + new Answer(cmd, new ExecutionException("Failed to create VPX instance on the netscaler SDX device " + _ip + + " as there are no admin profile to use for creating VPX.")); + } + String profileName = profiles[0].get_name(); + ns_obj.set_nsroot_profile(profileName); + + // 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_vpx_image[] vpxImages = xen_vpx_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) { + 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_ns_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_ns_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_credential(username, password); + _netscalerService.set_timeout(_timeout); + 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 NetscalerResource(), + 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 void enableVPXInterfaces(String publicIf, String privateIf, ns ns_obj) { + // 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")) { + ns_obj.set_if_10_1(new Boolean(true)); + } + + if (publicIf.equals("10/2") || privateIf.equals("10/2")) { + ns_obj.set_if_10_2(new Boolean(true)); + } + + if (publicIf.equals("10/3") || privateIf.equals("10/3")) { + ns_obj.set_if_10_3(new Boolean(true)); + } + + if (publicIf.equals("10/4") || privateIf.equals("10/4")) { + ns_obj.set_if_10_4(new Boolean(true)); + } + + if (publicIf.equals("10/5") || privateIf.equals("10/5")) { + ns_obj.set_if_10_5(new Boolean(true)); + } + + if (publicIf.equals("10/6") || privateIf.equals("10/6")) { + ns_obj.set_if_10_6(new Boolean(true)); + } + + if (publicIf.equals("10/7") || privateIf.equals("10/7")) { + ns_obj.set_if_10_7(new Boolean(true)); + } + + if (publicIf.equals("10/8") || privateIf.equals("10/8")) { + ns_obj.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")) { + ns_obj.set_if_1_1(new Boolean(true)); + } + + if (publicIf.equals("1/2") || privateIf.equals("1/2")) { + ns_obj.set_if_1_2(new Boolean(true)); + } + + if (publicIf.equals("1/3") || privateIf.equals("1/3")) { + ns_obj.set_if_1_3(new Boolean(true)); + } + + if (publicIf.equals("1/4") || privateIf.equals("1/4")) { + ns_obj.set_if_1_4(new Boolean(true)); + } + + if (publicIf.equals("1/5") || privateIf.equals("1/5")) { + ns_obj.set_if_1_5(new Boolean(true)); + } + + if (publicIf.equals("1/6") || privateIf.equals("1/6")) { + ns_obj.set_if_1_6(new Boolean(true)); + } + + if (publicIf.equals("1/7") || privateIf.equals("1/7")) { + ns_obj.set_if_1_7(new Boolean(true)); + } + + if (publicIf.equals("1/8") || privateIf.equals("1/8")) { + ns_obj.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); + inat iNatRule = 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); + } + } else { + try { + inat.delete(_netscalerService, iNatRuleName); + } 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 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 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 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 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 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 { + + lbvserver_servicegroup_binding vserver_servicegroup_binding = new lbvserver_servicegroup_binding(); + + try { + lbvserver_servicegroup_binding[] result = vserver_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 servicegroup getServiceGroupIfExisits(String lbVServerName ) throws ExecutionException { + try { + return servicegroup.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 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 + 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.getProtocol(); + StickinessPolicyTO[] stickyPolicies = loadBalancer.getStickinessPolicies(); + String nsProtocol = "TCP"; + + 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 (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> paramsList = stickinessPolicy.getParams(); + for(Pair 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) { + s_logger.warn("Failed to create virtual server " , 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()); + } + } + + 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(vmGroupTO.getState().equals("new")) { + assert !loadBalancer.isRevoked(); + createAutoScaleConfig(loadBalancer); + } + else if(loadBalancer.isRevoked() || vmGroupTO.getState().equals("revoke")) { + removeAutoScaleConfig(loadBalancer); + } + else if(vmGroupTO.getState().equals("enabled")) { + assert !loadBalancer.isRevoked(); + enableAutoScaleConfig(loadBalancer, false); + } + else if(vmGroupTO.getState().equals("disabled")) { + assert !loadBalancer.isRevoked(); + disableAutoScaleConfig(loadBalancer, false); + } else { + ///// This should never happen + throw new ExecutionException("Unknown vmGroup State :" + vmGroupTO.getState()); + } + } + + @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(); + String vmGroupIdentifier = 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(vmGroupIdentifier); + servicegroup serviceGroup = getServiceGroupIfExisits(serviceGroupName); + if(serviceGroup == null) { + // add servicegroup lb_autoscaleGroup -autoscale POLICY -memberPort 80 + int memberPort = vmGroupTO.getMemberPort(); + try { + 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); + vserver_servicegroup_binding.add(_netscalerService, vserver_servicegroup_binding); + } catch (Exception e) { + throw e; + } + } + + // Create the autoscale config + enableAutoScaleConfig(loadBalancerTO, false); + return true; + } + + @SuppressWarnings("static-access") + private synchronized boolean removeAutoScaleConfig(LoadBalancerTO loadBalancerTO) throws Exception, ExecutionException { + String srcIp = loadBalancerTO.getSrcIp(); + int srcPort = loadBalancerTO.getSrcPort(); + String vmGroupIdentifier = generateAutoScaleVmGroupIdentifier(loadBalancerTO); + + String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort); + String serviceGroupName = generateAutoScaleServiceGroupName(vmGroupIdentifier); + + if(loadBalancerTO.getAutoScaleVmGroupTO().getState().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); + vserver_servicegroup_binding.delete(_netscalerService, vserver_servicegroup_binding); + } catch (Exception e) { + throw e; + } + } + + if(getServiceGroupIfExisits(serviceGroupName) != null) { + // 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(vmGroupIdentifier); + 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 policies = vmGroupTO.getPolicies(); + int interval = vmGroupTO.getInterval(); + int snmpPort = profileTO.getSnmpPort(); + String snmpCommunity = profileTO.getSnmpCommunity(); + long cur_prirotiy = 1; + + 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); + vserver.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(); + + com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleprofile autoscaleProfile = new com.citrix.netscaler.nitro.resource.config.autoscale.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); + timer.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); + scaleUpAction.set_quiettime(scaleUpQuietTime); + String scaleUpParameters = "command=deployVirtualMachine" + "&" + + ApiConstants.ZONE_ID + "=" + profileTO.getZoneId()+ "&" + + ApiConstants.SERVICE_OFFERING_ID + "=" + profileTO.getServiceOfferingId()+ "&" + + ApiConstants.TEMPLATE_ID + "=" + profileTO.getTemplateId()+ "&" + + ((profileTO.getOtherDeployParams() == null)? "" : (profileTO.getOtherDeployParams() + "&")) + + "lbruleid=" + loadBalancerTO.getUuid(); + scaleUpAction.set_parameters(scaleUpParameters); + scaleUpAction.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); + scaleDownAction.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 snmpMetrics = new HashMap(); + for (AutoScalePolicyTO autoScalePolicyTO : policies) { + List 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); + metricTable.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 + 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)); + monitor.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); + // metrics, basically use it for autoscaling purpose only. + 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); + metrictable_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_lbmetrictable_binding monitor_metrictable_binding = new +// lbmonitor_lbmetrictable_binding(); + lbmonitor_metric_binding monitor_metric_binding = new lbmonitor_metric_binding(); + ; + try { + monitor_metric_binding.set_monitorname(monitorName); + monitor_metric_binding.set_metric(counterName); + monitor_metric_binding.set_metricthreshold(1); + monitor_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(vmGroupIdentifier); + AutoScaleVmGroupTO vmGroupTO = loadBalancerTO.getAutoScaleVmGroupTO(); + List 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 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); + scaleDownAction.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); + scaleUpAction.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); + timer.delete(_netscalerService, timer); + } catch (Exception e) { + // Ignore Exception on cleanup + if (!isCleanUp) + throw e; + } + + // Delete AutoScale Profile + com.citrix.netscaler.nitro.resource.config.autoscale.autoscaleprofile autoscaleProfile = new com.citrix.netscaler.nitro.resource.config.autoscale.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"); + monitor.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); + metricTable.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); + timerPolicy.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_global("DEFAULT"); // vserver name is present in the expression, this is default +// now + 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); + timer_policy_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); + // timer_policy_binding.set_global("DEFAULT"); // by default only global bank + timer_policy_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); + timerPolicy.delete(_netscalerService, timerPolicy); + } catch (Exception e) { + // Ignore Exception on cleanup + if (!isCleanUp) + throw e; + } + + } + + private boolean isAutoScaleSupportedInNetScaler() throws ExecutionException { + autoscaleprofile autoscaleProfile = 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 generateNSVirtualServerName(String srcIp, long srcPort) { + return genObjectName("Cloud-VirtualServer", 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(String vmGroupIdentifier) { + return genObjectName("Cloud-AutoScale-SvcGrp", vmGroupIdentifier); + } + + 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 genObjectName(Object... args) { + String objectName = ""; + for (int i = 0; i < args.length; i++) { + objectName += args[i]; + if (i != args.length -1) { + objectName += _objectNamePathSep; + } + } + return objectName; + } + + @Override + public IAgentControl getAgentControl() { + return null; + } + + @Override + public PingCommand getCurrentStatus(long id) { + return new PingCommand(Host.Type.ExternalLoadBalancer, id); + } + + @Override + public Type getType() { + return Host.Type.ExternalLoadBalancer; + } + + @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; + } +} diff --git a/deps/cloud-netscaler.jar b/deps/cloud-netscaler.jar index 475ff638440b83aec6dc581145d66425ebe3657a..0cf1820f86e9a0434f834b9fd1e68acb7eb3dc24 100755 GIT binary patch delta 184112 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

7;V{0`xv6Fk>mcx|zL@b*(k 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 z%0A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 z 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 ZbmXEwA>yJPHizx^2c}L5-RXmq{{w-w*G~Wd delta 183221 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 IdKmuoe}Y$#1poj5