Ejemplo n.º 1
0
 def _check_member_monitor_options(self, member):
     if self._check_monitor_options(member):
         msg = _('OVN Load Balancer does not support different member '
                 'monitor address or port.')
         raise driver_exceptions.UnsupportedOptionError(
             user_fault_string=msg,
             operator_fault_string=msg)
Ejemplo n.º 2
0
 def _validate_pool_algorithm(self, pool):
     if pool.lb_algorithm not in AMPHORA_SUPPORTED_LB_ALGORITHMS:
         msg = ('Amphora provider does not support %s algorithm.'
                % pool.lb_algorithm)
         raise exceptions.UnsupportedOptionError(
             user_fault_string=msg,
             operator_fault_string=msg)
Ejemplo n.º 3
0
 def _validate_listener_protocol(self, listener):
     if listener.protocol not in AMPHORA_SUPPORTED_PROTOCOLS:
         msg = ('Amphora provider does not support %s protocol. '
                'Supported: %s' %
                (listener.protocol, ", ".join(AMPHORA_SUPPORTED_PROTOCOLS)))
         raise exceptions.UnsupportedOptionError(user_fault_string=msg,
                                                 operator_fault_string=msg)
Ejemplo n.º 4
0
    def validate_flavor(self, flavor_dict):
        """Validates flavor profile data.

        This will validate a flavor profile dataset against the flavor
        settings the amphora driver supports.

        :param flavor_dict: The flavor dictionary to validate.
        :type flavor: dict
        :return: None
        :raises DriverError: An unexpected error occurred.
        :raises UnsupportedOptionError: If the driver does not support
          one of the flavor settings.
        """
        try:
            validate(flavor_dict, flavor_schema.SUPPORTED_FLAVOR_SCHEMA)
        except js_exceptions.ValidationError as e:
            error_object = ''
            if e.relative_path:
                error_object = '{} '.format(e.relative_path[0])
            raise exceptions.UnsupportedOptionError(
                user_fault_string='{0}{1}'.format(error_object, e.message),
                operator_fault_string=str(e))
        except Exception as e:
            raise exceptions.DriverError(
                user_fault_string='Failed to validate the flavor metadata '
                                  'due to: {}'.format(str(e)),
                operator_fault_string='Failed to validate the flavor metadata '
                                      'due to: {}'.format(str(e)))
        compute_flavor = flavor_dict.get(consts.COMPUTE_FLAVOR, None)
        if compute_flavor:
            compute_driver = stevedore_driver.DriverManager(
                namespace='octavia.compute.drivers',
                name=CONF.controller_worker.compute_driver,
                invoke_on_load=True
            ).driver

            # TODO(johnsom) Fix this to raise a NotFound error
            # when the octavia-lib supports it.
            compute_driver.validate_flavor(compute_flavor)

        amp_image_tag = flavor_dict.get(consts.AMP_IMAGE_TAG, None)
        if amp_image_tag:
            image_driver = stevedore_driver.DriverManager(
                namespace='octavia.image.drivers',
                name=CONF.controller_worker.image_driver,
                invoke_on_load=True
            ).driver

            try:
                image_driver.get_image_id_by_tag(
                    amp_image_tag, CONF.controller_worker.amp_image_owner_id)
            except Exception as e:
                raise exceptions.NotFound(
                    user_fault_string='Failed to find an image with tag {} '
                                      'due to: {}'.format(
                                          amp_image_tag, str(e)),
                    operator_fault_string='Failed to find an image with tag '
                                          '{} due to: {}'.format(
                                              amp_image_tag, str(e)))
Ejemplo n.º 5
0
 def _check_for_allowed_cidrs(self, allowed_cidrs):
     # TODO(haleyb): add support for this
     if isinstance(allowed_cidrs, o_datamodels.UnsetType):
         allowed_cidrs = []
     if allowed_cidrs:
         msg = _('OVN provider does not support allowed_cidrs option')
         raise driver_exceptions.UnsupportedOptionError(
             user_fault_string=msg,
             operator_fault_string=msg)
Ejemplo n.º 6
0
    def test_UnsupportedOptionError(self):
        unsupported_option_error = exceptions.UnsupportedOptionError(
            user_fault_string=self.user_fault_string,
            operator_fault_string=self.operator_fault_string)

        self.assertEqual(self.user_fault_string,
                         unsupported_option_error.user_fault_string)
        self.assertEqual(self.operator_fault_string,
                         unsupported_option_error.operator_fault_string)
        self.assertIsInstance(unsupported_option_error, Exception)
Ejemplo n.º 7
0
    def validate_availability_zone(self, availability_zone_dict):
        """Validates availability zone profile data.

        This will validate an availability zone profile dataset against the
        availability zone settings the amphora driver supports.

        :param availability_zone_dict: The availability zone dict to validate.
        :type availability_zone_dict: dict
        :return: None
        :raises DriverError: An unexpected error occurred.
        :raises UnsupportedOptionError: If the driver does not support
          one of the availability zone settings.
        """
        try:
            validate(
                availability_zone_dict,
                availability_zone_schema.SUPPORTED_AVAILABILITY_ZONE_SCHEMA)
        except js_exceptions.ValidationError as e:
            error_object = ''
            if e.relative_path:
                error_object = '{} '.format(e.relative_path[0])
            raise exceptions.UnsupportedOptionError(
                user_fault_string='{0}{1}'.format(error_object, e.message),
                operator_fault_string=str(e))
        except Exception as e:
            raise exceptions.DriverError(
                user_fault_string='Failed to validate the availability zone '
                                  'metadata due to: {}'.format(str(e)),
                operator_fault_string='Failed to validate the availability '
                                      'zone metadata due to: {}'.format(str(e))
            )
        compute_zone = availability_zone_dict.get(consts.COMPUTE_ZONE, None)
        if compute_zone:
            compute_driver = stevedore_driver.DriverManager(
                namespace='octavia.compute.drivers',
                name=CONF.controller_worker.compute_driver,
                invoke_on_load=True
            ).driver

            # TODO(johnsom) Fix this to raise a NotFound error
            # when the octavia-lib supports it.
            compute_driver.validate_availability_zone(compute_zone)

        check_nets = availability_zone_dict.get(
            consts.VALID_VIP_NETWORKS, [])
        management_net = availability_zone_dict.get(
            consts.MANAGEMENT_NETWORK, None)
        if management_net:
            check_nets.append(management_net)
        for check_net in check_nets:
            network_driver = utils.get_network_driver()

            # TODO(johnsom) Fix this to raise a NotFound error
            # when the octavia-lib supports it.
            network_driver.get_network(check_net)
Ejemplo n.º 8
0
 def _validate_alpn_protocols(self, listener):
     if not listener.alpn_protocols:
         return
     supported = consts.AMPHORA_SUPPORTED_ALPN_PROTOCOLS
     not_supported = set(listener.alpn_protocols) - set(supported)
     if not_supported:
         msg = ('Amphora provider does not support %s ALPN protocol(s). '
                'Supported: %s' %
                (", ".join(not_supported), ", ".join(supported)))
         raise exceptions.UnsupportedOptionError(user_fault_string=msg,
                                                 operator_fault_string=msg)
Ejemplo n.º 9
0
 def _validate_hm_support(self, hm, action='create'):
     if not self._is_health_check_supported():
         msg = _('OVN Load Balancer supports Health Check provider '
                 'from version 2.12. Upgrade OVN in order to use it.')
         raise driver_exceptions.UnsupportedOptionError(
             user_fault_string=msg,
             operator_fault_string=msg)
     # type is only required for create
     if action == 'create':
         if isinstance(hm.type, o_datamodels.UnsetType):
             msg = _('OVN provider health monitor type not specified.')
             # seems this should be other than "unsupported"?
             raise driver_exceptions.UnsupportedOptionError(
                 user_fault_string=msg,
                 operator_fault_string=msg)
         if hm.type not in ovn_const.SUPPORTED_HEALTH_MONITOR_TYPES:
             msg = (_('OVN provider does not support %s '
                      'health monitor type. Supported types: %s') %
                     (hm.type,
                      ', '.join(ovn_const.SUPPORTED_HEALTH_MONITOR_TYPES)))
             raise driver_exceptions.UnsupportedOptionError(
                 user_fault_string=msg,
                 operator_fault_string=msg)
Ejemplo n.º 10
0
    def _validate_members(self, db_pool, members):
        if db_pool.protocol == consts.PROTOCOL_UDP:
            # For UDP LBs, check that we are not mixing IPv4 and IPv6
            for member in members:
                member_is_ipv6 = utils.is_ipv6(member.address)

                for listener in db_pool.listeners:
                    lb = listener.load_balancer
                    vip_is_ipv6 = utils.is_ipv6(lb.vip.ip_address)

                    if member_is_ipv6 != vip_is_ipv6:
                        msg = ("This provider doesn't support mixing IPv4 and "
                               "IPv6 addresses for its VIP and members in UDP "
                               "load balancers.")
                        raise exceptions.UnsupportedOptionError(
                            user_fault_string=msg, operator_fault_string=msg)
Ejemplo n.º 11
0
    def member_create(self, member):
        # Validate monitoring options if present
        self._check_member_monitor_options(member)
        if self._ip_version_differs(member):
            raise ovn_exc.IPVersionsMixingNotSupportedError()
        admin_state_up = member.admin_state_up
        subnet_id = member.subnet_id
        if (isinstance(subnet_id, o_datamodels.UnsetType) or not subnet_id):
            subnet_id = self._ovn_helper._get_subnet_from_pool(member.pool_id)
            if not subnet_id:
                msg = _('Subnet is required, or Loadbalancer associated with '
                        'Pool must have a subnet, for Member creation '
                        'with OVN Provider Driver')
                raise driver_exceptions.UnsupportedOptionError(
                    user_fault_string=msg,
                    operator_fault_string=msg)

        if isinstance(admin_state_up, o_datamodels.UnsetType):
            admin_state_up = True
        request_info = {'id': member.member_id,
                        'address': member.address,
                        'protocol_port': member.protocol_port,
                        'pool_id': member.pool_id,
                        'subnet_id': subnet_id,
                        'admin_state_up': admin_state_up}
        request = {'type': ovn_const.REQ_TYPE_MEMBER_CREATE,
                   'info': request_info}
        self._ovn_helper.add_request(request)

        # NOTE(mjozefcz): If LB has FIP on VIP
        # and member has FIP we need to centralize
        # traffic for member.
        request_info = {'id': member.member_id,
                        'address': member.address,
                        'pool_id': member.pool_id,
                        'subnet_id': subnet_id,
                        'action': ovn_const.REQ_INFO_MEMBER_ADDED}
        request = {'type': ovn_const.REQ_TYPE_HANDLE_MEMBER_DVR,
                   'info': request_info}
        self._ovn_helper.add_request(request)
Ejemplo n.º 12
0
    def validate_flavor(self, flavor_dict):
        try:
            validate(flavor_dict, flavor_schema.SUPPORTED_FLAVOR_SCHEMA)

            # validate flavor for slb objects
            if 'virtual-server' in flavor_dict:
                flavor = flavor_dict['virtual-server']
                if 'name' in flavor:
                    raise Exception('axapi key \'name\' is not allowed')
                if 'ip-address' in flavor:
                    raise Exception(
                        'axapi key \'ip-address\' is not supported yet')
                self._validate_flavor_name_expressions(flavor)
            if 'virtual-port' in flavor_dict:
                flavor = flavor_dict['virtual-port']
                if 'name' in flavor:
                    raise Exception('axapi key \'name\' is not allowed')
                if 'port-number' in flavor:
                    raise Exception('axapi key \'port-number\' is not allowed')
                if 'protocol' in flavor:
                    raise Exception('axapi key \'protocol\' is not allowed')
                self._validate_flavor_name_expressions(flavor)
            if 'service-group' in flavor_dict:
                flavor = flavor_dict['service-group']
                if 'name' in flavor:
                    raise Exception('axapi key \'name\' is not allowed')
                self._validate_flavor_name_expressions(flavor)
            if 'server' in flavor_dict:
                flavor = flavor_dict['server']
                if 'name' in flavor:
                    raise Exception('axapi key \'name\' is not allowed')
                self._validate_flavor_name_expressions(flavor)
            if 'health-monitor' in flavor_dict:
                flavor = flavor_dict['health-monitor']
                if 'name' in flavor:
                    raise Exception('axapi key \'name\' is not allowed')
                self._validate_flavor_name_expressions(flavor)

            # validate nat-pool and nat-pool-list keys
            if 'nat-pool' in flavor_dict:
                nat = flavor_dict['nat-pool']
                if 'pool-name' not in nat:
                    raise Exception(
                        'pool-name is required for nat-pool flavor')
                if 'start-address' not in nat:
                    raise Exception(
                        'start-address is required for nat-pool flavor')
                if 'end-address' not in nat:
                    raise Exception(
                        'end-address is required for nat-pool flavor')
                if 'netmask' not in nat:
                    raise Exception('netmask is required for nat-pool flavor')
            if 'nat-pool-list' in flavor_dict:
                for nat in flavor_dict['nat-pool-list']:
                    if 'pool-name' not in nat:
                        raise Exception(
                            'pool-name is required for nat-pool-list flavor')
                    if 'start-address' not in nat:
                        raise Exception(
                            'start-address is required for nat-pool-list flavor'
                        )
                    if 'end-address' not in nat:
                        raise Exception(
                            'end-address is required for nat-pool-list flavor')
                    if 'netmask' not in nat:
                        raise Exception(
                            'netmask is required for nat-pool-list flavor')
            if 'deployment' in flavor_dict:
                deployment = flavor_dict['deployment']
                if ('dsr_type' in deployment and deployment['dsr_type']
                        not in ['l2dsr_transparent']):
                    raise Exception(
                        'l2dsr_transparent is required value for dsr_type')

        except js_exceptions.ValidationError as e:
            error_object = ''
            if e.relative_path:
                error_object = '{} '.format(e.relative_path[0])
            raise exceptions.UnsupportedOptionError(
                user_fault_string='{0}{1}'.format(error_object, e.message),
                operator_fault_string=str(e))
        except Exception as e:
            raise exceptions.DriverError(
                user_fault_string='Failed to validate the flavor metadata '
                'due to: {}'.format(str(e)),
                operator_fault_string='Failed to validate the flavor metadata '
                'due to: {}'.format(str(e)))
Ejemplo n.º 13
0
 def _check_for_supported_algorithms(self, algorithm):
     if algorithm not in ovn_const.OVN_NATIVE_LB_ALGORITHMS:
         msg = _('OVN provider does not support %s algorithm') % algorithm
         raise driver_exceptions.UnsupportedOptionError(
             user_fault_string=msg,
             operator_fault_string=msg)
Ejemplo n.º 14
0
 def _check_for_supported_protocols(self, protocol):
     if protocol not in ovn_const.OVN_NATIVE_LB_PROTOCOLS:
         msg = _('OVN provider does not support %s protocol') % protocol
         raise driver_exceptions.UnsupportedOptionError(
             user_fault_string=msg,
             operator_fault_string=msg)
Ejemplo n.º 15
0
    def member_batch_update(self, pool_id, members):
        request_list = []
        skipped_members = []
        pool_key, ovn_lb = self._ovn_helper._find_ovn_lb_by_pool_id(pool_id)
        external_ids = copy.deepcopy(ovn_lb.external_ids)
        pool = external_ids[pool_key]
        existing_members = pool.split(',') if pool else []
        members_to_delete = copy.copy(existing_members)
        pool_subnet_id = None
        for member in members:
            if (self._check_monitor_options(member) or
                    member.address and self._ip_version_differs(member)):
                skipped_members.append(member.member_id)
                continue
            # NOTE(froyo): if subnet_id not provided, lets try to get it
            # from the member pool_id
            subnet_id = member.subnet_id
            if (isinstance(subnet_id, o_datamodels.UnsetType) or
                    not subnet_id):
                pool_subnet_id = (
                    pool_subnet_id
                    if pool_subnet_id
                    else self._ovn_helper._get_subnet_from_pool(pool_id))
                # NOTE(mjozefcz): We need to have subnet_id information.
                if not pool_subnet_id:
                    msg = _('Subnet is required, or Loadbalancer associated '
                            'with Pool must have a subnet, for Member '
                            'creation with OVN Provider Driver')
                    raise driver_exceptions.UnsupportedOptionError(
                        user_fault_string=msg,
                        operator_fault_string=msg)
                member.subnet_id = pool_subnet_id
            admin_state_up = member.admin_state_up
            if isinstance(admin_state_up, o_datamodels.UnsetType):
                admin_state_up = True

            member_info = self._ovn_helper._get_member_info(member)
            if member_info not in existing_members:
                req_type = ovn_const.REQ_TYPE_MEMBER_CREATE
            else:
                # If member exists in pool, then Update
                req_type = ovn_const.REQ_TYPE_MEMBER_UPDATE
                # Remove all updating members so only deleted ones are left
                members_to_delete.remove(member_info)

            request_info = {'id': member.member_id,
                            'address': member.address,
                            'protocol_port': member.protocol_port,
                            'pool_id': member.pool_id,
                            'subnet_id': member.subnet_id,
                            'admin_state_up': admin_state_up}
            request = {'type': req_type,
                       'info': request_info}
            request_list.append(request)

        for member in members_to_delete:
            member_info = member.split('_')
            request_info = {'id': member_info[1],
                            'address': member_info[2].split(':')[0],
                            'protocol_port': member_info[2].split(':')[1],
                            'pool_id': pool_id}
            if len(member_info) == 4:
                request_info['subnet_id'] = member_info[3]
            request = {'type': ovn_const.REQ_TYPE_MEMBER_DELETE,
                       'info': request_info}
            request_list.append(request)

        for request in request_list:
            self._ovn_helper.add_request(request)
        if skipped_members:
            msg = (_('OVN provider does not support monitor options, '
                     'so following members skipped: %s') % skipped_members)
            raise driver_exceptions.UnsupportedOptionError(
                user_fault_string=msg,
                operator_fault_string=msg)
Ejemplo n.º 16
0
 def loadbalancer_failover(self, loadbalancer_id):
     msg = _('OVN provider does not support loadbalancer failover')
     raise driver_exceptions.UnsupportedOptionError(
         user_fault_string=msg,
         operator_fault_string=msg)