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