bug 6876: netscaler MPX & VPX support

- adding supprt for Netscaler VPX & MPX load blancers
- implemented for virtual networking
- works only with new fetched public IP, inline support is not added yet

more details will be added in the bug
This commit is contained in:
Murali Reddy 2011-08-29 19:26:08 +05:30
parent dc7ac31dce
commit 9a10f2b402
4 changed files with 1136 additions and 0 deletions

View File

@ -0,0 +1,812 @@
/**
* * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
*
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.network.resource;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.naming.ConfigurationException;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer;
import com.cloud.agent.api.ExternalNetworkResourceUsageCommand;
import com.cloud.agent.api.MaintainAnswer;
import com.cloud.agent.api.MaintainCommand;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupExternalLoadBalancerCommand;
import com.cloud.agent.api.routing.IpAssocAnswer;
import com.cloud.agent.api.routing.IpAssocCommand;
import com.cloud.agent.api.routing.LoadBalancerConfigCommand;
import com.cloud.agent.api.to.IpAddressTO;
import com.cloud.agent.api.to.LoadBalancerTO;
import com.cloud.agent.api.to.LoadBalancerTO.DestinationTO;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.resource.ServerResource;
import com.cloud.serializer.GsonHelper;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.exception.ExecutionException;
import com.cloud.utils.net.NetUtils;
import com.google.gson.Gson;
import com.citrix.netscaler.nitro.service.nitro_service;
import com.citrix.netscaler.nitro.resource.base.base_response;
import com.citrix.netscaler.nitro.exception.nitro_exception;
import com.citrix.netscaler.nitro.resource.config.ns.nsconfig;
import com.citrix.netscaler.nitro.resource.config.lb.lbvserver;
import com.citrix.netscaler.nitro.resource.config.basic.service;
import com.citrix.netscaler.nitro.resource.config.network.*;
import com.citrix.netscaler.nitro.resource.config.ns.*;
import com.citrix.netscaler.nitro.resource.config.basic.server_service_binding;
import org.apache.axis.types.*;
import org.apache.log4j.Logger;
class NitroError {
static final int NS_RESOURCE_EXISTS = 273;
static final int NS_RESOURCE_NOT_EXISTS=258;
static final int NS_NO_SERIVCE = 344;
}
public class NetscalerMPXResource implements ServerResource {
// deployment configuration
private String _name;
private String _zoneId;
private String _ip;
private String _username;
private String _password;
private String _publicInterface;
private String _privateInterface;
private Integer _numRetries;
private String _guid;
private boolean _inline;
private static final Logger s_logger = Logger.getLogger(NetscalerMPXResource.class);
protected Gson _gson;
private String _objectNamePathSep = "-";
nitro_service nsService ;
Long timeout = new Long(100000);
base_response apiCallResult;
public NetscalerMPXResource () {
_gson = GsonHelper.getGsonLogger();
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
try {
_name = (String) params.get("name");
if (_name == null) {
throw new ConfigurationException("Unable to find name");
}
_zoneId = (String) params.get("zoneId");
if (_zoneId == null) {
throw new ConfigurationException("Unable to find zone");
}
_ip = (String) params.get("ip");
if (_ip == null) {
throw new ConfigurationException("Unable to find IP");
}
_username = (String) params.get("username");
if (_username == null) {
throw new ConfigurationException("Unable to find username");
}
_password = (String) params.get("password");
if (_password == null) {
throw new ConfigurationException("Unable to find password");
}
_publicInterface = (String) params.get("publicInterface");
if (_publicInterface == null) {
throw new ConfigurationException("Unable to find public interface");
}
_privateInterface = (String) params.get("privateInterface");
if (_privateInterface == null) {
throw new ConfigurationException("Unable to find private interface");
}
_numRetries = NumbersUtil.parseInt((String) params.get("numRetries"), 1);
_guid = (String)params.get("guid");
if (_guid == null) {
throw new ConfigurationException("Unable to find the guid");
}
_inline = Boolean.parseBoolean((String) params.get("inline"));
if (!login()) {
throw new ExecutionException("Failed to login to the Netscaler device.");
}
if (!enableNetScalerLoadBalancing()) {
throw new ExecutionException("Failed to enable load balancing feature on the Netscaler device.");
}
return true;
} catch (Exception e) {
throw new ConfigurationException(e.getMessage());
}
}
private boolean login() {
try {
nsService = new nitro_service(_ip, "https");
apiCallResult = nsService.login(_username, _password, timeout);
if (apiCallResult.errorcode == 0) {
return true;
} else {
s_logger.debug("Failed to log in to Netscaler device at " + _ip + " due to " + apiCallResult.message);
return false;
}
} catch (nitro_exception e) {
s_logger.debug("Failed to log in to Netscaler device at " + _ip + " due to " + e.response[0].message);
} catch (Exception e) {
s_logger.debug("Failed to log in to Netscaler device at " + _ip + " due to " + e.getMessage());
}
return false;
}
private boolean enableNetScalerLoadBalancing() {
try {
String[] feature = new String[1];
feature[0] = "LB";
nsService.enable_features(feature);
return true;
} catch (nitro_exception e) {
System.out.println("Enabling netscaler load balancing feature failed errorcode="+e.getErrorCode()+",message="+ e.getMessage());
} catch (Exception e) {
System.out.println("Enabling netscaler load balancing feature failed due to "+e.getMessage());
}
return false;
}
@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) {
return executeRequest(cmd, _numRetries);
}
private Answer executeRequest(Command cmd, int numRetries) {
if (cmd instanceof ReadyCommand) {
return execute((ReadyCommand) cmd);
} else if (cmd instanceof MaintainCommand) {
return execute((MaintainCommand) cmd);
} else if (cmd instanceof IpAssocCommand) {
return execute((IpAssocCommand) cmd, numRetries);
} else if (cmd instanceof LoadBalancerConfigCommand) {
return execute((LoadBalancerConfigCommand) cmd, numRetries);
} else if (cmd instanceof ExternalNetworkResourceUsageCommand) {
return execute((ExternalNetworkResourceUsageCommand) cmd);
} else if (cmd instanceof MaintainCommand) {
return execute((MaintainCommand) cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
}
private Answer execute(ReadyCommand cmd) {
return new ReadyAnswer(cmd);
}
protected Answer execute(MaintainCommand cmd) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Executing resource MaintainCommand");
}
return new MaintainAnswer(cmd, "Put host in maintaince");
}
private synchronized Answer execute(IpAssocCommand cmd, int numRetries) {
String[] results = new String[cmd.getIpAddresses().length];
int i = 0;
try {
IpAddressTO[] ips = cmd.getIpAddresses();
for (IpAddressTO ip : ips) {
long guestVlanTag = Long.valueOf(ip.getVlanId());
String vlanSelfIp = ip.getVlanGateway();
String vlanNetmask = ip.getVlanNetmask();
// Check and delete any existing guest VLAN with this tag, self IP, and netmask
deleteGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask);
if (ip.isAdd()) {
// Add a new guest VLAN and its subnet and bind it to private interface
addGuestVlanAndSubnet(guestVlanTag, vlanSelfIp, vlanNetmask);
}
saveConfiguration();
results[i++] = ip.getPublicIp() + " - success";
}
} catch (ExecutionException e) {
s_logger.error("Failed to execute IPAssocCommand due to " + e);
if (shouldRetry(numRetries)) {
return retry(cmd, numRetries);
} else {
results[i++] = IpAssocAnswer.errorResult;
}
}
return new IpAssocAnswer(cmd, results);
}
private synchronized Answer execute(LoadBalancerConfigCommand cmd, int numRetries) {
try {
String lbProtocol;
String lbMethod;
LoadBalancerTO[] loadBalancers = cmd.getLoadBalancers();
for (LoadBalancerTO loadBalancer : loadBalancers) {
if (loadBalancer.getProtocol() == null) {
lbProtocol = "TCP";
} else if (loadBalancer.getProtocol().equals(NetUtils.TCP_PROTO)){
lbProtocol = "TCP";
} else if (loadBalancer.getProtocol().equals(NetUtils.UDP_PROTO)) {
lbProtocol = "UDP";
} else {
throw new ExecutionException("Got invalid protocol: " + loadBalancer.getProtocol());
}
if (loadBalancer.getAlgorithm().equals("roundrobin")) {
lbMethod = "ROUNDROBIN";
} else if (loadBalancer.getAlgorithm().equals("leastconn")) {
lbMethod = "LEASTCONNECTION";
} else {
throw new ExecutionException("Got invalid load balancing algorithm: " + loadBalancer.getAlgorithm());
}
String srcIp = loadBalancer.getSrcIp();
int srcPort = loadBalancer.getSrcPort();
String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort, lbProtocol);
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, lbMethod, lbProtocol);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Created load balancing virtual server " + nsVirtualServerName + " on the Netscaler device");
}
List<String> activePoolMembers = new ArrayList<String>();
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(nsService, 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(nsService, 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(nsService, 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(nsService, 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(nsService, binding);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to delete the binding between the virtual server: " + nsVirtualServerName + " and service:" + nsServiceName);
}
// delete the service
apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.service.delete(nsService, nsServiceName);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to delete service: " + nsServiceName);
}
// delete the server if there is no associated services
server_service_binding[] services = server_service_binding.get(nsService, nsServerName);
if ((services == null) || (services.length == 0)) {
apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.delete(nsService, nsServerName);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to remove server:" + nsServerName);
}
}
}
}
}
}
}
} else {
// delete the implemented load balancing rule and its destinations
lbvserver lbserver = lbvserver.get(nsService, nsVirtualServerName);
if (lbserver == null) {
throw new ExecutionException("Failed to find virtual server with name:" + nsVirtualServerName);
}
//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(nsService, 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(nsService, binding);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to unbind servic from the lb virtual server: " + nsVirtualServerName);
}
com.citrix.netscaler.nitro.resource.config.basic.service svc = com.citrix.netscaler.nitro.resource.config.basic.service.get(nsService, serviceName);
String nsServerName = svc.get_servername();
// delete the service
com.citrix.netscaler.nitro.resource.config.basic.service.delete(nsService, serviceName);
//delete the server if no more services attached
server_service_binding[] services = server_service_binding.get(nsService, nsServerName);
if ((services == null) || (services.length == 0)) {
apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.delete(nsService, nsServerName);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to remove server:" + nsServerName);
}
}
}
}
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.getMessage());
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.getMessage());
if (shouldRetry(numRetries)) {
return retry(cmd, numRetries);
} else {
return new Answer(cmd, e);
}
}
}
private synchronized ExternalNetworkResourceUsageAnswer execute(ExternalNetworkResourceUsageCommand cmd) {
try {
return getPublicIpBytesSentAndReceived(cmd);
} catch (ExecutionException e) {
return new ExternalNetworkResourceUsageAnswer(cmd, e);
}
}
private void addGuestVlanAndSubnet(long vlanTag, String vlanSelfIp, String vlanNetmask) throws ExecutionException {
org.apache.axis.types.UnsignedInt result;
try {
String vlanName = generateVlanName(vlanTag);
if (!nsVlanExists(vlanTag)) {
// add new vlan
vlan vlanObj = new vlan();
vlanObj.set_id(vlanTag);
apiCallResult = vlan.add(nsService, vlanObj);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to add new vlan with tag:" + vlanTag + "due to" + apiCallResult.message);
}
// add self-ip and subnet to the Netscaler
nsip selfIp = new nsip();
selfIp.set_ipaddress(vlanSelfIp);
selfIp.set_netmask(vlanNetmask);
selfIp.set_type("SNIP");
apiCallResult = nsip.add(nsService, selfIp);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to add new self-ip due to "+ apiCallResult.message);
}
//bind the vlan to guest subnet
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(nsService, ipVlanBinding);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to bind vlan with tag:" + vlanTag + " to the subnet due to" + apiCallResult.message);
}
// bind vlan to the private interface
vlan_interface_binding vlanBinding = new vlan_interface_binding();
vlanBinding.set_ifnum(_privateInterface);
vlanBinding.set_tagged(true);
vlanBinding.set_id(vlanTag);
apiCallResult = vlan_interface_binding.add(nsService, vlanBinding);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to bind vlan with tag:" + vlanTag + " with the interface " + _privateInterface + " due to " + apiCallResult.message);
}
} else {
throw new ExecutionException("Failed to configure Netscaler device for vlan with tag " + vlanTag + " as vlan already exisits");
}
} catch (nitro_exception e) {
throw new ExecutionException("Failed to implement guest network on the Netscaler device");
} catch (Exception e) {
throw new ExecutionException("Failed to implement guest network on the Netscaler device");
}
}
private void deleteGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask) throws ExecutionException {
org.apache.axis.types.UnsignedInt result;
try {
if (nsVlanExists(vlanTag)) {
// Delete all servers and associated services from this guest VLAN
deleteServersInGuestVlan(vlanTag, vlanSelfIp, vlanNetmask);
// unbind vlan to the private interface
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(nsService, vlanIfBinding);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to unbind vlan:" + vlanTag + " with the private interface due to " + apiCallResult.message);
}
//unbind the vlan to subnet
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(nsService, vlanSnipBinding);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to unbind vlan:" + vlanTag + " with the subnet due to " + apiCallResult.message);
}
// remove subnet IP
nsip subnetIp = nsip.get(nsService, vlanSelfIp);
apiCallResult = nsip.delete(nsService, subnetIp);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to remove subnet ip:" + vlanTag + " to the subnet due to" + apiCallResult.message);
}
// remove vlan
apiCallResult = com.citrix.netscaler.nitro.resource.config.network.vlan.delete(nsService, 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");
} catch (Exception e) {
s_logger.error(e);
throw new ExecutionException(e.getMessage());
}
}
private boolean nsVlanExists(long vlanTag) {// throws ExecutionException {
try {
if (vlan.get(nsService, new Long(vlanTag)) != null) {
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
private boolean nsServerExists(String serverName) throws ExecutionException {
try {
if (com.citrix.netscaler.nitro.resource.config.basic.server.get(nsService, 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(e.getMessage());
}
} catch (Exception e) {
throw new ExecutionException(e.getMessage());
}
}
private boolean nsServiceExists(String serviceName) throws ExecutionException {
try {
if (com.citrix.netscaler.nitro.resource.config.basic.service.get(nsService, serviceName) != null) {
return true;
} else {
return false;
}
} catch (nitro_exception e) {
if (e.getErrorCode() == NitroError.NS_NO_SERIVCE) {
return false;
} else {
throw new ExecutionException(e.getMessage());
}
} catch (Exception e) {
throw new ExecutionException(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(nsService, 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(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(nsService);
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(nsService);
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(nsService, 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(nsService, 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 void addLBVirtualServer(String virtualServerName, String srcIp, int srcPort, String lbMethod, String lbProtocol) throws ExecutionException {
try {
lbvserver vserver = new lbvserver();
vserver.set_name(virtualServerName);
vserver.set_ipv46(srcIp);
vserver.set_port(srcPort);
vserver.set_servicetype(lbProtocol);
vserver.set_lbmethod(lbMethod);
apiCallResult = lbvserver.add(nsService,vserver);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to create new virtual server:" + virtualServerName);
}
} catch (nitro_exception e) {
if (e.getErrorCode() != NitroError.NS_RESOURCE_EXISTS) {
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(nsService, virtualServerName);
if (vserver == null) {
throw new ExecutionException("Failed to find virtual server with name:" + virtualServerName);
}
apiCallResult = lbvserver.delete(nsService, vserver);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to remove virtual server:" + virtualServerName);
}
} catch (nitro_exception e) {
throw new ExecutionException("Failed remove virtual server:" + virtualServerName +" due to " + e.getMessage());
} catch (Exception e) {
throw new ExecutionException("Failed remove virtual server:" + virtualServerName +" due to " + e.getMessage());
}
}
private void saveConfiguration() throws ExecutionException {
try {
apiCallResult = nsconfig.save(nsService);
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Error occured while saving configuration changes to Netscaler device due to error:" + apiCallResult.errorcode);
}
} 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 {
//TODO: add the stats collection
} catch (Exception e) {
s_logger.error(e);
throw new ExecutionException(e.getMessage());
}
return answer;
}
private Answer retry(Command cmd, int numRetries) {
int numRetriesRemaining = numRetries - 1;
s_logger.error("Retrying " + cmd.getClass().getSimpleName() + ". Number of retries remaining: " + numRetriesRemaining);
return executeRequest(cmd, numRetriesRemaining);
}
private boolean shouldRetry(int numRetries) {
return (numRetries > 0 && login());
}
private String generateVlanName(long vlanTag) {
return genObjectName("cloud-vlan", String.valueOf(vlanTag));
}
private String generateNSVirtualServerName(String srcIp, long srcPort, String protocol) {
return genObjectName("cloud-VirtualServer", protocol, 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 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;
}
}

BIN
deps/cloud-netscaler.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,162 @@
/**
* * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
*
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.network.element;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.dc.DataCenter;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientNetworkCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.ExternalNetworkManager;
import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.NetworkManager;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.PublicIpAddress;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.StaticNat;
import com.cloud.offering.NetworkOffering;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.Inject;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Local(value=NetworkElement.class)
public class F5ExternalLoadBalancerElement extends AdapterBase implements NetworkElement {
private static final Logger s_logger = Logger.getLogger(F5ExternalLoadBalancerElement.class);
@Inject NetworkManager _networkManager;
@Inject ExternalNetworkManager _externalNetworkManager;
@Inject ConfigurationManager _configMgr;
private boolean canHandle(Network config) {
DataCenter zone = _configMgr.getZone(config.getDataCenterId());
if (config.getGuestType() != Network.GuestIpType.Virtual || config.getTrafficType() != TrafficType.Guest) {
s_logger.trace("Not handling network with guest Type " + config.getGuestType() + " and traffic type " + config.getTrafficType());
return false;
}
return (_networkManager.zoneIsConfiguredForExternalNetworking(zone.getId()) &&
zone.getLoadBalancerProvider() != null && zone.getLoadBalancerProvider().equals(Network.Provider.F5BigIp.getName()));
}
@Override
public boolean implement(Network guestConfig, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientNetworkCapacityException {
if (!canHandle(guestConfig)) {
return false;
}
return _externalNetworkManager.manageGuestNetworkWithExternalLoadBalancer(true, guestConfig);
}
@Override
public boolean prepare(Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientNetworkCapacityException, ResourceUnavailableException {
return true;
}
@Override
public boolean release(Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, ReservationContext context) {
return true;
}
@Override
public boolean shutdown(Network guestConfig, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException {
if (!canHandle(guestConfig)) {
return false;
}
return _externalNetworkManager.manageGuestNetworkWithExternalLoadBalancer(false, guestConfig);
}
@Override
public boolean destroy(Network config) {
return true;
}
@Override
public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress) throws ResourceUnavailableException {
return true;
}
@Override
public boolean applyRules(Network config, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
if (!canHandle(config)) {
return false;
}
return _externalNetworkManager.applyLoadBalancerRules(config, rules);
}
@Override
public Map<Service, Map<Capability, String>> getCapabilities() {
Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
// Set capabilities for LB service
Map<Capability, String> lbCapabilities = new HashMap<Capability, String>();
// Specifies that the RoundRobin and Leastconn algorithms are supported for load balancing rules
lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn");
// Specifies that load balancing rules can be made for either TCP or UDP traffic
lbCapabilities.put(Capability.SupportedProtocols, "tcp,udp");
// Specifies that this element can measure network usage on a per public IP basis
lbCapabilities.put(Capability.TrafficStatistics, "per public ip");
// Specifies that load balancing rules can only be made with public IPs that aren't source NAT IPs
lbCapabilities.put(Capability.LoadBalancingSupportedIps, "additional");
capabilities.put(Service.Lb, lbCapabilities);
return capabilities;
}
@Override
public Provider getProvider() {
return Provider.F5BigIp;
}
@Override
public boolean restart(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{
return true;
}
@Override
public boolean applyStaticNats(Network config, List<? extends StaticNat> rules) throws ResourceUnavailableException {
return false;
}
}

View File

@ -0,0 +1,162 @@
/**
* * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
*
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.network.element;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.dc.DataCenter;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientNetworkCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.ExternalNetworkManager;
import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.NetworkManager;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.PublicIpAddress;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.StaticNat;
import com.cloud.offering.NetworkOffering;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.Inject;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Local(value=NetworkElement.class)
public class NetscalerExternalLoadBalancerElement extends AdapterBase implements NetworkElement {
private static final Logger s_logger = Logger.getLogger(NetscalerExternalLoadBalancerElement.class);
@Inject NetworkManager _networkManager;
@Inject ExternalNetworkManager _externalNetworkManager;
@Inject ConfigurationManager _configMgr;
private boolean canHandle(Network config) {
DataCenter zone = _configMgr.getZone(config.getDataCenterId());
if (config.getGuestType() != Network.GuestIpType.Virtual || config.getTrafficType() != TrafficType.Guest) {
s_logger.trace("Not handling network with guest Type " + config.getGuestType() + " and traffic type " + config.getTrafficType());
return false;
}
return (_networkManager.zoneIsConfiguredForExternalNetworking(zone.getId()) &&
zone.getLoadBalancerProvider() != null && zone.getLoadBalancerProvider().equals(Network.Provider.NetscalerMPX.getName()));
}
@Override
public boolean implement(Network guestConfig, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientNetworkCapacityException {
if (!canHandle(guestConfig)) {
return false;
}
return _externalNetworkManager.manageGuestNetworkWithExternalLoadBalancer(true, guestConfig);
}
@Override
public boolean prepare(Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientNetworkCapacityException, ResourceUnavailableException {
return true;
}
@Override
public boolean release(Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, ReservationContext context) {
return true;
}
@Override
public boolean shutdown(Network guestConfig, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException {
if (!canHandle(guestConfig)) {
return false;
}
return _externalNetworkManager.manageGuestNetworkWithExternalLoadBalancer(false, guestConfig);
}
@Override
public boolean destroy(Network config) {
return true;
}
@Override
public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress) throws ResourceUnavailableException {
return true;
}
@Override
public boolean applyRules(Network config, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
if (!canHandle(config)) {
return false;
}
return _externalNetworkManager.applyLoadBalancerRules(config, rules);
}
@Override
public Map<Service, Map<Capability, String>> getCapabilities() {
Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
// Set capabilities for LB service
Map<Capability, String> lbCapabilities = new HashMap<Capability, String>();
// Specifies that the RoundRobin and Leastconn algorithms are supported for load balancing rules
lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn");
// Specifies that load balancing rules can be made for either TCP or UDP traffic
lbCapabilities.put(Capability.SupportedProtocols, "tcp,udp");
// Specifies that this element can measure network usage on a per public IP basis
lbCapabilities.put(Capability.TrafficStatistics, "per public ip");
// Specifies that load balancing rules can only be made with public IPs that aren't source NAT IPs
lbCapabilities.put(Capability.LoadBalancingSupportedIps, "additional");
capabilities.put(Service.Lb, lbCapabilities);
return capabilities;
}
@Override
public Provider getProvider() {
return Provider.NetscalerMPX;
}
@Override
public boolean restart(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{
return true;
}
@Override
public boolean applyStaticNats(Network config, List<? extends StaticNat> rules) throws ResourceUnavailableException {
return false;
}
}