예제 #1
0
 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()
예제 #2
0
 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 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)
예제 #5
0
    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)
예제 #6
0
    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
예제 #7
0
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)
 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)
예제 #9
0
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'])
예제 #10
0
    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)
예제 #11
0
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
예제 #12
0
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
예제 #13
0
 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()
예제 #14
0
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
예제 #15
0
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
예제 #17
0
 def __init__(self, conf):
     self.conf = conf
     self.policy_helper = BigIPResourceHelper(ResourceType.l7policy)
     self.rule_helper = BigIPResourceHelper(ResourceType.rule)
예제 #18
0
 def __init__(self):
     self.folder_helper = BigIPResourceHelper(ResourceType.folder)
예제 #19
0
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
예제 #20
0
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
예제 #21
0
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)
예제 #22
0
 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()
예제 #23
0
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)
예제 #24
0
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
예제 #25
0
# 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)
예제 #26
0
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