def __init__(self, driver, l2_service, l3_binding): self.driver = driver self.l2_service = l2_service self.l3_binding = l3_binding self.snatpool_manager = BigIPResourceHelper(ResourceType.snatpool) self.snat_translation_manager = BigIPResourceHelper( ResourceType.snat_translation) self.network_helper = NetworkHelper()
def __init__(self, service_adapter): self.service_adapter = service_adapter self.http_mon_helper = BigIPResourceHelper(ResourceType.http_monitor) self.https_mon_helper = BigIPResourceHelper(ResourceType.https_monitor) self.tcp_mon_helper = BigIPResourceHelper(ResourceType.tcp_monitor) self.ping_mon_helper = BigIPResourceHelper(ResourceType.ping_monitor) self.pool_helper = BigIPResourceHelper(ResourceType.pool) self.node_helper = BigIPResourceHelper(ResourceType.node)
def resource_exists(self, bigip, tag_name, resource_type): helper = BigIPResourceHelper(resource_type) name = tag_name # allow user to define chain cert name with or without '.crt' if resource_type == ResourceType.ssl_cert_file and not \ name.endswith('.crt'): name += '.crt' return helper.exists_in_collection(bigip, name)
def purge_folder_contents(self, bigip, folder): network_helper = NetworkHelper() if folder not in self.exempt_folders: # First remove all LTM resources. ltm_types = [ ResourceType.virtual, ResourceType.pool, ResourceType.http_monitor, ResourceType.https_monitor, ResourceType.tcp_monitor, ResourceType.ping_monitor, ResourceType.node, ResourceType.snat, ResourceType.snatpool, ResourceType.snat_translation, ResourceType.rule ] for ltm_type in ltm_types: resource = BigIPResourceHelper(ltm_type) [r.delete() for r in resource.get_resources(bigip, folder)] # Remove all net resources net_types = [ ResourceType.arp, ResourceType.selfip, ResourceType.vlan, ResourceType.route_domain ] for net_type in net_types: resource = BigIPResourceHelper(net_type) [r.delete() for r in resource.get_resources(bigip, folder)] # Tunnels and fdb's require some special attention. resource = BigIPResourceHelper(ResourceType.tunnel) tunnels = resource.get_resources(bigip, folder) for tunnel in tunnels: network_helper.delete_all_fdb_entries(bigip, tunnel.name, folder) network_helper.delete_tunnel(bigip, tunnel.name, folder)
def __init__(self, event, f5_l7policy): self.event = event self.f5_l7policy = f5_l7policy self.helper = BigIPResourceHelper(ResourceType.l7policy) if event == 'DELETE_L7POLICY': # both rules and policies handled by same method self.execute = self.delete else: # create and update event for both rules and polices self.execute = self.create
class LoadBalancerServiceBuilder(object): """Create loadbalancer related objects on BIG-IPs Handles requests to create and delete LBaaS v2 tenant partition folders on one or more BIG-IP systems. """ def __init__(self): self.folder_helper = BigIPResourceHelper(ResourceType.folder) def create_partition(self, service, bigips): """Create tenant partition on set of BIG-IPs. Creates a partition if it is not named "Common". :param service: Dictionary which contains a both a listener and load balancer definition. :param bigips: Array of BigIP class instances to create Listener. """ folder = ServiceModelAdapter.get_partition(service) if folder != "Common": for bigip in bigips: self.folder_helper.create(bigip, folder) def delete_partition(self, service, bigips): """Deletes partition from a set of BIG-IP systems. Deletes partition if it is not named "Common". :param service: Dictionary which contains a load balancer definition. :param bigips: Array of BigIP class instances to delete partition. """ folder = ServiceModelAdapter.get_partition(service) if folder != "Common": for bigip in bigips: self.folder_helper.delete(bigip, name=folder["name"]) def prep_service(self, service, bigips): """Prepares for LBaaS service request by creating partition. Creates partition, if not Common, and sets partition name on service loadbalancer. :param service: service object for request. :param bigips: Array of BigIP class instances to delete partition. """ # create partition if not Common self.create_partition(service, bigips) # set partition name on loadbalancer object ServiceModelAdapter.set_partition(service)
class L7PolicyBuilder(object): """Class supports CRUD for L7 policies and rules Handles both L7 policy and L7 rules for these events: - create l7 policy - delete l7 policy """ def __init__(self, event, f5_l7policy): self.event = event self.f5_l7policy = f5_l7policy self.helper = BigIPResourceHelper(ResourceType.l7policy) if event == 'DELETE_L7POLICY': # both rules and policies handled by same method self.execute = self.delete else: # create and update event for both rules and polices self.execute = self.create def create(self, bigip): LOG.debug("L7PolicyBuilder: create") if self.helper.exists(bigip, name=self.f5_l7policy['name'], partition=self.f5_l7policy['partition']): self.helper.update(bigip, self.f5_l7policy) else: self.helper.create(bigip, self.f5_l7policy) def delete(self, bigip): LOG.debug("L7PolicyBuilder: delete") self.helper.delete( bigip, self.f5_l7policy['name'], self.f5_l7policy['partition'])
def purge_folder_contents(self, bigip, folder): network_helper = NetworkHelper() if folder not in self.exempt_folders: # First remove all LTM resources. ltm_types = [ ResourceType.virtual, ResourceType.virtual_address, ResourceType.pool, ResourceType.http_monitor, ResourceType.https_monitor, ResourceType.tcp_monitor, ResourceType.ping_monitor, ResourceType.node, ResourceType.snat, ResourceType.snatpool, ResourceType.snat_translation, ResourceType.universal_persistence, ResourceType.rule, ResourceType.l7policy ] for ltm_type in ltm_types: resource = BigIPResourceHelper(ltm_type) [r.delete() for r in resource.get_resources(bigip, folder)] # Remove all net resources net_types = [ ResourceType.arp, ResourceType.selfip, ResourceType.vlan, ResourceType.route_domain ] for net_type in net_types: resource = BigIPResourceHelper(net_type) [r.delete() for r in resource.get_resources(bigip, folder)] # Tunnels and fdb's require some special attention. resource = BigIPResourceHelper(ResourceType.tunnel) tunnels = resource.get_resources(bigip, folder) for tunnel in tunnels: network_helper.delete_all_fdb_entries( bigip, tunnel.name, folder) network_helper.delete_tunnel( bigip, tunnel.name, folder)
class PoolServiceBuilder(object): """Create LBaaS v2 pools and related objects on BIG-IPs. Handles requests to create, update, delete LBaaS v2 pools, health monitors, and members on one or more BIG-IP systems. """ def __init__(self, service_adapter): self.service_adapter = service_adapter self.http_mon_helper = BigIPResourceHelper(ResourceType.http_monitor) self.https_mon_helper = BigIPResourceHelper(ResourceType.https_monitor) self.tcp_mon_helper = BigIPResourceHelper(ResourceType.tcp_monitor) self.ping_mon_helper = BigIPResourceHelper(ResourceType.ping_monitor) self.pool_helper = BigIPResourceHelper(ResourceType.pool) self.node_helper = BigIPResourceHelper(ResourceType.node) def create_pool(self, service, bigips): """Create a pool on set of BIG-IPs. Creates a BIG-IP pool to represent an LBaaS pool object. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to create pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.create(bigip, pool) def delete_pool(self, service, bigips): """Delete a pool on set of BIG-IPs. Deletes a BIG-IP pool defined by LBaaS pool object. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to delete pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.delete(bigip, name=pool["name"], partition=pool["partition"]) def update_pool(self, service, bigips): """Update BIG-IP pool. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to create pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.update(bigip, pool) def create_healthmonitor(self, service, bigips): # create member hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) pool = self.service_adapter.get_pool(service) for bigip in bigips: hm_helper.create(bigip, hm) # update pool with new health monitor self.pool_helper.update(bigip, pool) def delete_healthmonitor(self, service, bigips): # delete health monitor hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) # update pool pool = self.service_adapter.get_pool(service) pool["monitor"] = "" for bigip in bigips: # need to first remove monitor reference from pool self.pool_helper.update(bigip, pool) # after updating pool, delete monitor hm_helper.delete(bigip, name=hm["name"], partition=hm["partition"]) def update_healthmonitor(self, service, bigips): hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) pool = self.service_adapter.get_pool(service) for bigip in bigips: hm_helper.update(bigip, hm) # update pool with new health monitor self.pool_helper.update(bigip, pool) # Note: can't use BigIPResourceHelper class because members # are created within pool objects. Following member methods # use the F5 SDK directly. def create_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) for bigip in bigips: part = pool["partition"] p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members m.create(**member) def delete_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] for bigip in bigips: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members member_exists = m.exists(name=urllib.quote(member["name"]), partition=part) if member_exists: m = m.load(name=urllib.quote(member["name"]), partition=part) m.delete() try: node = self.service_adapter.get_member_node(service) self.node_helper.delete(bigip, name=urllib.quote(node["name"]), partition=node["partition"]) except HTTPError as err: # Possilbe error if node is shared with another member. # If so, ignore the error. if err.response.status_code == 400: LOG.debug(err.message) else: raise def update_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] for bigip in bigips: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members if m.exists(name=urllib.quote(member["name"]), partition=part): m = m.load(name=urllib.quote(member["name"]), partition=part) member.pop("address", None) m.modify(**member) def delete_orphaned_members(self, service, bigips): pool = self.service_adapter.get_pool(service) srv_members = service['members'] part = pool['partition'] for bigip in bigips: p = self.pool_helper.load(bigip, name=pool['name'], partition=part) deployed_members = p.members_s.get_collection() for dm in deployed_members: orphaned = True for sm in srv_members: svc = {"loadbalancer": service["loadbalancer"], "pool": service["pool"], "member": sm} member = self.service_adapter.get_member(svc) if member['name'] == dm.name: orphaned = False if orphaned: node_name = dm.address dm.delete() try: self.node_helper.delete(bigip, name=urllib.quote(node_name), partition=part) except HTTPError as err: # Possilbe error if node is shared with another member. # If so, ignore the error. if err.response.status_code == 400: LOG.debug(err.message) else: raise def _get_monitor_helper(self, service): monitor_type = self.service_adapter.get_monitor_type(service) if monitor_type == "HTTPS": hm = self.https_mon_helper elif monitor_type == "TCP": hm = self.tcp_mon_helper elif monitor_type == "PING": hm = self.ping_mon_helper else: hm = self.http_mon_helper return hm def get_member_status(self, service, bigip, status_keys): """Return status values for a single pool. Status keys to collect are defined as an array of strings in input status_keys. :param service: Has pool and member name/partition :param bigip: BIG-IP to get member status from. :param status_keys: Array of strings that define which status keys to collect. :return: A dict with key/value pairs for each status defined in input status_keys. """ member_status = {} pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] try: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members if m.exists(name=urllib.quote(member["name"]), partition=part): m = m.load(name=urllib.quote(member["name"]), partition=part) member_status = self.pool_helper.collect_stats( m, stat_keys=status_keys) else: LOG.error("Unable to get member status. " "Member %s does not exist.", member["name"]) except Exception as e: # log error but continue on LOG.error("Error getting member status: %s", e.message) return member_status
class BigipSelfIpManager(object): def __init__(self, driver, l2_service, l3_binding): self.driver = driver self.l2_service = l2_service self.l3_binding = l3_binding self.selfip_manager = BigIPResourceHelper(ResourceType.selfip) self.network_helper = NetworkHelper() def create_bigip_selfip(self, bigip, model): if not model['name']: return False LOG.debug("Getting selfip....") s = bigip.net.selfips.selfip if s.exists(name=model['name'], partition=model['partition']): LOG.debug("It exists!!!!") return True try: LOG.debug("Doesn't exist!!!!") self.selfip_manager.create(bigip, model) LOG.debug("CREATED!!!!") except HTTPError as err: if err.response.status_code is not 400: raise if err.response.text.find("must be one of the vlans " "in the associated route domain") > 0: self.network_helper.add_vlan_to_domain( bigip, name=model['vlan'], partition=model['partition']) try: self.selfip_manager.create(bigip, model) except HTTPError as err: LOG.error("Error creating selfip %s. " "Repsponse status code: %s. Response " "message: %s." % (model["name"], err.response.status_code, err.message)) def assure_bigip_selfip(self, bigip, service, subnetinfo): network = subnetinfo['network'] if not network: LOG.error('Attempted to create selfip and snats ' 'for network with no id... skipping.') return subnet = subnetinfo['subnet'] tenant_id = service['loadbalancer']['tenant_id'] # If we have already assured this subnet.. return. # Note this cache is periodically cleared in order to # force assurance that the configuration is present. if tenant_id in bigip.assured_tenant_snat_subnets and \ subnet['id'] in bigip.assured_tenant_snat_subnets[tenant_id]: return selfip_address = self._get_bigip_selfip_address(bigip, subnet) # FIXME(Rich Browne): it is possible this is not set unless # use namespaces is true. I think this method is only called # in the global_routed_mode == False case though. Need to check # that network['route_domain_id'] exists. if 'route_domain_id' not in network: LOG.debug("NETWORK ROUTE DOMAIN NOT SET") network['route_domain_id'] = "0" LOG.debug("route domain id: %s" % network['route_domain_id']) selfip_address += '%' + str(network['route_domain_id']) LOG.debug("have selfip address: %s" % selfip_address) if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = self.driver.service_adapter.\ get_folder_name(service['loadbalancer']['tenant_id']) LOG.debug("getting network name") (network_name, preserve_network_name) = \ self.l2_service.get_network_name(bigip, network) LOG.debug("CREATING THE SELFIP--------------------") netmask = netaddr.IPNetwork(subnet['cidr']).prefixlen address = selfip_address + ("/%d" % netmask) model = { "name": "local-" + bigip.device_name + "-" + subnet['id'], "address": address, "vlan": network_name, "floating": "disabled", "partition": network_folder } LOG.debug("Model: %s" % model) self.create_bigip_selfip(bigip, model) # TO DO: we need to only bind the local SelfIP to the # local device... not treat it as if it was floating LOG.debug("self ip CREATED!!!!!!") if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=selfip_address) def _get_bigip_selfip_address(self, bigip, subnet): # Get ip address for selfip to use on BIG-IP®. selfip_name = "local-" + bigip.device_name + "-" + subnet['id'] ports = self.driver.plugin_rpc.get_port_by_name(port_name=selfip_name) if len(ports) > 0: port = ports[0] else: port = self.driver.plugin_rpc.create_port_on_subnet( subnet_id=subnet['id'], mac_address=None, name=selfip_name, fixed_address_count=1) return port['fixed_ips'][0]['ip_address'] def assure_gateway_on_subnet(self, bigip, subnetinfo, traffic_group): # Called for every bigip only in replication mode. # Otherwise called once. subnet = subnetinfo['subnet'] if subnet['id'] in bigip.assured_gateway_subnets: return network = subnetinfo['network'] (network_name, preserve_network_name) = \ self.l2_service.get_network_name(bigip, network) if self.l2_service.is_common_network(network): network_folder = 'Common' network_name = '/Common/' + network_name else: network_folder = self.driver.service_adapter.\ get_folder_name(subnet['tenant_id']) # Select a traffic group for the floating SelfIP floating_selfip_name = "gw-" + subnet['id'] netmask = netaddr.IPNetwork(subnet['cidr']).netmask model = { 'name': floating_selfip_name, 'ip_address': subnet['gateway_ip'], 'netmask': netmask, 'vlan_name': network_name, 'floating': True, 'traffic_group': traffic_group, 'partition': network_folder, 'preserve_vlan_name': preserve_network_name } self.create_bigip_selfip(bigip, model) if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=subnet['gateway_ip']) # Setup a wild card ip forwarding virtual service for this subnet gw_name = "gw-" + subnet['id'] vs = bigip.ltm.virtuals.virtual if not vs.exists(name=gw_name, partition=network_folder): vs.create( name=gw_name, partition=network_folder, destination='0.0.0.0:0', mask='0.0.0.0', vlansEnabled=True, vlans=[network_name], sourceAddressTranslation={'type': 'automap'}, ipForward=True ) else: vs.load(name=gw_name, partition=network_folder) virtual_address = bigip.ltm.virtual_address_s.virtual_address virtual_address.load(name='0.0.0.0:0', partition=network_folder) virtual_address.update(trafficGroup=traffic_group) bigip.assured_gateway_subnets.append(subnet['id']) def delete_gateway_on_subnet(self, bigip, subnetinfo): # Called for every bigip only in replication mode. # Otherwise called once. network = subnetinfo['network'] if not network: LOG.error('Attempted to delete default gateway ' 'for network with no id... skipping.') return subnet = subnetinfo['subnet'] if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = self.driver.service_adapter.\ get_folder_name(subnet['tenant_id']) floating_selfip_name = "gw-" + subnet['id'] if self.driver.conf.f5_populate_static_arp: self.network_helper.arp_delete_by_subnet( bigip, partition=network_folder, subnet=subnetinfo['subnet']['cidr'], mask=None ) self.network_helper.delete_selfip( bigip, floating_selfip_name, network_folder) if self.l3_binding: self.l3_binding.unbind_address(subnet_id=subnet['id'], ip_address=subnet['gateway_ip']) gw_name = "gw-" + subnet['id'] vs = bigip.ltm.virtuals.virtual if vs.exists(name=gw_name, partition=network_folder): vs.load(name=gw_name, partition=network_folder) vs.delete() if subnet['id'] in bigip.assured_gateway_subnets: bigip.assured_gateway_subnets.remove(subnet['id']) return gw_name
def __init__(self, driver, l2_service, l3_binding): self.driver = driver self.l2_service = l2_service self.l3_binding = l3_binding self.selfip_manager = BigIPResourceHelper(ResourceType.selfip) self.network_helper = NetworkHelper()
class L7PolicyService(object): """Handles requests to create, update, delete L7 policies on BIG-IPs.""" def __init__(self, conf): self.conf = conf self.policy_helper = BigIPResourceHelper(ResourceType.l7policy) self.rule_helper = BigIPResourceHelper(ResourceType.rule) def create_l7policy(self, f5_l7policy, bigips): LOG.debug("L7PolicyService: create_l7policy") error = None for bigip in bigips: try: self.policy_helper.create(bigip, f5_l7policy) error = None except HTTPError as err: status_code = err.response.status_code if status_code == 409: LOG.debug("L7 policy already exists...updating") try: self.policy_helper.update(bigip, f5_l7policy) except Exception as err: error = f5_ex.L7PolicyUpdateException(err.message) else: error = f5_ex.L7PolicyCreationException(err.message) except Exception as err: error = f5_ex.L7PolicyCreationException(err.message) if error: LOG.error("L7 policy creation error: %s" % error.message) return error def delete_l7policy(self, f5_l7policy, bigips): LOG.debug("L7PolicyService:delete_l7policy") error = False for bigip in bigips: try: self.policy_helper.delete(bigip, f5_l7policy['name'], f5_l7policy['partition']) except HTTPError as err: status_code = err.response.status_code if status_code == 404: LOG.warn("Deleting L7 policy failed...not found: %s", err.message) elif status_code == 400: LOG.debug( "Deleting L7 policy failed...unknown " "client error: %s", err.message) error = f5_ex.L7PolicyDeleteException(err.message) else: error = f5_ex.L7PolicyDeleteException(err.message) except Exception as err: LOG.exception(err) error = f5_ex.L7PolicyDeleteException(err.message) if error: LOG.error("L7 Policy deletion error: %s", error.message) return error def build_policy(self, l7policy, lbaas_service): # build data structure for service adapter input LOG.debug("L7PolicyService: service") import pprint # LOG.debug(pprint.pformat(lbaas_service.service_object, indent=4)) LOG.debug("L7PolicyService: l7policy") # LOG.debug(pprint.pformat(l7policy, indent=4)) l7policy_adapter = L7PolicyServiceAdapter(self.conf) os_policies = { 'l7rules': [], 'l7policies': [], 'f5_policy': {}, 'iRules': [] } # get all policies and rules for listener referenced by this policy listener = lbaas_service.get_listener(l7policy['listener_id']) for policy_id in listener['l7_policies']: policy = lbaas_service.get_l7policy(policy_id['id']) if policy: os_policies['l7policies'].append(policy) for rule in policy['rules']: l7rule = lbaas_service.get_l7rule(rule['id']) if l7rule: os_policies['l7rules'].append(l7rule) if os_policies['l7policies']: os_policies['f5_policy'] = l7policy_adapter.translate(os_policies) if getattr(l7policy_adapter, 'iRules', None): os_policies['iRules'] = l7policy_adapter.iRules LOG.debug(pprint.pformat(os_policies, indent=2)) return os_policies def create_irule(self, irules, bigips): LOG.debug("L7PolicyService: create_iRule") error = None for bigip in bigips: for rule in irules: try: self.rule_helper.create(bigip, rule) except HTTPError as err: status_code = err.response.status_code if status_code == 409: LOG.debug( "L7 rule (REGEX irule) already exists...updating") try: self.rule_helper.update(bigip, rule) except Exception as err: error = f5_ex.L7PolicyUpdateException(err.message) else: error = f5_ex.L7PolicyCreationException(err.message) except Exception as err: error = f5_ex.L7PolicyCreationException(err.message) if error: LOG.error("L7 rule (REGEX irule) creation error: %s" % error.message) return error def delete_irule(self, delete_irules, bigips): LOG.debug("L7PolicyService:delete_iRule") error = False for bigip in bigips: for rule in delete_irules: try: self.rule_helper.delete(bigip, name=rule.get('name'), partition=rule.get('partition')) except HTTPError as err: status_code = err.response.status_code if status_code == 404: LOG.warn( "Deleting L7 policy (iRule) " + "failed...not found: %s", err.message) elif status_code == 400: LOG.debug( "Deleting L7 policy (iRule) failed...unknown " "client error: %s", err.message) error = f5_ex.L7PolicyDeleteException(err.message) else: error = f5_ex.L7PolicyDeleteException(err.message) except Exception as err: LOG.exception(err) error = f5_ex.L7PolicyDeleteException(err.message) if error: LOG.error("L7 Policy (iRule) deletion error: %s", error.message) return error
class PoolServiceBuilder(object): """Create LBaaS v2 pools and related objects on BIG-IP®s. Handles requests to create, update, delete LBaaS v2 pools, health monitors, and members on one or more BIG-IP® systems. """ def __init__(self, service_adapter): self.service_adapter = service_adapter self.http_mon_helper = BigIPResourceHelper(ResourceType.http_monitor) self.https_mon_helper = BigIPResourceHelper(ResourceType.https_monitor) self.tcp_mon_helper = BigIPResourceHelper(ResourceType.tcp_monitor) self.ping_mon_helper = BigIPResourceHelper(ResourceType.ping_monitor) self.pool_helper = BigIPResourceHelper(ResourceType.pool) self.node_helper = BigIPResourceHelper(ResourceType.node) def create_pool(self, service, bigips): """Create a pool on set of BIG-IP®s. Creates a BIG-IP® pool to represent an LBaaS pool object. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to create pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.create(bigip, pool) def delete_pool(self, service, bigips): """Delete a pool on set of BIG-IP®s. Deletes a BIG-IP® pool defined by LBaaS pool object. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to delete pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.delete(bigip, name=pool["name"], partition=pool["partition"]) def update_pool(self, service, bigips): """Update BIG-IP® pool. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to create pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.update(bigip, pool) def create_healthmonitor(self, service, bigips): # create member hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) pool = self.service_adapter.get_pool(service) for bigip in bigips: hm_helper.create(bigip, hm) # update pool with new health monitor self.pool_helper.update(bigip, pool) def delete_healthmonitor(self, service, bigips): # delete health monitor hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) # update pool pool = self.service_adapter.get_pool(service) pool["monitor"] = "" for bigip in bigips: # need to first remove monitor reference from pool self.pool_helper.update(bigip, pool) # after updating pool, delete monitor hm_helper.delete(bigip, name=hm["name"], partition=hm["partition"]) def update_healthmonitor(self, service, bigips): hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) for bigip in bigips: hm_helper.update(bigip, hm) # Note: can't use BigIPResourceHelper class because members # are created within pool objects. Following member methods # use the F5® SDK directly. def create_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) for bigip in bigips: part = pool["partition"] p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members member_exists = m.exists(name=urllib.quote(member["name"]), partition=part) if not member_exists: m.create(**member) def delete_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] for bigip in bigips: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members member_exists = m.exists(name=urllib.quote(member["name"]), partition=part) if member_exists: m = m.load(name=urllib.quote(member["name"]), partition=part) m.delete() node = self.service_adapter.get_member_node(service) self.node_helper.delete(bigip, name=urllib.quote(node["name"]), partition=node["partition"]) def update_member(self, service, bigips): # TODO(jl) handle state -- SDK enforces at least state=None pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] for bigip in bigips: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members if m.exists(name=urllib.quote(member["name"]), partition=part): m = m.load(name=urllib.quote(member["name"]), partition=part) m.modify(**member) def _get_monitor_helper(self, service): monitor_type = self.service_adapter.get_monitor_type(service) if monitor_type == "HTTPS": hm = self.https_mon_helper elif monitor_type == "TCP": hm = self.tcp_mon_helper elif monitor_type == "PING": hm = self.ping_mon_helper else: hm = self.http_mon_helper return hm
class PoolServiceBuilder(object): """Create LBaaS v2 pools and related objects on BIG-IPs. Handles requests to create, update, delete LBaaS v2 pools, health monitors, and members on one or more BIG-IP systems. """ def __init__(self, service_adapter): self.service_adapter = service_adapter self.http_mon_helper = BigIPResourceHelper(ResourceType.http_monitor) self.https_mon_helper = BigIPResourceHelper(ResourceType.https_monitor) self.tcp_mon_helper = BigIPResourceHelper(ResourceType.tcp_monitor) self.ping_mon_helper = BigIPResourceHelper(ResourceType.ping_monitor) self.pool_helper = BigIPResourceHelper(ResourceType.pool) self.node_helper = BigIPResourceHelper(ResourceType.node) def create_pool(self, service, bigips): """Create a pool on set of BIG-IPs. Creates a BIG-IP pool to represent an LBaaS pool object. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to create pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.create(bigip, pool) def delete_pool(self, service, bigips): """Delete a pool on set of BIG-IPs. Deletes a BIG-IP pool defined by LBaaS pool object. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to delete pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.delete(bigip, name=pool["name"], partition=pool["partition"]) def update_pool(self, service, bigips): """Update BIG-IP pool. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to create pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.update(bigip, pool) def create_healthmonitor(self, service, bigips): # create member hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) pool = self.service_adapter.get_pool(service) for bigip in bigips: hm_helper.create(bigip, hm) # update pool with new health monitor self.pool_helper.update(bigip, pool) def delete_healthmonitor(self, service, bigips): # delete health monitor hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) # update pool pool = self.service_adapter.get_pool(service) pool["monitor"] = "" for bigip in bigips: # need to first remove monitor reference from pool self.pool_helper.update(bigip, pool) # after updating pool, delete monitor hm_helper.delete(bigip, name=hm["name"], partition=hm["partition"]) def update_healthmonitor(self, service, bigips): hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) pool = self.service_adapter.get_pool(service) for bigip in bigips: hm_helper.update(bigip, hm) # update pool with new health monitor self.pool_helper.update(bigip, pool) # Note: can't use BigIPResourceHelper class because members # are created within pool objects. Following member methods # use the F5 SDK directly. def create_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) for bigip in bigips: part = pool["partition"] p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members m.create(**member) def delete_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] for bigip in bigips: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members member_exists = m.exists(name=urllib.quote(member["name"]), partition=part) if member_exists: m = m.load(name=urllib.quote(member["name"]), partition=part) m.delete() try: node = self.service_adapter.get_member_node(service) self.node_helper.delete(bigip, name=urllib.quote(node["name"]), partition=node["partition"]) except HTTPError as err: # Possilbe error if node is shared with another member. # If so, ignore the error. if err.response.status_code == 400: LOG.debug(err.message) else: raise def update_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] for bigip in bigips: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members if m.exists(name=urllib.quote(member["name"]), partition=part): m = m.load(name=urllib.quote(member["name"]), partition=part) member.pop("address", None) m.modify(**member) def delete_orphaned_members(self, service, bigips): pool = self.service_adapter.get_pool(service) srv_members = service['members'] part = pool['partition'] for bigip in bigips: p = self.pool_helper.load(bigip, name=pool['name'], partition=part) deployed_members = p.members_s.get_collection() for dm in deployed_members: orphaned = True for sm in srv_members: svc = { "loadbalancer": service["loadbalancer"], "pool": service["pool"], "member": sm } member = self.service_adapter.get_member(svc) if member['name'] == dm.name: orphaned = False if orphaned: node_name = dm.address dm.delete() try: self.node_helper.delete(bigip, name=urllib.quote(node_name), partition=part) except HTTPError as err: # Possilbe error if node is shared with another member. # If so, ignore the error. if err.response.status_code == 400: LOG.debug(err.message) else: raise def _get_monitor_helper(self, service): monitor_type = self.service_adapter.get_monitor_type(service) if monitor_type == "HTTPS": hm = self.https_mon_helper elif monitor_type == "TCP": hm = self.tcp_mon_helper elif monitor_type == "PING": hm = self.ping_mon_helper else: hm = self.http_mon_helper return hm def get_member_status(self, service, bigip, status_keys): """Return status values for a single pool. Status keys to collect are defined as an array of strings in input status_keys. :param service: Has pool and member name/partition :param bigip: BIG-IP to get member status from. :param status_keys: Array of strings that define which status keys to collect. :return: A dict with key/value pairs for each status defined in input status_keys. """ member_status = {} pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] try: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) m = p.members_s.members if m.exists(name=urllib.quote(member["name"]), partition=part): m = m.load(name=urllib.quote(member["name"]), partition=part) member_status = self.pool_helper.collect_stats( m, stat_keys=status_keys) else: LOG.error( "Unable to get member status. " "Member %s does not exist.", member["name"]) except Exception as e: # log error but continue on LOG.error("Error getting member status: %s", e.message) return member_status
def __init__(self, conf): self.conf = conf self.policy_helper = BigIPResourceHelper(ResourceType.l7policy) self.rule_helper = BigIPResourceHelper(ResourceType.rule)
def __init__(self): self.folder_helper = BigIPResourceHelper(ResourceType.folder)
class BigipSelfIpManager(object): def __init__(self, driver, l2_service, l3_binding): self.driver = driver self.l2_service = l2_service self.l3_binding = l3_binding self.selfip_manager = BigIPResourceHelper(ResourceType.selfip) def assure_bigip_selfip(self, bigip, service, subnetinfo): network = subnetinfo['network'] if not network: LOG.error('Attempted to create selfip and snats ' 'for network with no id... skipping.') return subnet = subnetinfo['subnet'] tenant_id = service['pool']['tenant_id'] # If we have already assured this subnet.. return. # Note this cache is periodically cleared in order to # force assurance that the configuration is present. if tenant_id in bigip.assured_tenant_snat_subnets and \ subnet['id'] in bigip.assured_tenant_snat_subnets[tenant_id]: return selfip_address = self._get_bigip_selfip_address(bigip, subnet) selfip_address += '%' + str(network['route_domain_id']) if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = service['pool']['tenant_id'] (network_name, preserve_network_name) = \ self.l2_service.get_network_name(bigip, network) model = { "name": "local-" + bigip.device_name + "-" + subnet['id'], "ip_address": selfip_address, "netmask": netaddr.IPNetwork(subnet['cidr']).netmask, "vlan_name": network_name, "floating": "False", "folder": network_folder, "preserve_vlan_name": preserve_network_name} self.selfip_manager.create(bigip, model) # TO DO: we need to only bind the local SelfIP to the # local device... not treat it as if it was floating if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=selfip_address) def _get_bigip_selfip_address(self, bigip, subnet): # Get ip address for selfip to use on BIG-IP. selfip_name = "local-" + bigip.device_name + "-" + subnet['id'] ports = self.driver.plugin_rpc.get_port_by_name(port_name=selfip_name) if len(ports) > 0: port = ports[0] else: port = self.driver.plugin_rpc.create_port_on_subnet( subnet_id=subnet['id'], mac_address=None, name=selfip_name, fixed_address_count=1) return port['fixed_ips'][0]['ip_address'] def assure_gateway_on_subnet(self, bigip, subnetinfo, traffic_group): # Called for every bigip only in replication mode. # Otherwise called once. subnet = subnetinfo['subnet'] if subnet['id'] in bigip.assured_gateway_subnets: return network = subnetinfo['network'] (network_name, preserve_network_name) = \ self.l2_service.get_network_name(bigip, network) if self.l2_service.is_common_network(network): network_folder = 'Common' network_name = '/Common/' + network_name else: network_folder = subnet['tenant_id'] # Select a traffic group for the floating SelfIP floating_selfip_name = "gw-" + subnet['id'] netmask = netaddr.IPNetwork(subnet['cidr']).netmask bigip.selfip.create(name=floating_selfip_name, ip_address=subnet['gateway_ip'], netmask=netmask, vlan_name=network_name, floating=True, traffic_group=traffic_group, folder=network_folder, preserve_vlan_name=preserve_network_name) if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=subnet['gateway_ip']) # Setup a wild card ip forwarding virtual service for this subnet gw_name = "gw-" + subnet['id'] bigip.virtual_server.create_ip_forwarder( name=gw_name, ip_address='0.0.0.0', mask='0.0.0.0', vlan_name=network_name, traffic_group=traffic_group, folder=network_folder, preserve_vlan_name=preserve_network_name) # Setup the IP forwarding virtual server to use the Self IPs # as the forwarding SNAT addresses bigip.virtual_server.set_snat_automap(name=gw_name, folder=network_folder) bigip.assured_gateway_subnets.append(subnet['id']) def delete_gateway_on_subnet(self, bigip, subnetinfo): # Called for every bigip only in replication mode. # Otherwise called once. network = subnetinfo['network'] if not network: LOG.error('Attempted to delete default gateway ' 'for network with no id... skipping.') return subnet = subnetinfo['subnet'] if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = subnet['tenant_id'] floating_selfip_name = "gw-" + subnet['id'] if self.driver.conf.f5_populate_static_arp: bigip.arp.delete_by_subnet(subnet=subnetinfo['subnet']['cidr'], mask=None, folder=network_folder) bigip.selfip.delete(name=floating_selfip_name, folder=network_folder) if self.l3_binding: self.l3_binding.unbind_address(subnet_id=subnet['id'], ip_address=subnet['gateway_ip']) gw_name = "gw-" + subnet['id'] bigip.virtual_server.delete(name=gw_name, folder=network_folder) if subnet['id'] in bigip.assured_gateway_subnets: bigip.assured_gateway_subnets.remove(subnet['id']) return gw_name
class BigipSelfIpManager(object): def __init__(self, driver, l2_service, l3_binding): self.driver = driver self.l2_service = l2_service self.l3_binding = l3_binding self.selfip_manager = BigIPResourceHelper(ResourceType.selfip) self.network_helper = NetworkHelper() def _create_bigip_selfip(self, bigip, model): created = False if self.selfip_manager.exists(bigip, name=model['name'], partition=model['partition']): created = True else: try: self.selfip_manager.create(bigip, model) created = True except HTTPError as err: if (err.response.status_code == 400 and err.response.text.find( "must be one of the vlans " "in the associated route domain") > 0): try: self.network_helper.add_vlan_to_domain( bigip, name=model['vlan'], partition=model['partition']) self.selfip_manager.create(bigip, model) created = True except HTTPError as err: LOG.exception("Error creating selfip %s. " "Repsponse status code: %s. " "Response message: %s." % ( model["name"], err.response.status_code, err.message)) raise f5_ex.SelfIPCreationException("selfip") else: LOG.exception("selfip creation error: %s(%s)" % (err.message, err.response.status_code)) raise except Exception as err: LOG.error("Failed to create selfip") LOG.exception(err.message) raise f5_ex.SelfIPCreationException("selfip creation") return created def assure_bigip_selfip(self, bigip, service, subnetinfo): u"""Ensure the BigIP has a selfip address on the tenant subnet.""" network = None subnet = None if 'network' in subnetinfo: network = subnetinfo['network'] if 'subnet' in subnetinfo: subnet = subnetinfo['subnet'] if not network or not subnet: LOG.error('Attempted to create selfip and snats ' 'for network with not id...') raise KeyError("network and subnet need to be specified") tenant_id = service['loadbalancer']['tenant_id'] lb_id = service['loadbalancer']['id'] # If we have already assured this subnet.. return. # Note this cache is periodically cleared in order to # force assurance that the configuration is present. if tenant_id in bigip.assured_tenant_snat_subnets and \ subnet['id'] in bigip.assured_tenant_snat_subnets[tenant_id]: return True selfip_address = self._get_bigip_selfip_address(bigip, subnet, lb_id) if 'route_domain_id' not in network: LOG.error("network route domain is not set") raise KeyError() selfip_address += '%' + str(network['route_domain_id']) if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = self.driver.service_adapter.\ get_folder_name(service['loadbalancer']['tenant_id']) # Get the name of the vlan. (network_name, preserve_network_name) = \ self.l2_service.get_network_name(bigip, network) netmask = netaddr.IPNetwork(subnet['cidr']).prefixlen address = selfip_address + ("/%d" % netmask) model = { "name": "local-" + bigip.device_name + "-" + subnet['id'], "address": address, "vlan": network_name, "floating": "disabled", "partition": network_folder } self._create_bigip_selfip(bigip, model) if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=selfip_address) def _get_bigip_selfip_address(self, bigip, subnet, device_id): u"""Ensure a selfip address is allocated on Neutron network.""" # Get ip address for selfip to use on BIG-IP. selfip_address = "" selfip_name = "local-" + bigip.device_name + "-" + subnet['id'] ports = self.driver.plugin_rpc.get_port_by_name(port_name=selfip_name) if len(ports) > 0: port = ports[0] else: port = self.driver.plugin_rpc.create_port_on_subnet( subnet_id=subnet['id'], mac_address=None, name=selfip_name, fixed_address_count=1, device_id=device_id ) if port and 'fixed_ips' in port: fixed_ip = port['fixed_ips'][0] selfip_address = fixed_ip['ip_address'] return selfip_address def assure_gateway_on_subnet(self, bigip, subnetinfo, traffic_group): """Ensure """ network = None subnet = None if 'network' in subnetinfo: network = subnetinfo['network'] if 'subnet' in subnetinfo: subnet = subnetinfo['subnet'] if not network or not subnet: raise KeyError("network and subnet must be specified to create " "gateway on subnet.") if not subnet['gateway_ip']: raise KeyError("attempting to create gateway on subnet without " "gateway ip address specified.") if subnet['id'] in bigip.assured_gateway_subnets: return True (network_name, preserve_network_name) = \ self.l2_service.get_network_name(bigip, network) if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = self.driver.service_adapter.\ get_folder_name(subnet['tenant_id']) # Create a floating SelfIP for the given traffic-group. floating_selfip_name = "gw-" + subnet['id'] netmask = netaddr.IPNetwork(subnet['cidr']).prefixlen address = subnet['gateway_ip'] + "%" + str(network['route_domain_id']) address += ("/%d" % (netmask)) model = { 'name': floating_selfip_name, 'address': address, 'vlan': network_name, 'floating': True, 'traffic-group': traffic_group, 'partition': network_folder } if not self._create_bigip_selfip(bigip, model): LOG.error("failed to create gateway selfip") if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=subnet['gateway_ip']) # Setup a wild card ip forwarding virtual service for this subnet gw_name = "gw-" + subnet['id'] vs = bigip.tm.ltm.virtuals.virtual if not vs.exists(name=gw_name, partition=network_folder): try: vs.create( name=gw_name, partition=network_folder, destination='0.0.0.0:0', mask='0.0.0.0', vlansEnabled=True, vlans=[network_name], sourceAddressTranslation={'type': 'automap'}, ipForward=True ) except Exception as err: LOG.exception(err) raise f5_ex.VirtualServerCreationException( "Failed to create gateway virtual service on subnet %s", subnet['id'] ) # Put the virtual server address in the specified traffic group virtual_address = bigip.tm.ltm.virtual_address_s.virtual_address try: obj = virtual_address.load( name='0.0.0.0', partition=network_folder) obj.modify(trafficGroup=traffic_group) except Exception as err: LOG.exception(err) raise f5_ex.VirtualServerCreationException( "Failed to add virtual address to traffic group %s", traffic_group) bigip.assured_gateway_subnets.append(subnet['id']) def delete_gateway_on_subnet(self, bigip, subnetinfo): network = None subnet = None if 'network' in subnetinfo: network = subnetinfo['network'] if 'subnet' in subnetinfo: subnet = subnetinfo['subnet'] if not network or not subnet: LOG.error('Attempted to create selfip and snats ' 'for network with no id...') raise KeyError("network and subnet must be specified") if not subnet['gateway_ip']: raise KeyError("attempting to create gateway on subnet without " "gateway ip address specified.") if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = self.driver.service_adapter.\ get_folder_name(subnet['tenant_id']) if self.driver.conf.f5_populate_static_arp: self.network_helper.arp_delete_by_subnet( bigip, partition=network_folder, subnet=subnetinfo['subnet']['cidr'], mask=None ) floating_selfip_name = "gw-" + subnet['id'] self.delete_selfip( bigip, floating_selfip_name, network_folder) if self.l3_binding: self.l3_binding.unbind_address(subnet_id=subnet['id'], ip_address=subnet['gateway_ip']) gw_name = "gw-" + subnet['id'] vs = bigip.tm.ltm.virtuals.virtual try: if vs.exists(name=gw_name, partition=network_folder): obj = vs.load(name=gw_name, partition=network_folder) obj.delete() except Exception as err: LOG.exception(err) raise f5_ex.VirtualServerDeleteException( "Failed to delete gateway service on subnet %s", subnet['id']) if subnet['id'] in bigip.assured_gateway_subnets: bigip.assured_gateway_subnets.remove(subnet['id']) return gw_name def get_selfip_addr(self, bigip, name, partition=const.DEFAULT_PARTITION): selfip_addr = "" try: s = bigip.tm.net.selfips.selfip if s.exists(name=name, partition=partition): obj = s.load(name=name, partition=partition) # The selfip address on BigIP is actually a network, # parse out the address portion. if obj.address: (selfip_addr, netbits) = obj.address.split("/") except HTTPError as err: LOG.exception("Error getting selfip address for %s. " "Repsponse status code: %s. Response " "message: %s." % (name, err.response.status_code, err.message)) except Exception as err: LOG.exception("Error getting selfip address for %s.", name) return selfip_addr def get_selfips(self, bigip, partition=const.DEFAULT_PARTITION, vlan_name=None): selfips_list = [] if vlan_name: if not vlan_name.startswith('/'): vlan_name = "/%s/%s" % (partition, vlan_name) params = {'params': get_filter(bigip, 'partition', 'eq', partition)} try: selfips_list = [selfip for selfip in bigip.tm.net.selfips.get_collection( requests_params=params ) if vlan_name == selfip.vlan or not vlan_name] except HTTPError as err: LOG.exception("Error getting selfips for vlan(%s). " "Response status code: %s. " "Response message: %s." % ( vlan_name, err.response.status_code, err.message)) raise f5_ex.SelfIPQueryException( "Failed to get selfips assigned to vlan") return selfips_list def delete_selfip(self, bigip, name, partition=const.DEFAULT_PARTITION): """Delete the selfip if it exists.""" try: s = bigip.tm.net.selfips.selfip if s.exists(name=name, partition=partition): obj = s.load(name=name, partition=partition) obj.delete() except HTTPError as err: LOG.exception("Error deleting selfip %s. " "Response status code: %s. Response " "message: %s." % (name, err.response.status_code, err.message)) raise f5_ex.SelfIPDeleteException( "Failed to delete selfip %s." % name) except Exception as err: raise f5_ex.SelfIPDeleteException( "Failed to delete selfip %s." % name)
class BigipSelfIpManager(object): def __init__(self, driver, l2_service, l3_binding): self.driver = driver self.l2_service = l2_service self.l3_binding = l3_binding self.selfip_manager = BigIPResourceHelper(ResourceType.selfip) self.network_helper = NetworkHelper() def _create_bigip_selfip(self, bigip, model): created = False if self.selfip_manager.exists(bigip, name=model['name'], partition=model['partition']): created = True else: try: self.selfip_manager.create(bigip, model) created = True except HTTPError as err: if (err.response.status_code == 400 and err.response.text.find( "must be one of the vlans " "in the associated route domain") > 0): try: self.network_helper.add_vlan_to_domain( bigip, name=model['vlan'], partition=model['partition']) self.selfip_manager.create(bigip, model) created = True except HTTPError as err: LOG.exception("Error creating selfip %s. " "Repsponse status code: %s. " "Response message: %s." % (model["name"], err.response.status_code, err.message)) raise f5_ex.SelfIPCreationException("selfip") else: LOG.exception("selfip creation error: %s(%s)" % (err.message, err.response.status_code)) raise except Exception as err: LOG.error("Failed to create selfip") LOG.exception(err.message) raise f5_ex.SelfIPCreationException("selfip creation") return created def assure_bigip_selfip(self, bigip, service, subnetinfo): u"""Ensure the BigIP has a selfip address on the tenant subnet.""" network = None subnet = None if 'network' in subnetinfo: network = subnetinfo['network'] if 'subnet' in subnetinfo: subnet = subnetinfo['subnet'] if not network or not subnet: LOG.error('Attempted to create selfip and snats ' 'for network with not id...') raise KeyError("network and subnet need to be specified") tenant_id = service['loadbalancer']['tenant_id'] lb_id = service['loadbalancer']['id'] # If we have already assured this subnet.. return. # Note this cache is periodically cleared in order to # force assurance that the configuration is present. if tenant_id in bigip.assured_tenant_snat_subnets and \ subnet['id'] in bigip.assured_tenant_snat_subnets[tenant_id]: return True selfip_address = self._get_bigip_selfip_address(bigip, subnet, lb_id) if 'route_domain_id' not in network: LOG.error("network route domain is not set") raise KeyError() selfip_address += '%' + str(network['route_domain_id']) if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = self.driver.service_adapter.\ get_folder_name(service['loadbalancer']['tenant_id']) # Get the name of the vlan. (network_name, preserve_network_name) = \ self.l2_service.get_network_name(bigip, network) netmask = netaddr.IPNetwork(subnet['cidr']).prefixlen address = selfip_address + ("/%d" % netmask) model = { "name": "local-" + bigip.device_name + "-" + subnet['id'], "address": address, "vlan": network_name, "floating": "disabled", "partition": network_folder } self._create_bigip_selfip(bigip, model) if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=selfip_address) def _get_bigip_selfip_address(self, bigip, subnet, device_id): u"""Ensure a selfip address is allocated on Neutron network.""" # Get ip address for selfip to use on BIG-IP. if self.driver.conf.unlegacy_setting_placeholder: LOG.debug('setting vnic_type to normal instead of baremetal') vnic_type = "normal" else: vnic_type = "baremetal" selfip_address = "" selfip_name = "local-" + bigip.device_name + "-" + subnet['id'] ports = self.driver.plugin_rpc.get_port_by_name(port_name=selfip_name) if len(ports) > 0: port = ports[0] else: port = self.driver.plugin_rpc.create_port_on_subnet( subnet_id=subnet['id'], mac_address=None, name=selfip_name, fixed_address_count=1, device_id=device_id, vnic_type=vnic_type) if port and 'fixed_ips' in port: fixed_ip = port['fixed_ips'][0] selfip_address = fixed_ip['ip_address'] return selfip_address def assure_gateway_on_subnet(self, bigip, subnetinfo, traffic_group): """Ensure """ network = None subnet = None if 'network' in subnetinfo: network = subnetinfo['network'] if 'subnet' in subnetinfo: subnet = subnetinfo['subnet'] if not network or not subnet: raise KeyError("network and subnet must be specified to create " "gateway on subnet.") if not subnet['gateway_ip']: raise KeyError("attempting to create gateway on subnet without " "gateway ip address specified.") if subnet['id'] in bigip.assured_gateway_subnets: return True (network_name, preserve_network_name) = \ self.l2_service.get_network_name(bigip, network) if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = self.driver.service_adapter.\ get_folder_name(subnet['tenant_id']) # Create a floating SelfIP for the given traffic-group. floating_selfip_name = "gw-" + subnet['id'] netmask = netaddr.IPNetwork(subnet['cidr']).prefixlen address = subnet['gateway_ip'] + "%" + str(network['route_domain_id']) address += ("/%d" % (netmask)) model = { 'name': floating_selfip_name, 'address': address, 'vlan': network_name, 'floating': True, 'traffic-group': traffic_group, 'partition': network_folder } if not self._create_bigip_selfip(bigip, model): LOG.error("failed to create gateway selfip") if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=subnet['gateway_ip']) # Setup a wild card ip forwarding virtual service for this subnet gw_name = "gw-" + subnet['id'] vs = bigip.tm.ltm.virtuals.virtual if not vs.exists(name=gw_name, partition=network_folder): try: vs.create(name=gw_name, partition=network_folder, destination='0.0.0.0:0', mask='0.0.0.0', vlansEnabled=True, vlans=[network_name], sourceAddressTranslation={'type': 'automap'}, ipForward=True) except Exception as err: LOG.exception(err) raise f5_ex.VirtualServerCreationException( "Failed to create gateway virtual service on subnet %s", subnet['id']) # Put the virtual server address in the specified traffic group virtual_address = bigip.tm.ltm.virtual_address_s.virtual_address try: obj = virtual_address.load(name='0.0.0.0', partition=network_folder) obj.modify(trafficGroup=traffic_group) except Exception as err: LOG.exception(err) raise f5_ex.VirtualServerCreationException( "Failed to add virtual address to traffic group %s", traffic_group) bigip.assured_gateway_subnets.append(subnet['id']) def delete_gateway_on_subnet(self, bigip, subnetinfo): network = None subnet = None if 'network' in subnetinfo: network = subnetinfo['network'] if 'subnet' in subnetinfo: subnet = subnetinfo['subnet'] if not network or not subnet: LOG.error('Attempted to create selfip and snats ' 'for network with no id...') raise KeyError("network and subnet must be specified") if not subnet['gateway_ip']: raise KeyError("attempting to create gateway on subnet without " "gateway ip address specified.") if self.l2_service.is_common_network(network): network_folder = 'Common' else: network_folder = self.driver.service_adapter.\ get_folder_name(subnet['tenant_id']) if self.driver.conf.f5_populate_static_arp: self.network_helper.arp_delete_by_subnet( bigip, partition=network_folder, subnet=subnetinfo['subnet']['cidr'], mask=None) floating_selfip_name = "gw-" + subnet['id'] self.delete_selfip(bigip, floating_selfip_name, network_folder) if self.l3_binding: self.l3_binding.unbind_address(subnet_id=subnet['id'], ip_address=subnet['gateway_ip']) gw_name = "gw-" + subnet['id'] vs = bigip.tm.ltm.virtuals.virtual try: if vs.exists(name=gw_name, partition=network_folder): obj = vs.load(name=gw_name, partition=network_folder) obj.delete() except Exception as err: LOG.exception(err) raise f5_ex.VirtualServerDeleteException( "Failed to delete gateway service on subnet %s", subnet['id']) if subnet['id'] in bigip.assured_gateway_subnets: bigip.assured_gateway_subnets.remove(subnet['id']) return gw_name def get_selfip_addr(self, bigip, name, partition=const.DEFAULT_PARTITION): selfip_addr = "" try: s = bigip.tm.net.selfips.selfip if s.exists(name=name, partition=partition): obj = s.load(name=name, partition=partition) # The selfip address on BigIP is actually a network, # parse out the address portion. if obj.address: (selfip_addr, netbits) = obj.address.split("/") except HTTPError as err: LOG.exception("Error getting selfip address for %s. " "Repsponse status code: %s. Response " "message: %s." % (name, err.response.status_code, err.message)) except Exception as err: LOG.exception("Error getting selfip address for %s.", name) return selfip_addr def get_selfips(self, bigip, partition=const.DEFAULT_PARTITION, vlan_name=None): selfips_list = [] if vlan_name: if not vlan_name.startswith('/'): vlan_name = "/%s/%s" % (partition, vlan_name) params = {'params': get_filter(bigip, 'partition', 'eq', partition)} try: selfips_list = [ selfip for selfip in bigip.tm.net.selfips.get_collection( requests_params=params) if vlan_name == selfip.vlan or not vlan_name ] except HTTPError as err: LOG.exception("Error getting selfips for vlan(%s). " "Response status code: %s. " "Response message: %s." % (vlan_name, err.response.status_code, err.message)) raise f5_ex.SelfIPQueryException( "Failed to get selfips assigned to vlan") return selfips_list def delete_selfip(self, bigip, name, partition=const.DEFAULT_PARTITION): """Delete the selfip if it exists.""" try: s = bigip.tm.net.selfips.selfip if s.exists(name=name, partition=partition): obj = s.load(name=name, partition=partition) obj.delete() except HTTPError as err: LOG.exception("Error deleting selfip %s. " "Response status code: %s. Response " "message: %s." % (name, err.response.status_code, err.message)) raise f5_ex.SelfIPDeleteException("Failed to delete selfip %s." % name) except Exception as err: raise f5_ex.SelfIPDeleteException("Failed to delete selfip %s." % name)
class BigipSnatManager(object): def __init__(self, driver, l2_service, l3_binding): self.driver = driver self.l2_service = l2_service self.l3_binding = l3_binding self.snatpool_manager = BigIPResourceHelper(ResourceType.snatpool) self.snat_translation_manager = BigIPResourceHelper( ResourceType.snat_translation) self.network_helper = NetworkHelper() def _get_snat_name(self, subnet, tenant_id): # Get the snat name based on HA type if self.driver.conf.f5_ha_type == 'standalone': return 'snat-traffic-group-local-only-' + subnet['id'] elif self.driver.conf.f5_ha_type == 'pair': return 'snat-traffic-group-1-' + subnet['id'] elif self.driver.conf.f5_ha_type == 'scalen': traffic_group = self.driver.tenant_to_traffic_group(tenant_id) base_traffic_group = os.path.basename(traffic_group) return 'snat-' + base_traffic_group + '-' + subnet['id'] LOG.error('Invalid f5_ha_type:%s' % self.driver.conf.f5_ha_type) return '' def _get_snat_traffic_group(self, tenant_id): # Get the snat name based on HA type """ if self.driver.conf.f5_ha_type == 'standalone': return 'traffic-group-local-only' elif self.driver.conf.f5_ha_type == 'pair': return 'traffic-group-1' elif self.driver.conf.f5_ha_type == 'scalen': traffic_group = self.driver.tenant_to_traffic_group(tenant_id) return os.path.basename(traffic_group) # If this is an error shouldn't we raise? LOG.error('Invalid f5_ha_type:%s' % self.driver.conf.f5_ha_type) return '' def get_snat_addrs(self, subnetinfo, tenant_id, snat_count): # Get the ip addresses for snat """ subnet = subnetinfo['subnet'] snat_addrs = [] snat_name = self._get_snat_name(subnet, tenant_id) for i in range(snat_count): ip_address = "" index_snat_name = snat_name + "_" + str(i) ports = self.driver.plugin_rpc.get_port_by_name( port_name=index_snat_name) if len(ports) > 0: first_port = ports[0] first_fixed_ip = first_port['fixed_ips'][0] ip_address = first_fixed_ip['ip_address'] else: new_port = self.driver.plugin_rpc.create_port_on_subnet( subnet_id=subnet['id'], mac_address=None, name=index_snat_name, fixed_address_count=1) if new_port is not None: ip_address = new_port['fixed_ips'][0]['ip_address'] # Push the IP address on the list if the port was acquired. if len(ip_address) > 0: snat_addrs.append(ip_address) else: LOG.error("get_snat_addrs: failed to allocate port for " "SNAT address.") return snat_addrs def assure_bigip_snats(self, bigip, subnetinfo, snat_addrs, tenant_id): # Ensure Snat Addresses are configured on a bigip. # Called for every bigip only in replication mode. # otherwise called once and synced. network = subnetinfo['network'] snat_info = {} if self.l2_service.is_common_network(network): snat_info['network_folder'] = 'Common' else: snat_info['network_folder'] = ( self.driver.service_adapter.get_folder_name(tenant_id) ) snat_info['pool_name'] = self.driver.service_adapter.get_folder_name( tenant_id ) snat_info['pool_folder'] = self.driver.service_adapter.get_folder_name( tenant_id ) snat_info['addrs'] = snat_addrs self._assure_bigip_snats(bigip, subnetinfo, snat_info, tenant_id) def _assure_bigip_snats(self, bigip, subnetinfo, snat_info, tenant_id): # Configure the ip addresses for snat network = subnetinfo['network'] subnet = subnetinfo['subnet'] if tenant_id not in bigip.assured_tenant_snat_subnets: bigip.assured_tenant_snat_subnets[tenant_id] = [] if subnet['id'] in bigip.assured_tenant_snat_subnets[tenant_id]: return snat_name = self._get_snat_name(subnet, tenant_id) for i, snat_address in enumerate(snat_info['addrs']): ip_address = snat_address + \ '%' + str(network['route_domain_id']) index_snat_name = snat_name + "_" + str(i) snat_traffic_group = self._get_snat_traffic_group(tenant_id) # snat.create() did the following in LBaaSv1 # Creates the SNAT # * if the traffic_group is empty it uses a const # but this seems like it should be an error see message # in this file about this # Create a SNAT Pool if a name was passed in # * Add the snat to the list of members model = { "name": index_snat_name, "partition": snat_info['network_folder'], "address": ip_address, "trafficGroup": snat_traffic_group } try: if not self.snat_translation_manager.exists( bigip, name=index_snat_name, partition=snat_info['network_folder']): self.snat_translation_manager.create(bigip, model) except Exception as err: LOG.exception(err) raise f5_ex.SNATCreationException( "Error creating snat translation manager %s" % index_snat_name) model = { "name": snat_info['pool_name'], "partition": snat_info['network_folder'], } snatpool_member = ('/' + model["partition"] + '/' + index_snat_name) model["members"] = [snatpool_member] try: if not self.snatpool_manager.exists( bigip, name=model['name'], partition=model['partition']): LOG.debug("Creating SNAT pool: %s" % model) self.snatpool_manager.create(bigip, model) else: LOG.debug("Updating SNAT pool") snatpool = self.snatpool_manager.load( bigip, name=model["name"], partition=model["partition"] ) snatpool.members.append(snatpool_member) snatpool.modify(members=snatpool.members) except Exception as err: LOG.error("Create SNAT pool failed %s" % err.message) raise f5_ex.SNATCreationException( "Failed to create SNAT pool") if self.l3_binding: self.l3_binding.bind_address(subnet_id=subnet['id'], ip_address=ip_address) bigip.assured_tenant_snat_subnets[tenant_id].append(subnet['id']) def delete_bigip_snats(self, bigip, subnetinfo, tenant_id): # Assure shared snat configuration (which syncs) is deleted. # if not subnetinfo['network']: LOG.error('Attempted to delete selfip and snats ' 'for missing network ... skipping.') return set() return self._delete_bigip_snats(bigip, subnetinfo, tenant_id) def _remove_assured_tenant_snat_subnet(self, bigip, tenant_id, subnet): # Remove ref for the subnet for this tenant""" if tenant_id in bigip.assured_tenant_snat_subnets: tenant_snat_subnets = \ bigip.assured_tenant_snat_subnets[tenant_id] if tenant_snat_subnets and subnet['id'] in tenant_snat_subnets: LOG.debug( 'Remove subnet id %s from ' 'bigip.assured_tenant_snat_subnets for tenant %s' % (subnet['id'], tenant_id)) tenant_snat_subnets.remove(subnet['id']) else: LOG.debug( 'Subnet id %s does not exist in ' 'bigip.assured_tenant_snat_subnets for tenant %s' % (subnet['id'], tenant_id)) else: LOG.debug( 'Tenant id %s does not exist in ' 'bigip.assured_tenant_snat_subnets' % tenant_id) def _delete_bigip_snats(self, bigip, subnetinfo, tenant_id): # Assure snats deleted in standalone mode """ subnet = subnetinfo['subnet'] network = subnetinfo['network'] if self.l2_service.is_common_network(network): partition = 'Common' else: partition = self.driver.service_adapter.get_folder_name(tenant_id) snat_pool_name = self.driver.service_adapter.get_folder_name(tenant_id) deleted_names = set() in_use_subnets = set() # Delete SNATs on traffic-group-local-only snat_name = self._get_snat_name(subnet, tenant_id) for i in range(self.driver.conf.f5_snat_addresses_per_subnet): index_snat_name = snat_name + "_" + str(i) tmos_snat_name = index_snat_name if self.l3_binding: try: snat_xlate = self.snat_translation_manager.load( bigip, name=index_snat_name, partition=partition) except HTTPError as err: LOG.error("Load SNAT xlate failed %s" % err.message) except Exception: LOG.error("Unknown error occurred loading SNAT for unbind") else: self.l3_binding.unbind_address( subnet_id=subnet['id'], ip_address=snat_xlate.address) # Remove translation address from tenant snat pool # This seems strange that name and partition are tenant_id # but that is what the v1 code was doing. # The v1 code was also comparing basename in some cases # which seems dangerous because the folder may be in play? # # Revised (jl): It appears that v2 SNATs are created with a # name, not tenant_id, so we need to load SNAT by name. LOG.debug('Remove translation address from tenant SNAT pool') try: snatpool = self.snatpool_manager.load(bigip, snat_pool_name, partition) snatpool.members = [ member for member in snatpool.members if os.path.basename(member) != tmos_snat_name ] # Delete snat pool if empty (no members) # In LBaaSv1 the snat.remove_from_pool() method did this if # there was only one member and it matched the one we were # deleting making this call basically useless, but the # code above makes this still necessary and probably what the # original authors intended anyway since there is logging here # but not in the snat.py module from LBaaSv1 LOG.debug('Check if snat pool is empty') if not snatpool.members: LOG.debug('Snat pool is empty - delete snatpool') try: snatpool.delete() except HTTPError as err: LOG.error("Delete SNAT pool failed %s" % err.message) else: LOG.debug('Snat pool is not empty - update snatpool') try: snatpool.modify(members=snatpool.members) except HTTPError as err: LOG.error("Update SNAT pool failed %s" % err.message) except HTTPError as err: LOG.error("Failed to load SNAT pool %s" % err.message) # Check if subnet in use by any tenants/snatpools. If in use, # add subnet to hints list of subnets in use. self._remove_assured_tenant_snat_subnet(bigip, tenant_id, subnet) LOG.debug( 'Check cache for subnet %s in use by other tenant' % subnet['id']) in_use_count = 0 for loop_tenant_id in bigip.assured_tenant_snat_subnets: tenant_snat_subnets = \ bigip.assured_tenant_snat_subnets[loop_tenant_id] if subnet['id'] in tenant_snat_subnets: LOG.debug( 'Subnet %s in use (tenant %s)' % (subnet['id'], loop_tenant_id)) in_use_count += 1 if in_use_count: in_use_subnets.add(subnet['id']) else: LOG.debug('Check subnet in use by any tenant') member_use_count = \ self.get_snatpool_member_use_count( bigip, subnet['id']) if member_use_count: LOG.debug('Subnet in use - do not delete') in_use_subnets.add(subnet['id']) else: LOG.debug('Subnet not in use - delete') # Check if trans addr in use by any snatpool. If not in use, # okay to delete associated neutron port. LOG.debug('Check trans addr %s in use.' % tmos_snat_name) in_use_count = \ self.get_snatpool_member_use_count( bigip, tmos_snat_name) if not in_use_count: LOG.debug('Trans addr not in use - delete') deleted_names.add(index_snat_name) else: LOG.debug('Trans addr in use - do not delete') return deleted_names, in_use_subnets def get_snatpool_member_use_count(self, bigip, member_name): snat_count = 0 snatpools = bigip.tm.ltm.snatpools.get_collection() for snatpool in snatpools: for member in snatpool.members: if member_name == os.path.basename(member): snat_count += 1 return snat_count
# Note: symbols_data provided through commandline json file. from pytest import symbols as symbols_data class DummyConf(object): def __init__(self): self.environment_prefix = 'Project' self.f5_snat_mode = True requests.packages.urllib3.disable_warnings(InsecureRequestWarning) disconnected_service = DisconnectedService() service_adapter = ServiceModelAdapter(DummyConf()) listener_builder = ListenerServiceBuilder(service_adapter) folder_helper = BigIPResourceHelper(ResourceType.folder) bigips = [ BigIP(symbols_data.bigip_ip, symbols_data.bigip_username, symbols_data.bigip_password) ] def deploy_service(service_file): service = {'listeners': []} folder = None try: service = json.load(open(service_file))["service"] # create partition folder = service_adapter.get_folder(service)
class PoolServiceBuilder(object): """Create LBaaS v2 pools and related objects on BIG-IPs. Handles requests to create, update, delete LBaaS v2 pools, health monitors, and members on one or more BIG-IP systems. """ def __init__(self, service_adapter): self.service_adapter = service_adapter self.http_mon_helper = BigIPResourceHelper(ResourceType.http_monitor) self.https_mon_helper = BigIPResourceHelper(ResourceType.https_monitor) self.tcp_mon_helper = BigIPResourceHelper(ResourceType.tcp_monitor) self.ping_mon_helper = BigIPResourceHelper(ResourceType.ping_monitor) self.pool_helper = BigIPResourceHelper(ResourceType.pool) self.node_helper = BigIPResourceHelper(ResourceType.node) def create_pool(self, service, bigips): """Create a pool on set of BIG-IPs. Creates a BIG-IP pool to represent an LBaaS pool object. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to create Listener. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: try: self.pool_helper.create(bigip, pool) except HTTPError as err: LOG.error("Error creating pool %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (pool["name"], bigip.device_name, err.response.status_code, err.message)) def delete_pool(self, service, bigips): """Delete a pool on set of BIG-IPs. Deletes a BIG-IP pool defined by LBaaS pool object. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigips: Array of BigIP class instances to delete pool. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: try: self.pool_helper.delete(bigip, name=pool["name"], partition=pool["partition"]) except HTTPError as err: LOG.error("Error deleting pool %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (pool["name"], bigip.device_name, err.response.status_code, err.message)) def update_pool(self, service, bigips): """Update BIG-IP pool. :param service: Dictionary which contains a both a pool and load balancer definition. :param bigip: Array of BigIP class instances to create Listener. """ pool = self.service_adapter.get_pool(service) for bigip in bigips: try: self.pool_helper.update(bigip, pool) except HTTPError as err: LOG.error("Error updating pool %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (pool["name"], bigip.device_name, err.response.status_code, err.message)) def create_healthmonitor(self, service, bigips): # create member hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) for bigip in bigips: try: hm_helper.create(bigip, hm) except HTTPError as err: LOG.error("Error creating health monitor %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (hm["name"], bigip.device_name, err.response.status_code, err.message)) # update pool with new health monitor pool = self.service_adapter.get_pool(service) for bigip in bigips: self.pool_helper.update(bigip, pool) def delete_healthmonitor(self, service, bigips): # delete health monitor hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) # update pool pool = self.service_adapter.get_pool(service) pool["monitor"] = "" for bigip in bigips: # need to first remove monitor reference from pool try: self.pool_helper.update(bigip, pool) except HTTPError as err: LOG.error("Error updating pool %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (pool["name"], bigip.device_name, err.response.status_code, err.message)) try: hm_helper.delete(bigip, name=hm["name"], partition=hm["partition"]) except HTTPError as err: LOG.error("Error deleting health monitor %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (hm["name"], bigip.device_name, err.response.status_code, err.message)) def update_healthmonitor(self, service, bigips): hm = self.service_adapter.get_healthmonitor(service) hm_helper = self._get_monitor_helper(service) for bigip in bigips: try: hm_helper.delete(bigip, name=hm["name"], partition=hm["partition"]) except HTTPError as err: LOG.error("Error updating health monitor %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (hm["name"], bigip.device_name, err.response.status_code, err.message)) # Note: can't use BigIPResourceHelper class because members # are created within pool objects. Following member methods # use the F5 SDK directly. def create_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) for bigip in bigips: part = pool["partition"] try: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) except HTTPError as err: LOG.error("Error loading pool %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (pool["name"], bigip.device_name, err.response.status_code, err.message)) continue m = p.members_s.members try: member_exists = m.exists(name=member["name"], partition=part) except HTTPError as err: LOG.error("Error checking if member %s exists on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (member["name"], bigip.device_name, err.response.status_code, err.message)) continue if not member_exists: try: m.create(**member) except HTTPError as err: LOG.error("Error creating member %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (member["name"], bigip.device_name, err.response.status_code, err.message)) def delete_member(self, service, bigips): pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] for bigip in bigips: try: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) except HTTPError as err: LOG.error("Error loading pool %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (pool["name"], bigip.device_name, err.response.status_code, err.message)) continue m = p.members_s.members try: member_exists = m.exists(name=member["name"], partition=part) except HTTPError as err: LOG.error("Error checking if member %s exists on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (member["name"], bigip.device_name, err.response.status_code, err.message)) continue if member_exists: try: m = m.load(name=member["name"], partition=part) except HTTPError as err: LOG.error("Error loading member %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (member["name"], bigip.device_name, err.response.status_code, err.message)) continue try: m.delete() node = self.service_adapter.get_member_node(service) self.node_helper.delete(bigip, name=node["name"], partition=node["partition"]) except HTTPError as err: LOG.error("Error deleting member %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (member["name"], bigip.device_name, err.response.status_code, err.message)) def update_member(self, service, bigips): # TODO(jl) handle state -- SDK enforces at least state=None pool = self.service_adapter.get_pool(service) member = self.service_adapter.get_member(service) part = pool["partition"] for bigip in bigips: try: p = self.pool_helper.load(bigip, name=pool["name"], partition=part) except HTTPError as err: LOG.error("Error loading pool %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (pool["name"], bigip.device_name, err.response.status_code, err.message)) continue m = p.members_s.members try: member_exists = m.exists(name=member["name"], partition=part) except HTTPError as err: LOG.error("Error checking if member %s exists on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (member["name"], bigip.device_name, err.response.status_code, err.message)) continue if member_exists: try: m = m.load(name=member["name"], partition=part) except HTTPError as err: LOG.error("Error loading member %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (member["name"], bigip.device_name, err.response.status_code, err.message)) continue try: m.update(**member) except HTTPError as err: LOG.error("Error updating member %s on BIG-IP %s. " "Repsponse status code: %s. Response " "message: %s." % (member["name"], bigip.device_name, err.response.status_code, err.message)) def _get_monitor_helper(self, service): monitor_type = self.service_adapter.get_monitor_type(service) if monitor_type == "HTTPS": hm = self.https_mon_helper elif monitor_type == "TCP": hm = self.tcp_mon_helper elif monitor_type == "PING": hm = self.ping_mon_helper else: hm = self.http_mon_helper return hm