| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| package com.cloud.network.resource; |
| |
| import 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 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 { |
| _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"); |
| } |
| |
| 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(F5BigIpResource.class.getPackage().getImplementationVersion()); |
| 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) { |
| // is it saver to use Long.valueOf(BroadcastDomain.getValue(ip.getBroadcastUri())) ??? |
| // i.o.w. can this contain vlan:// then change !!! |
| long guestVlanTag = Long.parseLong(ip.getBroadcastUri()); |
| // It's a hack, using isOneToOneNat field for indicate if it's inline or not |
| boolean inline = ip.isOneToOneNat(); |
| 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, inline); |
| |
| if (ip.isAdd()) { |
| // Add a new guest VLAN |
| addGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask, inline); |
| } |
| |
| 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) { |
| boolean inline = loadBalancer.isInline(); |
| 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; |
| } |
| } |
| |
| // Delete the virtual server with this protocol, source IP, and source port, along with its default pool and all pool members |
| deleteVirtualServerAndDefaultPool(virtualServerName); |
| 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()); |
| } |
| } |
| |
| // Add the virtual server |
| addVirtualServer(virtualServerName, lbProtocol, srcIp, srcPort, loadBalancer.getStickinessPolicies()); |
| } |
| } |
| |
| 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, boolean inline) throws ExecutionException { |
| try { |
| String vlanName = genVlanName(vlanTag); |
| List<String> allVlans = getStrippedVlans(); |
| 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"}); |
| s_logger.debug("vlanName " + vlanName); |
| s_logger.debug("getStrippedVlans " + getStrippedVlans()); |
| |
| if (!getStrippedVlans().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, boolean inline) 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 = getStrippedVlans(); |
| 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 = getStrippedVirtualServers(); |
| 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()); |
| } |
| } |
| |
| //This was working with Big IP 10.x |
| //getVlans retuns vlans with user partition information |
| //ex: if vlanname is vlan-100 then the get_list() will return /Common/vlan-100 |
| 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()); |
| } |
| } |
| |
| //getVlans retuns vlan names without user partition information |
| //ex: if vlanname is vlan-100 then the get_list() will return /Common/vlan-100 |
| // This method will strip the partition information and only returns a list with vlan name (vlan-100) |
| private List<String> getStrippedVlans() throws ExecutionException { |
| try { |
| List<String> vlans = new ArrayList<String>(); |
| String[] vlansArray = _vlanApi.get_list(); |
| |
| for (String vlan : vlansArray) { |
| if(vlan.contains("/")){ |
| vlans.add(vlan.substring(vlan.lastIndexOf("/") + 1)); |
| }else{ |
| 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.parseInt(destIpAndPort[1])); |
| } |
| |
| // Delete the virtual server |
| s_logger.debug("Deleting virtual server " + virtualServerName); |
| _virtualServerApi.delete_virtual_server(genStringArray(virtualServerName)); |
| |
| if (getStrippedVirtualServers().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 getStrippedVirtualServers().contains(virtualServerName); |
| } |
| |
| //This was working with Big IP 10.x |
| //getVirtualServers retuns VirtualServers with user partition information |
| //ex: if VirtualServers is vs-tcp-10.147.44.8-22 then the get_list() will return /Common/vs-tcp-10.147.44.8-22 |
| 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()); |
| } |
| } |
| |
| /* getStrippedVirtualServers retuns VirtualServers without user partition information |
| ex: if VirtualServers is vs-tcp-10.147.44.8-22 then the get_list() will return /Common/vs-tcp-10.147.44.8-22 |
| This method will strip the partition information and only returns a list with VirtualServers (vs-tcp-10.147.44.8-22)*/ |
| private List<String> getStrippedVirtualServers() throws ExecutionException { |
| try { |
| List<String> virtualServers = new ArrayList<String>(); |
| String[] virtualServersArray = _virtualServerApi.get_list(); |
| |
| for (String virtualServer : virtualServersArray) { |
| if(virtualServer.contains("/")){ |
| virtualServers.add(virtualServer.substring(virtualServer.lastIndexOf("/") + 1)); |
| }else{ |
| 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.parseInt(ipAndPort[1])); |
| } |
| } |
| } |
| |
| private void deletePoolMember(String virtualServerName, String destIp, int destPort) throws ExecutionException { |
| try { |
| String memberIdentifier = destIp + "-" + destPort; |
| List<String> lbPools = getAllStrippedLbPools(); |
| |
| 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 getAllStrippedLbPools().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("-"); |
| } |
| |
| //This was working with Big IP 10.x |
| //getAllLbPools retuns LbPools with user partition information |
| //ex: if LbPools is vs-tcp-10.147.44.8-22 then the get_list() will return /Common/vs-tcp-10.147.44.8-22 |
| 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()); |
| } |
| } |
| |
| //Big IP 11.x |
| //getAllLbPools retuns LbPools without user partition information |
| //ex: if LbPools is vs-tcp-10.147.44.8-22 then the get_list() will return /Common/vs-tcp-10.147.44.8-22 |
| //This method will strip the partition information and only returns a list with LbPools (vs-tcp-10.147.44.8-22) |
| public List<String> getAllStrippedLbPools() throws ExecutionException { |
| try { |
| List<String> lbPools = new ArrayList<String>(); |
| String[] pools = _loadbalancerApi.get_list(); |
| |
| for (String pool : pools) { |
| if(pool.contains("/")){ |
| lbPools.add(pool.substring(pool.lastIndexOf("/") + 1)); |
| }else{ |
| 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(); |
| |
| 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(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() + 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() + ((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}; |
| } |
| |
| @Override |
| public void setName(String name) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public void setConfigParams(Map<String, Object> params) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public Map<String, Object> getConfigParams() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public int getRunLevel() { |
| // TODO Auto-generated method stub |
| return 0; |
| } |
| |
| @Override |
| public void setRunLevel(int level) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| } |