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'])
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
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)