Esempio n. 1
0
    def delete(self, id):
        """Deletes a listener from a load balancer."""
        context = pecan.request.context.get('octavia_context')
        db_listener = self._get_db_listener(context.session, id,
                                            show_deleted=False)
        load_balancer_id = db_listener.load_balancer_id

        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_statuses(
                lock_session, load_balancer_id,
                id=id, listener_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Listener %s to provider %s", id,
                     driver.name)
            provider_listener = (
                driver_utils.db_listener_to_provider_listener(db_listener))
            driver_utils.call_provider(driver.name, driver.listener_delete,
                                       provider_listener)
Esempio n. 2
0
    def post(self, rule_):
        """Creates a l7rule on an l7policy."""
        l7rule = rule_.rule
        context = pecan_request.context.get('octavia_context')

        db_l7policy = self._get_db_l7policy(context.session, self.l7policy_id,
                                            show_deleted=False)
        load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
            db_l7policy)
        l7rule.project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)
        self._auth_validate_action(context, l7rule.project_id,
                                   constants.RBAC_POST)

        try:
            validate.l7rule_data(l7rule)
        except Exception as e:
            raise exceptions.L7RuleValidation(error=e)

        self._check_l7policy_max_rules(context.session)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(
                    context.session,
                    lock_session,
                    data_models.L7Rule,
                    l7rule.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.L7Rule._name())

            l7rule_dict = db_prepare.create_l7rule(
                l7rule.to_dict(render_unsets=True), self.l7policy_id)

            self._test_lb_listener_policy_statuses(context.session)

            db_l7rule = self._validate_create_l7rule(lock_session, l7rule_dict)

            # Prepare the data for the driver data model
            provider_l7rule = (
                driver_utils.db_l7rule_to_provider_l7rule(db_l7rule))

            # Dispatch to the driver
            LOG.info("Sending create L7 Rule %s to provider %s",
                     db_l7rule.id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.l7rule_create, provider_l7rule)

            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_l7rule = self._get_db_l7rule(context.session, db_l7rule.id)
        result = self._convert_db_to_type(db_l7rule,
                                          l7rule_types.L7RuleResponse)
        return l7rule_types.L7RuleRootResponse(rule=result)
Esempio n. 3
0
    def delete(self, id):
        """Deletes a health monitor."""
        context = pecan.request.context.get('octavia_context')
        db_hm = self._get_db_hm(context.session, id, show_deleted=False)

        pool = self._get_db_pool(context.session, db_hm.pool_id)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, project_id, consts.RBAC_DELETE)

        if db_hm.provisioning_status == consts.DELETED:
            return

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_and_pool_statuses(lock_session, db_hm)

            self.repositories.health_monitor.update(
                lock_session,
                db_hm.id,
                provisioning_status=consts.PENDING_DELETE)

            LOG.info("Sending delete Health Monitor %s to provider %s", id,
                     driver.name)
            provider_healthmon = driver_utils.db_HM_to_provider_HM(db_hm)
            driver_utils.call_provider(driver.name,
                                       driver.health_monitor_delete,
                                       provider_healthmon)
Esempio n. 4
0
    def post(self, flavor_profile_):
        """Creates a flavor Profile."""
        flavorprofile = flavor_profile_.flavorprofile
        context = pecan_request.context.get('octavia_context')
        self._auth_validate_action(context, context.project_id,
                                   constants.RBAC_POST)
        # Do a basic JSON validation on the metadata
        try:
            flavor_data_dict = jsonutils.loads(flavorprofile.flavor_data)
        except Exception as e:
            raise exceptions.InvalidOption(
                value=flavorprofile.flavor_data,
                option=constants.FLAVOR_DATA) from e

        # Validate that the provider driver supports the metadata
        driver = driver_factory.get_driver(flavorprofile.provider_name)
        driver_utils.call_provider(driver.name, driver.validate_flavor,
                                   flavor_data_dict)

        lock_session = db_api.get_session(autocommit=False)
        try:
            flavorprofile_dict = flavorprofile.to_dict(render_unsets=True)
            flavorprofile_dict['id'] = uuidutils.generate_uuid()
            db_flavor_profile = self.repositories.flavor_profile.create(
                lock_session, **flavorprofile_dict)
            lock_session.commit()
        except odb_exceptions.DBDuplicateEntry as e:
            lock_session.rollback()
            raise exceptions.IDAlreadyExists() from e
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()
        result = self._convert_db_to_type(
            db_flavor_profile, profile_types.FlavorProfileResponse)
        return profile_types.FlavorProfileRootResponse(flavorprofile=result)
Esempio n. 5
0
    def delete(self, id):
        """Deletes a l7policy."""
        context = pecan_request.context.get('octavia_context')
        db_l7policy = self._get_db_l7policy(context.session,
                                            id,
                                            show_deleted=False)
        load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
            db_l7policy)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        if db_l7policy.provisioning_status == constants.DELETED:
            return

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_statuses(lock_session,
                                                lb_id=load_balancer_id,
                                                listener_ids=[listener_id])
            self.repositories.l7policy.update(
                lock_session,
                db_l7policy.id,
                provisioning_status=constants.PENDING_DELETE)

            LOG.info("Sending delete L7 Policy %s to provider %s", id,
                     driver.name)
            provider_l7policy = driver_utils.db_l7policy_to_provider_l7policy(
                db_l7policy)
            driver_utils.call_provider(driver.name, driver.l7policy_delete,
                                       provider_l7policy)
Esempio n. 6
0
    def delete(self, id):
        """Deletes a pool from a load balancer."""
        context = pecan.request.context.get('octavia_context')
        db_pool = self._get_db_pool(context.session, id, show_deleted=False)
        if db_pool.l7policies:
            raise exceptions.PoolInUseByL7Policy(
                id=db_pool.id, l7policy_id=db_pool.l7policies[0].id)

        project_id, provider = self._get_lb_project_id_provider(
            context.session, db_pool.load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_statuses(
                lock_session, lb_id=db_pool.load_balancer_id,
                listener_ids=self._get_affected_listener_ids(db_pool))
            self.repositories.pool.update(
                lock_session, db_pool.id,
                provisioning_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Pool %s to provider %s", id, driver.name)
            provider_pool = (
                driver_utils.db_pool_to_provider_pool(db_pool))
            driver_utils.call_provider(driver.name, driver.pool_delete,
                                       provider_pool)
Esempio n. 7
0
    def _validate_and_return_az_dict(self, lock_session, driver, lb_dict):

        az_dict = {}
        if 'availability_zone' in lb_dict:
            try:
                az = self.repositories.availability_zone.get(
                    lock_session, name=lb_dict['availability_zone'])
                az_dict = (
                    self.repositories.availability_zone
                    .get_availability_zone_metadata_dict(lock_session, az.name)
                )
            except sa_exception.NoResultFound:
                raise exceptions.ValidationException(
                    detail=_("Invalid availability_zone."))

        # Make sure the driver will still accept the availability zone metadata
        if az_dict:
            try:
                driver_utils.call_provider(driver.name,
                                           driver.validate_availability_zone,
                                           az_dict)
            except NotImplementedError:
                raise exceptions.ProviderNotImplementedError(
                    prov=driver.name, user_msg="This provider does not support"
                                               " availability zones.")

        return az_dict
Esempio n. 8
0
    def delete(self, id):
        """Deletes a l7policy."""
        context = pecan.request.context.get('octavia_context')
        db_l7policy = self._get_db_l7policy(context.session, id,
                                            show_deleted=False)
        load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
            db_l7policy)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        if db_l7policy.provisioning_status == constants.DELETED:
            return

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_statuses(lock_session,
                                                lb_id=load_balancer_id,
                                                listener_ids=[listener_id])
            self.repositories.l7policy.update(
                lock_session, db_l7policy.id,
                provisioning_status=constants.PENDING_DELETE)

            LOG.info("Sending delete L7 Policy %s to provider %s",
                     id, driver.name)
            provider_l7policy = driver_utils.db_l7policy_to_provider_l7policy(
                db_l7policy)
            driver_utils.call_provider(driver.name, driver.l7policy_delete,
                                       provider_l7policy)
Esempio n. 9
0
    def delete(self, id, cascade=False):
        """Deletes a load balancer."""
        context = pecan_request.context.get('octavia_context')
        cascade = strutils.bool_from_string(cascade)
        db_lb = self._get_db_lb(context.session, id, show_deleted=False)

        self._auth_validate_action(context, db_lb.project_id,
                                   constants.RBAC_DELETE)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(db_lb.provider)

        with db_api.get_lock_session() as lock_session:
            if (db_lb.listeners or db_lb.pools) and not cascade:
                msg = _("Cannot delete Load Balancer %s - "
                        "it has children") % id
                LOG.warning(msg)
                raise exceptions.ValidationException(detail=msg)
            self._test_lb_status(lock_session, id,
                                 lb_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Load Balancer %s to provider %s",
                     id, driver.name)
            provider_loadbalancer = (
                driver_utils.db_loadbalancer_to_provider_loadbalancer(
                    db_lb, for_delete=True))
            driver_utils.call_provider(driver.name, driver.loadbalancer_delete,
                                       provider_loadbalancer, cascade)
Esempio n. 10
0
    def post(self, member_):
        """Creates a pool member on a pool."""
        member = member_.member
        context = pecan.request.context.get('octavia_context')

        validate.ip_not_reserved(member.address)

        # Validate member subnet
        if member.subnet_id and not validate.subnet_exists(member.subnet_id):
            raise exceptions.NotFound(resource='Subnet', id=member.subnet_id)
        pool = self.repositories.pool.get(context.session, id=self.pool_id)
        member.project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, member.project_id,
                                   constants.RBAC_POST)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_clusterquota_met(
                    lock_session, data_models.Member,
                    base_res_id=self.pool_id):
                raise exceptions.ClusterQuotaException(
                    resource=data_models.Member._name())
            if self.repositories.check_quota_met(context.session, lock_session,
                                                 data_models.Member,
                                                 member.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.Member._name())

            member_dict = db_prepare.create_member(
                member.to_dict(render_unsets=True), self.pool_id,
                bool(pool.health_monitor))

            self._test_lb_and_listener_and_pool_statuses(lock_session)

            db_member = self._validate_create_member(lock_session, member_dict)

            # Prepare the data for the driver data model
            provider_member = (
                driver_utils.db_member_to_provider_member(db_member))

            # Dispatch to the driver
            LOG.info("Sending create Member %s to provider %s", db_member.id,
                     driver.name)
            driver_utils.call_provider(driver.name, driver.member_create,
                                       provider_member)

            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_member = self._get_db_member(context.session, db_member.id)
        result = self._convert_db_to_type(db_member,
                                          member_types.MemberResponse)
        return member_types.MemberRootResponse(member=result)
Esempio n. 11
0
    def delete(self, id):
        """Deletes a pool member."""
        context = pecan.request.context.get('octavia_context')
        db_member = self._get_db_member(context.session,
                                        id,
                                        show_deleted=False)

        pool = self.repositories.pool.get(context.session,
                                          id=db_member.pool_id)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_and_pool_statuses(lock_session,
                                                         member=db_member)
            self.repositories.member.update(
                lock_session,
                db_member.id,
                provisioning_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Member %s to provider %s", id,
                     driver.name)
            provider_member = (
                driver_utils.db_member_to_provider_member(db_member))
            driver_utils.call_provider(driver.name, driver.member_delete,
                                       provider_member)
Esempio n. 12
0
    def put(self, id, listener_):
        """Updates a listener on a load balancer."""
        listener = listener_.listener
        context = pecan_request.context.get('octavia_context')
        db_listener = self._get_db_listener(context.session,
                                            id,
                                            show_deleted=False)
        load_balancer_id = db_listener.load_balancer_id

        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        self._validate_listener_PUT(listener, db_listener)

        self._set_default_on_none(listener)

        if listener.default_pool_id:
            self._validate_pool(context.session, load_balancer_id,
                                listener.default_pool_id, db_listener.protocol)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_statuses(lock_session,
                                                load_balancer_id,
                                                id=id)

            # Prepare the data for the driver data model
            listener_dict = listener.to_dict(render_unsets=False)
            listener_dict['id'] = id

            provider_listener_dict = (
                driver_utils.listener_dict_to_provider_dict(listener_dict))

            # Also prepare the baseline object data
            old_provider_listener = (
                driver_utils.db_listener_to_provider_listener(db_listener,
                                                              for_delete=True))

            # Dispatch to the driver
            LOG.info("Sending update Listener %s to provider %s", id,
                     driver.name)
            driver_utils.call_provider(
                driver.name, driver.listener_update, old_provider_listener,
                driver_dm.Listener.from_dict(provider_listener_dict))

            # Update the database to reflect what the driver just accepted
            self.repositories.listener.update(
                lock_session, id, **listener.to_dict(render_unsets=False))

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_listener = self._get_db_listener(context.session, id)
        result = self._convert_db_to_type(db_listener,
                                          listener_types.ListenerResponse)
        return listener_types.ListenerRootResponse(listener=result)
Esempio n. 13
0
    def delete(self, id):
        """Deletes a pool from a load balancer."""
        context = pecan.request.context.get('octavia_context')
        db_pool = self._get_db_pool(context.session, id, show_deleted=False)
        if db_pool.l7policies:
            raise exceptions.PoolInUseByL7Policy(
                id=db_pool.id, l7policy_id=db_pool.l7policies[0].id)

        project_id, provider = self._get_lb_project_id_provider(
            context.session, db_pool.load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_statuses(
                lock_session,
                lb_id=db_pool.load_balancer_id,
                listener_ids=self._get_affected_listener_ids(db_pool))
            self.repositories.pool.update(
                lock_session,
                db_pool.id,
                provisioning_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Pool %s to provider %s", id, driver.name)
            driver_utils.call_provider(driver.name, driver.pool_delete, id)
Esempio n. 14
0
    def _apply_flavor_to_lb_dict(self, lock_session, driver, lb_dict):

        flavor_dict = {}
        if 'flavor_id' in lb_dict:
            try:
                flavor_dict = (
                    self.repositories.flavor.get_flavor_metadata_dict(
                        lock_session, lb_dict['flavor_id']))
            except sa_exception.NoResultFound:
                raise exceptions.ValidationException(
                    detail=_("Invalid flavor_id."))

        # Make sure the driver will still accept the flavor metadata
        if flavor_dict:
            driver_utils.call_provider(driver.name, driver.validate_flavor,
                                       flavor_dict)

        # Apply the flavor settings to the load balanacer
        # Use the configuration file settings as defaults
        lb_dict[constants.TOPOLOGY] = flavor_dict.get(
            constants.LOADBALANCER_TOPOLOGY,
            CONF.controller_worker.loadbalancer_topology)

        lb_dict[constants.DISTRIBUTOR_ID] = flavor_dict.get(
            constants.DISTRIBUTOR)

        return flavor_dict
Esempio n. 15
0
    def delete(self, id, cascade=False):
        """Deletes a load balancer."""
        context = pecan.request.context.get('octavia_context')
        cascade = strutils.bool_from_string(cascade)
        db_lb = self._get_db_lb(context.session, id, show_deleted=False)

        self._auth_validate_action(context, db_lb.project_id,
                                   constants.RBAC_DELETE)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(db_lb.provider)

        with db_api.get_lock_session() as lock_session:
            if (db_lb.listeners or db_lb.pools) and not cascade:
                msg = _("Cannot delete Load Balancer %s - "
                        "it has children") % id
                LOG.warning(msg)
                raise exceptions.ValidationException(detail=msg)
            self._test_lb_status(lock_session, id,
                                 lb_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Load Balancer %s to provider %s",
                     id, driver.name)
            provider_loadbalancer = (
                driver_utils.db_loadbalancer_to_provider_loadbalancer(db_lb))
            driver_utils.call_provider(driver.name, driver.loadbalancer_delete,
                                       provider_loadbalancer, cascade)
Esempio n. 16
0
    def post(self, flavor_profile_):
        """Creates a flavor Profile."""
        flavorprofile = flavor_profile_.flavorprofile
        context = pecan.request.context.get('octavia_context')
        self._auth_validate_action(context, context.project_id,
                                   constants.RBAC_POST)
        # Do a basic JSON validation on the metadata
        try:
            flavor_data_dict = jsonutils.loads(flavorprofile.flavor_data)
        except Exception:
            raise exceptions.InvalidOption(
                value=flavorprofile.flavor_data,
                option=constants.FLAVOR_DATA)

        # Validate that the provider driver supports the metadata
        driver = driver_factory.get_driver(flavorprofile.provider_name)
        driver_utils.call_provider(driver.name, driver.validate_flavor,
                                   flavor_data_dict)

        lock_session = db_api.get_session(autocommit=False)
        try:
            flavorprofile_dict = flavorprofile.to_dict(render_unsets=True)
            flavorprofile_dict['id'] = uuidutils.generate_uuid()
            db_flavor_profile = self.repositories.flavor_profile.create(
                lock_session, **flavorprofile_dict)
            lock_session.commit()
        except odb_exceptions.DBDuplicateEntry:
            lock_session.rollback()
            raise exceptions.IDAlreadyExists()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()
        result = self._convert_db_to_type(
            db_flavor_profile, profile_types.FlavorProfileResponse)
        return profile_types.FlavorProfileRootResponse(flavorprofile=result)
Esempio n. 17
0
    def test_call_provider(self):
        mock_driver_method = mock.MagicMock()

        # Test happy path
        utils.call_provider("provider_name",
                            mock_driver_method,
                            "arg1",
                            foo="arg2")
        mock_driver_method.assert_called_with("arg1", foo="arg2")

        # Test driver raising DriverError
        mock_driver_method.side_effect = driver_exceptions.DriverError
        self.assertRaises(exceptions.ProviderDriverError, utils.call_provider,
                          "provider_name", mock_driver_method)

        # Test driver raising NotImplementedError
        mock_driver_method.side_effect = driver_exceptions.NotImplementedError
        self.assertRaises(exceptions.ProviderNotImplementedError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)

        # Test driver raising UnsupportedOptionError
        mock_driver_method.side_effect = (
            driver_exceptions.UnsupportedOptionError)
        self.assertRaises(exceptions.ProviderUnsupportedOptionError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)

        # Test driver raising DriverError
        mock_driver_method.side_effect = Exception
        self.assertRaises(exceptions.ProviderDriverError, utils.call_provider,
                          "provider_name", mock_driver_method)
Esempio n. 18
0
    def put(self, id, l7policy_):
        """Updates a l7policy."""
        l7policy = l7policy_.l7policy
        l7policy_dict = validate.sanitize_l7policy_api_args(
            l7policy.to_dict(render_unsets=False))
        # Reset renamed attributes
        for attr, val in l7policy_types.L7PolicyPUT._type_to_model_map.items():
            if val in l7policy_dict:
                l7policy_dict[attr] = l7policy_dict.pop(val)
        sanitized_l7policy = l7policy_types.L7PolicyPUT(**l7policy_dict)
        context = pecan.request.context.get('octavia_context')
        # Make sure any specified redirect_pool_id exists
        if l7policy_dict.get('redirect_pool_id'):
            self._get_db_pool(context.session,
                              l7policy_dict['redirect_pool_id'])
        db_l7policy = self._get_db_l7policy(context.session,
                                            id,
                                            show_deleted=False)
        load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
            db_l7policy)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_statuses(lock_session,
                                                lb_id=load_balancer_id,
                                                listener_ids=[listener_id])

            # Prepare the data for the driver data model
            l7policy_dict = sanitized_l7policy.to_dict(render_unsets=False)
            l7policy_dict['id'] = id
            provider_l7policy_dict = (
                driver_utils.l7policy_dict_to_provider_dict(l7policy_dict))

            # Dispatch to the driver
            LOG.info("Sending update L7 Policy %s to provider %s", id,
                     driver.name)
            driver_utils.call_provider(
                driver.name, driver.l7policy_update,
                driver_dm.L7Policy.from_dict(provider_l7policy_dict))

            # Update the database to reflect what the driver just accepted
            sanitized_l7policy.provisioning_status = constants.PENDING_UPDATE
            db_l7policy_dict = sanitized_l7policy.to_dict(render_unsets=False)
            self.repositories.l7policy.update(lock_session, id,
                                              **db_l7policy_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_l7policy = self._get_db_l7policy(context.session, id)
        result = self._convert_db_to_type(db_l7policy,
                                          l7policy_types.L7PolicyResponse)
        return l7policy_types.L7PolicyRootResponse(l7policy=result)
Esempio n. 19
0
    def put(self, id, pool_):
        """Updates a pool on a load balancer."""
        pool = pool_.pool
        context = pecan_request.context.get('octavia_context')
        db_pool = self._get_db_pool(context.session, id, show_deleted=False)

        project_id, provider = self._get_lb_project_id_provider(
            context.session, db_pool.load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        if pool.tls_versions is None:
            pool.tls_versions = CONF.api_settings.default_pool_tls_versions
        if pool.tls_ciphers is None:
            pool.tls_ciphers = CONF.api_settings.default_pool_ciphers

        if (pool.session_persistence and not pool.session_persistence.type
                and db_pool.session_persistence
                and db_pool.session_persistence.type):
            pool.session_persistence.type = db_pool.session_persistence.type

        self._validate_pool_PUT(pool, db_pool)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_statuses(
                context.session,
                lb_id=db_pool.load_balancer_id,
                listener_ids=self._get_affected_listener_ids(db_pool))

            # Prepare the data for the driver data model
            pool_dict = pool.to_dict(render_unsets=False)
            pool_dict['id'] = id
            provider_pool_dict = (
                driver_utils.pool_dict_to_provider_dict(pool_dict))

            # Also prepare the baseline object data
            old_provider_pool = driver_utils.db_pool_to_provider_pool(
                db_pool, for_delete=True)

            # Dispatch to the driver
            LOG.info("Sending update Pool %s to provider %s", id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.pool_update, old_provider_pool,
                driver_dm.Pool.from_dict(provider_pool_dict))

            # Update the database to reflect what the driver just accepted
            pool.provisioning_status = constants.PENDING_UPDATE
            db_pool_dict = pool.to_dict(render_unsets=False)
            self.repositories.update_pool_and_sp(lock_session, id,
                                                 db_pool_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_pool = self._get_db_pool(context.session, id)
        result = self._convert_db_to_type(db_pool, pool_types.PoolResponse)
        return pool_types.PoolRootResponse(pool=result)
Esempio n. 20
0
    def post(self, listener_):
        """Creates a listener on a load balancer."""
        listener = listener_.listener
        context = pecan.request.context.get('octavia_context')

        load_balancer_id = listener.loadbalancer_id
        listener.project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, listener.project_id,
                                   constants.RBAC_POST)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(context.session, lock_session,
                                                 data_models.Listener,
                                                 listener.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.Listener._name())

            listener_dict = db_prepare.create_listener(
                listener.to_dict(render_unsets=True), None)

            if listener_dict['default_pool_id']:
                self._validate_pool(context.session, load_balancer_id,
                                    listener_dict['default_pool_id'],
                                    listener.protocol)

            self._test_lb_and_listener_statuses(lock_session,
                                                lb_id=load_balancer_id)

            db_listener = self._validate_create_listener(
                lock_session, listener_dict)

            # Prepare the data for the driver data model
            provider_listener = (
                driver_utils.db_listener_to_provider_listener(db_listener))

            # re-inject the sni container references lost due to SNI
            # being a separate table in the DB
            provider_listener.sni_container_refs = listener.sni_container_refs

            # Dispatch to the driver
            LOG.info("Sending create Listener %s to provider %s",
                     db_listener.id, driver.name)
            driver_utils.call_provider(driver.name, driver.listener_create,
                                       provider_listener)

            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_listener = self._get_db_listener(context.session, db_listener.id)
        result = self._convert_db_to_type(db_listener,
                                          listener_types.ListenerResponse)
        return listener_types.ListenerRootResponse(listener=result)
Esempio n. 21
0
    def delete(self, id):
        """Deletes a pool member."""
        context = pecan.request.context.get('octavia_context')
        db_member = self._get_db_member(context.session, id,
                                        show_deleted=False)

        pool = self.repositories.pool.get(context.session,
                                          id=db_member.pool_id)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        self._validate_pool_id(id, db_member.pool_id)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_and_pool_statuses(lock_session,
                                                         member=db_member)
            self.repositories.member.update(
                lock_session, db_member.id,
                provisioning_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Member %s to provider %s", id,
                     driver.name)
            provider_member = (
                driver_utils.db_member_to_provider_member(db_member))
            driver_utils.call_provider(driver.name, driver.member_delete,
                                       provider_member)
Esempio n. 22
0
    def delete(self, id):
        """Deletes a listener from a load balancer."""
        context = pecan.request.context.get('octavia_context')
        db_listener = self._get_db_listener(context.session,
                                            id,
                                            show_deleted=False)
        load_balancer_id = db_listener.load_balancer_id

        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_statuses(
                lock_session,
                load_balancer_id,
                id=id,
                listener_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Listener %s to provider %s", id,
                     driver.name)
            provider_listener = (
                driver_utils.db_listener_to_provider_listener(db_listener))
            driver_utils.call_provider(driver.name, driver.listener_delete,
                                       provider_listener)
Esempio n. 23
0
    def post(self, health_monitor_):
        """Creates a health monitor on a pool."""
        context = pecan.request.context.get('octavia_context')
        health_monitor = health_monitor_.healthmonitor

        if (not CONF.api_settings.allow_ping_health_monitors
                and health_monitor.type == consts.HEALTH_MONITOR_PING):
            raise exceptions.DisabledOption(option='type',
                                            value=consts.HEALTH_MONITOR_PING)

        pool = self._get_db_pool(context.session, health_monitor.pool_id)

        health_monitor.project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, health_monitor.project_id,
                                   consts.RBAC_POST)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(context.session, lock_session,
                                                 data_models.HealthMonitor,
                                                 health_monitor.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.HealthMonitor._name())

            hm_dict = db_prepare.create_health_monitor(
                health_monitor.to_dict(render_unsets=True))

            self._test_lb_and_listener_and_pool_statuses(
                lock_session, health_monitor)
            db_hm = self._validate_create_hm(lock_session, hm_dict)

            # Prepare the data for the driver data model
            provider_healthmon = (driver_utils.db_HM_to_provider_HM(db_hm))

            # Dispatch to the driver
            LOG.info("Sending create Health Monitor %s to provider %s",
                     db_hm.id, driver.name)
            driver_utils.call_provider(driver.name,
                                       driver.health_monitor_create,
                                       provider_healthmon)

            lock_session.commit()
        except odb_exceptions.DBError:
            lock_session.rollback()
            raise exceptions.InvalidOption(value=hm_dict.get('type'),
                                           option='type')
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_hm = self._get_db_hm(context.session, db_hm.id)
        result = self._convert_db_to_type(db_hm,
                                          hm_types.HealthMonitorResponse)
        return hm_types.HealthMonitorRootResponse(healthmonitor=result)
Esempio n. 24
0
    def put(self, id, health_monitor_):
        """Updates a health monitor."""
        context = pecan_request.context.get('octavia_context')
        health_monitor = health_monitor_.healthmonitor
        db_hm = self._get_db_hm(context.session, id, show_deleted=False)

        pool = self._get_db_pool(context.session, db_hm.pool_id)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, project_id, consts.RBAC_PUT)

        self._validate_update_hm(db_hm, health_monitor)
        # Validate health monitor update options for UDP/SCTP
        if pool.protocol in (lib_consts.PROTOCOL_UDP,
                             lib_consts.PROTOCOL_SCTP):
            health_monitor.type = db_hm.type
            self._validate_healthmonitor_request_for_udp_sctp(
                health_monitor, pool.protocol)

        self._set_default_on_none(health_monitor)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_and_pool_statuses(lock_session, db_hm)

            # Prepare the data for the driver data model
            healthmon_dict = health_monitor.to_dict(render_unsets=False)
            healthmon_dict['id'] = id
            provider_healthmon_dict = (
                driver_utils.hm_dict_to_provider_dict(healthmon_dict))

            # Also prepare the baseline object data
            old_provider_healthmon = driver_utils.db_HM_to_provider_HM(db_hm)

            # Dispatch to the driver
            LOG.info("Sending update Health Monitor %s to provider %s", id,
                     driver.name)
            driver_utils.call_provider(
                driver.name, driver.health_monitor_update,
                old_provider_healthmon,
                driver_dm.HealthMonitor.from_dict(provider_healthmon_dict))

            # Update the database to reflect what the driver just accepted
            health_monitor.provisioning_status = consts.PENDING_UPDATE
            db_hm_dict = health_monitor.to_dict(render_unsets=False)
            self.repositories.health_monitor.update(lock_session, id,
                                                    **db_hm_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_hm = self._get_db_hm(context.session, id)
        result = self._convert_db_to_type(db_hm,
                                          hm_types.HealthMonitorResponse)
        return hm_types.HealthMonitorRootResponse(healthmonitor=result)
Esempio n. 25
0
    def post(self, l7policy_):
        """Creates a l7policy on a listener."""
        l7policy = l7policy_.l7policy
        context = pecan.request.context.get('octavia_context')
        # Make sure any pool specified by redirect_pool_id exists
        if l7policy.redirect_pool_id:
            db_pool = self._get_db_pool(context.session,
                                        l7policy.redirect_pool_id)
            self._escape_l7policy_udp_pool_request(db_pool)
        # Verify the parent listener exists
        listener_id = l7policy.listener_id
        listener = self._get_db_listener(context.session, listener_id)
        load_balancer_id = listener.load_balancer_id
        l7policy.project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, l7policy.project_id,
                                   constants.RBAC_POST)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(context.session, lock_session,
                                                 data_models.L7Policy,
                                                 l7policy.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.L7Policy._name())

            l7policy_dict = db_prepare.create_l7policy(
                l7policy.to_dict(render_unsets=True), load_balancer_id,
                listener_id)

            self._test_lb_and_listener_statuses(lock_session,
                                                lb_id=load_balancer_id,
                                                listener_ids=[listener_id])
            db_l7policy = self._validate_create_l7policy(
                lock_session, l7policy_dict)

            # Prepare the data for the driver data model
            provider_l7policy = (
                driver_utils.db_l7policy_to_provider_l7policy(db_l7policy))

            # Dispatch to the driver
            LOG.info("Sending create L7 Policy %s to provider %s",
                     db_l7policy.id, driver.name)
            driver_utils.call_provider(driver.name, driver.l7policy_create,
                                       provider_l7policy)

            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_l7policy = self._get_db_l7policy(context.session, db_l7policy.id)
        result = self._convert_db_to_type(db_l7policy,
                                          l7policy_types.L7PolicyResponse)
        return l7policy_types.L7PolicyRootResponse(l7policy=result)
Esempio n. 26
0
    def put(self, id, l7rule_):
        """Updates a l7rule."""
        l7rule = l7rule_.rule
        context = pecan.request.context.get('octavia_context')
        db_l7rule = self._get_db_l7rule(context.session,
                                        id,
                                        show_deleted=False)
        new_l7rule = db_l7rule.to_dict()
        new_l7rule.update(l7rule.to_dict())
        new_l7rule = data_models.L7Rule.from_dict(new_l7rule)

        db_l7policy = self._get_db_l7policy(context.session,
                                            self.l7policy_id,
                                            show_deleted=False)
        load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
            db_l7policy)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        try:
            validate.l7rule_data(new_l7rule)
        except Exception as e:
            raise exceptions.L7RuleValidation(error=e)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_listener_policy_statuses(lock_session)

            # Prepare the data for the driver data model
            l7rule_dict = l7rule.to_dict(render_unsets=False)
            l7rule_dict['id'] = id
            provider_l7rule_dict = (
                driver_utils.l7rule_dict_to_provider_dict(l7rule_dict))

            # Dispatch to the driver
            LOG.info("Sending update L7 Rule %s to provider %s", id,
                     driver.name)
            driver_utils.call_provider(
                driver.name, driver.l7rule_update,
                driver_dm.L7Rule.from_dict(provider_l7rule_dict))

            # Update the database to reflect what the driver just accepted
            l7rule.provisioning_status = constants.PENDING_UPDATE
            db_l7rule_dict = l7rule.to_dict(render_unsets=False)
            self.repositories.l7rule.update(lock_session, id, **db_l7rule_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_l7rule = self._get_db_l7rule(context.session, id)
        result = self._convert_db_to_type(db_l7rule,
                                          l7rule_types.L7RuleResponse)
        return l7rule_types.L7RuleRootResponse(rule=result)
Esempio n. 27
0
    def put(self, id, listener_):
        """Updates a listener on a load balancer."""
        listener = listener_.listener
        context = pecan.request.context.get('octavia_context')
        db_listener = self._get_db_listener(context.session, id,
                                            show_deleted=False)
        load_balancer_id = db_listener.load_balancer_id

        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        self._validate_listener_PUT(listener, db_listener)

        self._set_default_on_none(listener)

        if listener.default_pool_id:
            self._validate_pool(context.session, load_balancer_id,
                                listener.default_pool_id, db_listener.protocol)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_statuses(lock_session,
                                                load_balancer_id, id=id)

            # Prepare the data for the driver data model
            listener_dict = listener.to_dict(render_unsets=False)
            listener_dict['id'] = id
            provider_listener_dict = (
                driver_utils.listener_dict_to_provider_dict(listener_dict))

            # Also prepare the baseline object data
            old_provider_llistener = (
                driver_utils.db_listener_to_provider_listener(db_listener))

            # Dispatch to the driver
            LOG.info("Sending update Listener %s to provider %s", id,
                     driver.name)
            driver_utils.call_provider(
                driver.name, driver.listener_update,
                old_provider_llistener,
                driver_dm.Listener.from_dict(provider_listener_dict))

            # Update the database to reflect what the driver just accepted
            self.repositories.listener.update(
                lock_session, id, **listener.to_dict(render_unsets=False))

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_listener = self._get_db_listener(context.session, id)
        result = self._convert_db_to_type(db_listener,
                                          listener_types.ListenerResponse)
        return listener_types.ListenerRootResponse(listener=result)
Esempio n. 28
0
    def put(self, id, load_balancer):
        """Updates a load balancer."""
        load_balancer = load_balancer.loadbalancer
        context = pecan_request.context.get('octavia_context')
        db_lb = self._get_db_lb(context.session, id, show_deleted=False)

        self._auth_validate_action(context, db_lb.project_id,
                                   constants.RBAC_PUT)

        if not isinstance(load_balancer.vip_qos_policy_id, wtypes.UnsetType):
            network_driver = utils.get_network_driver()
            validate.qos_extension_enabled(network_driver)
            if load_balancer.vip_qos_policy_id is not None:
                if db_lb.vip.qos_policy_id != load_balancer.vip_qos_policy_id:
                    validate.qos_policy_exists(load_balancer.vip_qos_policy_id)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(db_lb.provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_status(lock_session, id)

            # Prepare the data for the driver data model
            lb_dict = load_balancer.to_dict(render_unsets=False)
            lb_dict['id'] = id
            vip_dict = lb_dict.pop('vip', {})
            lb_dict = driver_utils.lb_dict_to_provider_dict(lb_dict)
            if 'qos_policy_id' in vip_dict:
                lb_dict['vip_qos_policy_id'] = vip_dict['qos_policy_id']

            # Also prepare the baseline object data
            old_provider_lb = (
                driver_utils.db_loadbalancer_to_provider_loadbalancer(
                    db_lb, for_delete=True))

            # Dispatch to the driver
            LOG.info("Sending update Load Balancer %s to provider "
                     "%s", id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.loadbalancer_update,
                old_provider_lb,
                driver_dm.LoadBalancer.from_dict(lb_dict))

            db_lb_dict = load_balancer.to_dict(render_unsets=False)
            if 'vip' in db_lb_dict:
                db_vip_dict = db_lb_dict.pop('vip')
                self.repositories.vip.update(lock_session, id, **db_vip_dict)
            if db_lb_dict:
                self.repositories.load_balancer.update(lock_session, id,
                                                       **db_lb_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_lb = self._get_db_lb(context.session, id)
        result = self._convert_db_to_type(db_lb, lb_types.LoadBalancerResponse)
        return lb_types.LoadBalancerRootResponse(loadbalancer=result)
Esempio n. 29
0
    def post(self, member_):
        """Creates a pool member on a pool."""
        member = member_.member
        context = pecan.request.context.get('octavia_context')

        validate.ip_not_reserved(member.address)

        # Validate member subnet
        if member.subnet_id and not validate.subnet_exists(member.subnet_id):
            raise exceptions.NotFound(resource='Subnet',
                                      id=member.subnet_id)
        pool = self.repositories.pool.get(context.session, id=self.pool_id)
        member.project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, member.project_id,
                                   constants.RBAC_POST)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(
                    context.session,
                    lock_session,
                    data_models.Member,
                    member.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.Member._name())

            member_dict = db_prepare.create_member(member.to_dict(
                render_unsets=True), self.pool_id, bool(pool.health_monitor))

            self._test_lb_and_listener_and_pool_statuses(lock_session)

            db_member = self._validate_create_member(lock_session, member_dict)

            # Prepare the data for the driver data model
            provider_member = (
                driver_utils.db_member_to_provider_member(db_member))

            # Dispatch to the driver
            LOG.info("Sending create Member %s to provider %s",
                     db_member.id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.member_create, provider_member)

            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_member = self._get_db_member(context.session, db_member.id)
        result = self._convert_db_to_type(db_member,
                                          member_types.MemberResponse)
        return member_types.MemberRootResponse(member=result)
Esempio n. 30
0
    def put(self, id, pool_):
        """Updates a pool on a load balancer."""
        pool = pool_.pool
        context = pecan.request.context.get('octavia_context')
        db_pool = self._get_db_pool(context.session, id, show_deleted=False)

        project_id, provider = self._get_lb_project_id_provider(
            context.session, db_pool.load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        if (pool.session_persistence and
                not pool.session_persistence.type and
                db_pool.session_persistence and
                db_pool.session_persistence.type):
            pool.session_persistence.type = db_pool.session_persistence.type

        self._validate_pool_PUT(pool, db_pool)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_statuses(
                context.session, lb_id=db_pool.load_balancer_id,
                listener_ids=self._get_affected_listener_ids(db_pool))

            # Prepare the data for the driver data model
            pool_dict = pool.to_dict(render_unsets=False)
            pool_dict['id'] = id
            provider_pool_dict = (
                driver_utils.pool_dict_to_provider_dict(pool_dict))

            # Also prepare the baseline object data
            old_provider_pool = driver_utils.db_pool_to_provider_pool(
                db_pool)

            # Dispatch to the driver
            LOG.info("Sending update Pool %s to provider %s", id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.pool_update,
                old_provider_pool,
                driver_dm.Pool.from_dict(provider_pool_dict))

            # Update the database to reflect what the driver just accepted
            pool.provisioning_status = constants.PENDING_UPDATE
            db_pool_dict = pool.to_dict(render_unsets=False)
            self.repositories.update_pool_and_sp(lock_session, id,
                                                 db_pool_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_pool = self._get_db_pool(context.session, id)
        result = self._convert_db_to_type(db_pool, pool_types.PoolResponse)
        return pool_types.PoolRootResponse(pool=result)
Esempio n. 31
0
    def put(self, id, load_balancer):
        """Updates a load balancer."""
        load_balancer = load_balancer.loadbalancer
        context = pecan.request.context.get('octavia_context')
        db_lb = self._get_db_lb(context.session, id, show_deleted=False)

        self._auth_validate_action(context, db_lb.project_id,
                                   constants.RBAC_PUT)

        if not isinstance(load_balancer.vip_qos_policy_id, wtypes.UnsetType):
            network_driver = utils.get_network_driver()
            validate.qos_extension_enabled(network_driver)
            if load_balancer.vip_qos_policy_id is not None:
                if db_lb.vip.qos_policy_id != load_balancer.vip_qos_policy_id:
                    validate.qos_policy_exists(load_balancer.vip_qos_policy_id)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(db_lb.provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_status(lock_session, id)

            # Prepare the data for the driver data model
            lb_dict = load_balancer.to_dict(render_unsets=False)
            lb_dict['id'] = id
            vip_dict = lb_dict.pop('vip', {})
            lb_dict = driver_utils.lb_dict_to_provider_dict(lb_dict)
            if 'qos_policy_id' in vip_dict:
                lb_dict['vip_qos_policy_id'] = vip_dict['qos_policy_id']

            # Also prepare the baseline object data
            old_provider_lb = (
                driver_utils.db_loadbalancer_to_provider_loadbalancer(db_lb))

            # Dispatch to the driver
            LOG.info("Sending update Load Balancer %s to provider "
                     "%s", id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.loadbalancer_update,
                old_provider_lb,
                driver_dm.LoadBalancer.from_dict(lb_dict))

            db_lb_dict = load_balancer.to_dict(render_unsets=False)
            if 'vip' in db_lb_dict:
                db_vip_dict = db_lb_dict.pop('vip')
                self.repositories.vip.update(lock_session, id, **db_vip_dict)
            if db_lb_dict:
                self.repositories.load_balancer.update(lock_session, id,
                                                       **db_lb_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_lb = self._get_db_lb(context.session, id)
        result = self._convert_db_to_type(db_lb, lb_types.LoadBalancerResponse)
        return lb_types.LoadBalancerRootResponse(loadbalancer=result)
Esempio n. 32
0
    def put(self, id, member_):
        """Updates a pool member."""
        member = member_.member
        context = pecan_request.context.get('octavia_context')
        db_member = self._get_db_member(context.session, id,
                                        show_deleted=False)

        pool = self.repositories.pool.get(context.session,
                                          id=db_member.pool_id)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        self._validate_pool_id(id, db_member.pool_id)

        self._set_default_on_none(member)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_and_pool_statuses(lock_session,
                                                         member=db_member)

            # Prepare the data for the driver data model
            member_dict = member.to_dict(render_unsets=False)
            member_dict['id'] = id
            provider_member_dict = (
                driver_utils.member_dict_to_provider_dict(member_dict))

            # Also prepare the baseline object data
            old_provider_member = driver_utils.db_member_to_provider_member(
                db_member)

            # Dispatch to the driver
            LOG.info("Sending update Member %s to provider %s", id,
                     driver.name)
            driver_utils.call_provider(
                driver.name, driver.member_update,
                old_provider_member,
                driver_dm.Member.from_dict(provider_member_dict))

            # Update the database to reflect what the driver just accepted
            member.provisioning_status = constants.PENDING_UPDATE
            db_member_dict = member.to_dict(render_unsets=False)
            self.repositories.member.update(lock_session, id, **db_member_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_member = self._get_db_member(context.session, id)
        result = self._convert_db_to_type(db_member,
                                          member_types.MemberResponse)
        return member_types.MemberRootResponse(member=result)
Esempio n. 33
0
    def put(self, id, flavor_profile_):
        """Updates a flavor Profile."""
        flavorprofile = flavor_profile_.flavorprofile
        context = pecan.request.context.get('octavia_context')
        self._auth_validate_action(context, context.project_id,
                                   constants.RBAC_PUT)

        # Don't allow changes to the flavor_data or provider_name if it
        # is in use.
        if (not isinstance(flavorprofile.flavor_data, wtypes.UnsetType) or
                not isinstance(flavorprofile.provider_name, wtypes.UnsetType)):
            if self.repositories.flavor.count(context.session,
                                              flavor_profile_id=id) > 0:
                raise exceptions.ObjectInUse(object='Flavor profile', id=id)

        if not isinstance(flavorprofile.flavor_data, wtypes.UnsetType):
            # Do a basic JSON validation on the metadata
            try:
                flavor_data_dict = jsonutils.loads(flavorprofile.flavor_data)
            except Exception:
                raise exceptions.InvalidOption(
                    value=flavorprofile.flavor_data,
                    option=constants.FLAVOR_DATA)

            if isinstance(flavorprofile.provider_name, wtypes.UnsetType):
                db_flavor_profile = self._get_db_flavor_profile(
                    context.session, id)
                provider_driver = db_flavor_profile.provider_name
            else:
                provider_driver = flavorprofile.provider_name

            # Validate that the provider driver supports the metadata
            driver = driver_factory.get_driver(provider_driver)
            driver_utils.call_provider(driver.name, driver.validate_flavor,
                                       flavor_data_dict)

        lock_session = db_api.get_session(autocommit=False)
        try:
            flavorprofile_dict = flavorprofile.to_dict(render_unsets=False)
            if flavorprofile_dict:
                self.repositories.flavor_profile.update(lock_session, id,
                                                        **flavorprofile_dict)
            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_flavor_profile = self._get_db_flavor_profile(context.session, id)
        result = self._convert_db_to_type(
            db_flavor_profile, profile_types.FlavorProfileResponse)
        return profile_types.FlavorProfileRootResponse(flavorprofile=result)
Esempio n. 34
0
    def put(self, id, member_):
        """Updates a pool member."""
        member = member_.member
        context = pecan.request.context.get('octavia_context')
        db_member = self._get_db_member(context.session, id,
                                        show_deleted=False)

        pool = self.repositories.pool.get(context.session,
                                          id=db_member.pool_id)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, pool.load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        self._validate_pool_id(id, db_member.pool_id)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_and_pool_statuses(lock_session,
                                                         member=db_member)

            # Prepare the data for the driver data model
            member_dict = member.to_dict(render_unsets=False)
            member_dict['id'] = id
            provider_member_dict = (
                driver_utils.member_dict_to_provider_dict(member_dict))

            # Also prepare the baseline object data
            old_provider_member = driver_utils.db_member_to_provider_member(
                db_member)

            # Dispatch to the driver
            LOG.info("Sending update Member %s to provider %s", id,
                     driver.name)
            driver_utils.call_provider(
                driver.name, driver.member_update,
                old_provider_member,
                driver_dm.Member.from_dict(provider_member_dict))

            # Update the database to reflect what the driver just accepted
            member.provisioning_status = constants.PENDING_UPDATE
            db_member_dict = member.to_dict(render_unsets=False)
            self.repositories.member.update(lock_session, id, **db_member_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_member = self._get_db_member(context.session, id)
        result = self._convert_db_to_type(db_member,
                                          member_types.MemberResponse)
        return member_types.MemberRootResponse(member=result)
Esempio n. 35
0
    def put(self, id, flavor_profile_):
        """Updates a flavor Profile."""
        flavorprofile = flavor_profile_.flavorprofile
        context = pecan.request.context.get('octavia_context')
        self._auth_validate_action(context, context.project_id,
                                   constants.RBAC_PUT)

        # Don't allow changes to the flavor_data or provider_name if it
        # is in use.
        if (not isinstance(flavorprofile.flavor_data, wtypes.UnsetType) or
                not isinstance(flavorprofile.provider_name, wtypes.UnsetType)):
            if self.repositories.flavor.count(context.session,
                                              flavor_profile_id=id) > 0:
                raise exceptions.ObjectInUse(object='Flavor profile', id=id)

        if not isinstance(flavorprofile.flavor_data, wtypes.UnsetType):
            # Do a basic JSON validation on the metadata
            try:
                flavor_data_dict = jsonutils.loads(flavorprofile.flavor_data)
            except Exception:
                raise exceptions.InvalidOption(value=flavorprofile.flavor_data,
                                               option=constants.FLAVOR_DATA)

            if isinstance(flavorprofile.provider_name, wtypes.UnsetType):
                db_flavor_profile = self._get_db_flavor_profile(
                    context.session, id)
                provider_driver = db_flavor_profile.provider_name
            else:
                provider_driver = flavorprofile.provider_name

            # Validate that the provider driver supports the metadata
            driver = driver_factory.get_driver(provider_driver)
            driver_utils.call_provider(driver.name, driver.validate_flavor,
                                       flavor_data_dict)

        lock_session = db_api.get_session(autocommit=False)
        try:
            flavorprofile_dict = flavorprofile.to_dict(render_unsets=False)
            if flavorprofile_dict:
                self.repositories.flavor_profile.update(
                    lock_session, id, **flavorprofile_dict)
            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_flavor_profile = self._get_db_flavor_profile(context.session, id)
        result = self._convert_db_to_type(db_flavor_profile,
                                          profile_types.FlavorProfileResponse)
        return profile_types.FlavorProfileRootResponse(flavorprofile=result)
Esempio n. 36
0
    def put(self, number, **kwargs):
        try:
            count = int(number)
        except ValueError:
            raise exceptions.InvalidNumber(value=str(number))
        context = pecan.request.context.get('octavia_context')
        db_lb = self._get_db_lb(context.session,
                                self.lb_id,
                                show_deleted=False)

        self._auth_validate_action(context, db_lb.project_id,
                                   constants.RBAC_PUT_EXTEND)

        if db_lb.topology != constants.TOPOLOGY_ACTIVE_ACTIVE:
            raise exceptions.InvalidLoadBalancerOperation(type=db_lb.topology,
                                                          action='extension')

        try:
            flavor_dict = (self.repositories.flavor.get_flavor_metadata_dict(
                context.session, db_lb.flavor_id))
        except sa_exception.NoResultFound:
            raise exceptions.ValidationException(
                detail=_("Invalid flavor_id."))
        if count > flavor_dict[constants.MAX_AMPHORA_NUM]:
            raise exceptions.ExceededNumber(
                max_num=str(flavor_dict[constants.MAX_AMPHORA_NUM]))

        lb_amphorae = self.repositories.amphora.get_all_API_list(
            context.session,
            show_deleted=False,
            **{"load_balancer_id": self.lb_id})[0]
        old_count = len(lb_amphorae)
        if count < old_count:
            raise exceptions.UnsupportedOperation(
                operation="reducing amphora number")

        if count == old_count:
            return

        driver = driver_factory.get_driver(db_lb.provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_status(lock_session, self.lb_id)
            self.repositories.load_balancer.update(
                lock_session, self.lb_id,
                **{'expected_amphora_number': number})
            LOG.info(
                "Sending extension request for load balancer %s to the "
                "provider %s", self.lb_id, driver.name)
            driver_utils.call_provider(driver.name,
                                       driver.loadbalancer_extension,
                                       self.lb_id)
Esempio n. 37
0
    def test_call_provider(self):
        mock_driver_method = mock.MagicMock()

        # Test happy path
        utils.call_provider("provider_name", mock_driver_method,
                            "arg1", foo="arg2")
        mock_driver_method.assert_called_with("arg1", foo="arg2")

        # Test driver raising different types of DriverError
        mock_driver_method.side_effect = driver_exceptions.DriverError
        self.assertRaises(exceptions.ProviderDriverError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)
        mock_driver_method.side_effect = lib_exceptions.DriverError
        self.assertRaises(exceptions.ProviderDriverError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)

        # Test driver raising different types of NotImplementedError
        mock_driver_method.side_effect = driver_exceptions.NotImplementedError
        self.assertRaises(exceptions.ProviderNotImplementedError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)
        mock_driver_method.side_effect = NotImplementedError
        self.assertRaises(exceptions.ProviderNotImplementedError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)
        mock_driver_method.side_effect = lib_exceptions.NotImplementedError
        self.assertRaises(exceptions.ProviderNotImplementedError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)

        # Test driver raising different types of UnsupportedOptionError
        mock_driver_method.side_effect = (
            driver_exceptions.UnsupportedOptionError)
        self.assertRaises(exceptions.ProviderUnsupportedOptionError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)
        mock_driver_method.side_effect = (
            lib_exceptions.UnsupportedOptionError)
        self.assertRaises(exceptions.ProviderUnsupportedOptionError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)

        # Test driver raising DriverError
        mock_driver_method.side_effect = Exception
        self.assertRaises(exceptions.ProviderDriverError,
                          utils.call_provider, "provider_name",
                          mock_driver_method)
Esempio n. 38
0
    def put(self, **kwargs):
        """Fails over a loadbalancer"""
        context = pecan.request.context.get('octavia_context')
        db_lb = self._get_db_lb(context.session, self.lb_id,
                                show_deleted=False)

        self._auth_validate_action(context, db_lb.project_id,
                                   constants.RBAC_PUT_FAILOVER)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(db_lb.provider)

        with db_api.get_lock_session() as lock_session:
            self._test_and_set_failover_prov_status(lock_session, self.lb_id)
            LOG.info("Sending failover request for load balancer %s to the "
                     "provider %s", self.lb_id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.loadbalancer_failover, self.lb_id)
Esempio n. 39
0
    def put(self, **kwargs):
        """Fails over a loadbalancer"""
        context = pecan_request.context.get('octavia_context')
        db_lb = self._get_db_lb(context.session, self.lb_id,
                                show_deleted=False)

        self._auth_validate_action(context, db_lb.project_id,
                                   constants.RBAC_PUT_FAILOVER)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(db_lb.provider)

        with db_api.get_lock_session() as lock_session:
            self._test_and_set_failover_prov_status(lock_session, self.lb_id)
            LOG.info("Sending failover request for load balancer %s to the "
                     "provider %s", self.lb_id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.loadbalancer_failover, self.lb_id)
Esempio n. 40
0
    def post(self, availability_zone_profile_):
        """Creates an Availability Zone Profile."""
        availability_zone_profile = (
            availability_zone_profile_.availability_zone_profile)
        context = pecan_request.context.get('octavia_context')
        self._auth_validate_action(context, context.project_id,
                                   constants.RBAC_POST)
        # Do a basic JSON validation on the metadata
        try:
            availability_zone_data_dict = jsonutils.loads(
                availability_zone_profile.availability_zone_data)
        except Exception:
            raise exceptions.InvalidOption(
                value=availability_zone_profile.availability_zone_data,
                option=constants.AVAILABILITY_ZONE_DATA)

        # Validate that the provider driver supports the metadata
        driver = driver_factory.get_driver(
            availability_zone_profile.provider_name)
        driver_utils.call_provider(
            driver.name, driver.validate_availability_zone,
            availability_zone_data_dict)

        lock_session = db_api.get_session(autocommit=False)
        try:
            availability_zone_profile_dict = availability_zone_profile.to_dict(
                render_unsets=True)
            availability_zone_profile_dict['id'] = uuidutils.generate_uuid()
            db_availability_zone_profile = (
                self.repositories.availability_zone_profile.create(
                    lock_session, **availability_zone_profile_dict))
            lock_session.commit()
        except odb_exceptions.DBDuplicateEntry:
            lock_session.rollback()
            raise exceptions.IDAlreadyExists()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()
        result = self._convert_db_to_type(
            db_availability_zone_profile,
            profile_types.AvailabilityZoneProfileResponse)
        return profile_types.AvailabilityZoneProfileRootResponse(
            availability_zone_profile=result)
Esempio n. 41
0
    def _apply_flavor_to_lb_dict(self, lock_session, driver, lb_dict):

        flavor_dict = {}
        if 'flavor_id' in lb_dict:
            try:
                flavor_dict = (
                    self.repositories.flavor.get_flavor_metadata_dict(
                        lock_session, lb_dict['flavor_id']))
            except sa_exception.NoResultFound:
                raise exceptions.ValidationException(
                    detail=_("Invalid flavor_id."))

        # Make sure the driver will still accept the flavor metadata
        if flavor_dict:
            driver_utils.call_provider(driver.name, driver.validate_flavor,
                                       flavor_dict)

        # Apply the flavor settings to the load balanacer
        # Use the configuration file settings as defaults
        lb_dict[constants.TOPOLOGY] = flavor_dict.get(
            constants.LOADBALANCER_TOPOLOGY,
            CONF.controller_worker.loadbalancer_topology)

        return flavor_dict
Esempio n. 42
0
    def put(self, id, l7policy_):
        """Updates a l7policy."""
        l7policy = l7policy_.l7policy
        l7policy_dict = validate.sanitize_l7policy_api_args(
            l7policy.to_dict(render_unsets=False))
        # Reset renamed attributes
        for attr, val in l7policy_types.L7PolicyPUT._type_to_model_map.items():
            if val in l7policy_dict:
                l7policy_dict[attr] = l7policy_dict.pop(val)
        sanitized_l7policy = l7policy_types.L7PolicyPUT(**l7policy_dict)
        context = pecan.request.context.get('octavia_context')
        # Make sure any specified redirect_pool_id exists
        if l7policy_dict.get('redirect_pool_id'):
            db_pool = self._get_db_pool(
                context.session, l7policy_dict['redirect_pool_id'])
            self._escape_l7policy_udp_pool_request(db_pool)
        db_l7policy = self._get_db_l7policy(context.session, id,
                                            show_deleted=False)
        load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
            db_l7policy)
        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_statuses(lock_session,
                                                lb_id=load_balancer_id,
                                                listener_ids=[listener_id])

            # Prepare the data for the driver data model
            l7policy_dict = sanitized_l7policy.to_dict(render_unsets=False)
            l7policy_dict['id'] = id
            provider_l7policy_dict = (
                driver_utils.l7policy_dict_to_provider_dict(l7policy_dict))

            # Also prepare the baseline object data
            old_provider_l7policy = (
                driver_utils.db_l7policy_to_provider_l7policy(db_l7policy))

            # Dispatch to the driver
            LOG.info("Sending update L7 Policy %s to provider %s",
                     id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.l7policy_update,
                old_provider_l7policy,
                driver_dm.L7Policy.from_dict(provider_l7policy_dict))

            # Update the database to reflect what the driver just accepted
            sanitized_l7policy.provisioning_status = constants.PENDING_UPDATE
            db_l7policy_dict = sanitized_l7policy.to_dict(render_unsets=False)
            self.repositories.l7policy.update(lock_session, id,
                                              **db_l7policy_dict)

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_l7policy = self._get_db_l7policy(context.session, id)
        result = self._convert_db_to_type(db_l7policy,
                                          l7policy_types.L7PolicyResponse)
        return l7policy_types.L7PolicyRootResponse(l7policy=result)
Esempio n. 43
0
    def post(self, load_balancer):
        """Creates a load balancer."""
        load_balancer = load_balancer.loadbalancer
        context = pecan.request.context.get('octavia_context')

        if not load_balancer.project_id and context.project_id:
            load_balancer.project_id = context.project_id

        if not load_balancer.project_id:
            raise exceptions.ValidationException(detail=_(
                "Missing project ID in request where one is required."))

        self._auth_validate_action(context, load_balancer.project_id,
                                   constants.RBAC_POST)

        self._validate_vip_request_object(load_balancer)

        self._validate_flavor(context.session, load_balancer)

        provider = self._get_provider(context.session, load_balancer)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(
                    context.session,
                    lock_session,
                    data_models.LoadBalancer,
                    load_balancer.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.LoadBalancer._name())

            db_lb, db_pools, db_lists = None, None, None

            lb_dict = db_prepare.create_load_balancer(load_balancer.to_dict(
                render_unsets=False
            ))
            vip_dict = lb_dict.pop('vip', {})

            # Make sure we store the right provider in the DB
            lb_dict['provider'] = driver.name

            # NoneType can be weird here, have to force type a second time
            listeners = lb_dict.pop('listeners', []) or []
            pools = lb_dict.pop('pools', []) or []

            flavor_dict = self._apply_flavor_to_lb_dict(lock_session, driver,
                                                        lb_dict)

            db_lb = self.repositories.create_load_balancer_and_vip(
                lock_session, lb_dict, vip_dict)

            # Pass the flavor dictionary through for the provider drivers
            # This is a "virtual" lb_dict item that includes the expanded
            # flavor dict instead of just the flavor_id we store in the DB.
            lb_dict['flavor'] = flavor_dict

            # See if the provider driver wants to create the VIP port
            octavia_owned = False
            try:
                provider_vip_dict = driver_utils.vip_dict_to_provider_dict(
                    vip_dict)
                vip_dict = driver_utils.call_provider(
                    driver.name, driver.create_vip_port, db_lb.id,
                    db_lb.project_id, provider_vip_dict)
                vip = driver_utils.provider_vip_dict_to_vip_obj(vip_dict)
            except exceptions.ProviderNotImplementedError:
                # create vip port if not exist, driver didn't want to create
                # the VIP port
                vip = self._create_vip_port_if_not_exist(db_lb)
                LOG.info('Created VIP port %s for provider %s.',
                         vip.port_id, driver.name)
                # If a port_id wasn't passed in and we made it this far
                # we created the VIP
                if 'port_id' not in vip_dict or not vip_dict['port_id']:
                    octavia_owned = True

            self.repositories.vip.update(
                lock_session, db_lb.id, ip_address=vip.ip_address,
                port_id=vip.port_id, network_id=vip.network_id,
                subnet_id=vip.subnet_id, octavia_owned=octavia_owned)

            if listeners or pools:
                db_pools, db_lists = self._graph_create(
                    context.session, lock_session, db_lb, listeners, pools)

            # Prepare the data for the driver data model
            driver_lb_dict = driver_utils.lb_dict_to_provider_dict(
                lb_dict, vip, db_pools, db_lists)

            # Dispatch to the driver
            LOG.info("Sending create Load Balancer %s to provider %s",
                     db_lb.id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.loadbalancer_create,
                driver_dm.LoadBalancer.from_dict(driver_lb_dict))

            lock_session.commit()
        except odb_exceptions.DBDuplicateEntry:
            lock_session.rollback()
            raise exceptions.IDAlreadyExists()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_lb = self._get_db_lb(context.session, db_lb.id)

        result = self._convert_db_to_type(
            db_lb, lb_types.LoadBalancerFullResponse)
        return lb_types.LoadBalancerFullRootResponse(loadbalancer=result)
Esempio n. 44
0
    def post(self, load_balancer):
        """Creates a load balancer."""
        load_balancer = load_balancer.loadbalancer
        context = pecan_request.context.get('octavia_context')

        if not load_balancer.project_id and context.project_id:
            load_balancer.project_id = context.project_id

        if not load_balancer.project_id:
            raise exceptions.ValidationException(detail=_(
                "Missing project ID in request where one is required. "
                "An administrator should check the keystone settings "
                "in the Octavia configuration."))

        self._auth_validate_action(context, load_balancer.project_id,
                                   constants.RBAC_POST)

        self._validate_vip_request_object(load_balancer, context=context)

        self._validate_flavor(context.session, load_balancer)

        self._validate_availability_zone(context.session, load_balancer)

        provider = self._get_provider(context.session, load_balancer)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(
                    context.session,
                    lock_session,
                    data_models.LoadBalancer,
                    load_balancer.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.LoadBalancer._name())

            db_lb, db_pools, db_lists = None, None, None

            lb_dict = db_prepare.create_load_balancer(load_balancer.to_dict(
                render_unsets=False
            ))
            vip_dict = lb_dict.pop('vip', {})

            # Make sure we store the right provider in the DB
            lb_dict['provider'] = driver.name

            # NoneType can be weird here, have to force type a second time
            listeners = lb_dict.pop('listeners', []) or []
            pools = lb_dict.pop('pools', []) or []

            flavor_dict = self._apply_flavor_to_lb_dict(lock_session, driver,
                                                        lb_dict)

            az_dict = self._validate_and_return_az_dict(lock_session, driver,
                                                        lb_dict)
            # Validate the network as soon as we have the AZ data
            validate.network_allowed_by_config(
                load_balancer.vip_network_id,
                valid_networks=az_dict.get(constants.VALID_VIP_NETWORKS))

            db_lb = self.repositories.create_load_balancer_and_vip(
                lock_session, lb_dict, vip_dict)

            # Pass the flavor dictionary through for the provider drivers
            # This is a "virtual" lb_dict item that includes the expanded
            # flavor dict instead of just the flavor_id we store in the DB.
            lb_dict['flavor'] = flavor_dict

            # Do the same with the availability_zone dict
            lb_dict['availability_zone'] = az_dict

            # See if the provider driver wants to manage the VIP port
            # This will still be called if the user provided a port to
            # allow drivers to collect any required information about the
            # VIP port.
            octavia_owned = False
            try:
                provider_vip_dict = driver_utils.vip_dict_to_provider_dict(
                    vip_dict)
                vip_dict = driver_utils.call_provider(
                    driver.name, driver.create_vip_port, db_lb.id,
                    db_lb.project_id, provider_vip_dict)
                vip = driver_utils.provider_vip_dict_to_vip_obj(vip_dict)
            except exceptions.ProviderNotImplementedError:
                # create vip port if not exist, driver didn't want to create
                # the VIP port
                vip = self._create_vip_port_if_not_exist(db_lb)
                LOG.info('Created VIP port %s for provider %s.',
                         vip.port_id, driver.name)
                # If a port_id wasn't passed in and we made it this far
                # we created the VIP
                if 'port_id' not in vip_dict or not vip_dict['port_id']:
                    octavia_owned = True

            # Check if the driver claims octavia owns the VIP port.
            if vip.octavia_owned:
                octavia_owned = True

            self.repositories.vip.update(
                lock_session, db_lb.id, ip_address=vip.ip_address,
                port_id=vip.port_id, network_id=vip.network_id,
                subnet_id=vip.subnet_id, octavia_owned=octavia_owned)

            if listeners or pools:
                db_pools, db_lists = self._graph_create(
                    context.session, lock_session, db_lb, listeners, pools)

            # Prepare the data for the driver data model
            driver_lb_dict = driver_utils.lb_dict_to_provider_dict(
                lb_dict, vip, db_pools, db_lists)

            # Dispatch to the driver
            LOG.info("Sending create Load Balancer %s to provider %s",
                     db_lb.id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.loadbalancer_create,
                driver_dm.LoadBalancer.from_dict(driver_lb_dict))

            lock_session.commit()
        except odb_exceptions.DBDuplicateEntry:
            lock_session.rollback()
            raise exceptions.IDAlreadyExists()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_lb = self._get_db_lb(context.session, db_lb.id)

        result = self._convert_db_to_type(
            db_lb, lb_types.LoadBalancerFullResponse)
        return lb_types.LoadBalancerFullRootResponse(loadbalancer=result)
Esempio n. 45
0
    def post(self, pool_):
        """Creates a pool on a load balancer or listener.

        Note that this can optionally take a listener_id with which the pool
        should be associated as the listener's default_pool. If specified,
        the pool creation will fail if the listener specified already has
        a default_pool.
        """
        # For some API requests the listener_id will be passed in the
        # pool_dict:
        pool = pool_.pool
        context = pecan.request.context.get('octavia_context')
        if pool.protocol == constants.PROTOCOL_UDP:
            self._validate_pool_request_for_udp(pool)
        else:
            if (pool.session_persistence and (
                    pool.session_persistence.persistence_timeout or
                    pool.session_persistence.persistence_granularity)):
                raise exceptions.ValidationException(detail=_(
                    "persistence_timeout and persistence_granularity "
                    "is only for UDP protocol pools."))
        if pool.loadbalancer_id:
            pool.project_id, provider = self._get_lb_project_id_provider(
                context.session, pool.loadbalancer_id)
        elif pool.listener_id:
            listener = self.repositories.listener.get(
                context.session, id=pool.listener_id)
            pool.loadbalancer_id = listener.load_balancer_id
            pool.project_id, provider = self._get_lb_project_id_provider(
                context.session, pool.loadbalancer_id)
        else:
            msg = _("Must provide at least one of: "
                    "loadbalancer_id, listener_id")
            raise exceptions.ValidationException(detail=msg)

        self._auth_validate_action(context, pool.project_id,
                                   constants.RBAC_POST)

        if pool.session_persistence:
            sp_dict = pool.session_persistence.to_dict(render_unsets=False)
            validate.check_session_persistence(sp_dict)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(
                    context.session,
                    lock_session,
                    data_models.Pool,
                    pool.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.Pool._name())

            listener_repo = self.repositories.listener
            pool_dict = db_prepare.create_pool(
                pool.to_dict(render_unsets=True))

            listener_id = pool_dict.pop('listener_id', None)
            if listener_id:
                if listener_repo.has_default_pool(lock_session,
                                                  listener_id):
                    raise exceptions.DuplicatePoolEntry()

            self._test_lb_and_listener_statuses(
                lock_session, lb_id=pool_dict['load_balancer_id'],
                listener_ids=[listener_id] if listener_id else [])

            db_pool = self._validate_create_pool(
                lock_session, pool_dict, listener_id)

            # Prepare the data for the driver data model
            provider_pool = (
                driver_utils.db_pool_to_provider_pool(db_pool))

            # Dispatch to the driver
            LOG.info("Sending create Pool %s to provider %s",
                     db_pool.id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.pool_create, provider_pool)

            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_pool = self._get_db_pool(context.session, db_pool.id)
        result = self._convert_db_to_type(db_pool, pool_types.PoolResponse)
        return pool_types.PoolRootResponse(pool=result)
Esempio n. 46
0
    def put(self, members_):
        """Updates all members."""
        members = members_.members
        context = pecan.request.context.get('octavia_context')

        db_pool = self._get_db_pool(context.session, self.pool_id)
        old_members = db_pool.members

        project_id, provider = self._get_lb_project_id_provider(
            context.session, db_pool.load_balancer_id)

        # Check POST+PUT+DELETE since this operation is all of 'CUD'
        self._auth_validate_action(context, project_id, constants.RBAC_POST)
        self._auth_validate_action(context, project_id, constants.RBAC_PUT)
        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        # Validate member subnets
        for member in members:
            if member.subnet_id and not validate.subnet_exists(
                    member.subnet_id):
                raise exceptions.NotFound(resource='Subnet',
                                          id=member.subnet_id)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_and_pool_statuses(lock_session)

            member_count_diff = len(members) - len(old_members)
            if member_count_diff > 0 and self.repositories.check_quota_met(
                    context.session, lock_session, data_models.Member,
                    db_pool.project_id, count=member_count_diff):
                raise exceptions.QuotaException(
                    resource=data_models.Member._name())

            old_member_uniques = {
                (m.ip_address, m.protocol_port): m.id for m in old_members}
            new_member_uniques = [
                (m.address, m.protocol_port) for m in members]

            # Find members that are brand new or updated
            new_members = []
            updated_members = []
            for m in members:
                if (m.address, m.protocol_port) not in old_member_uniques:
                    validate.ip_not_reserved(m.address)
                    new_members.append(m)
                else:
                    m.id = old_member_uniques[(m.address, m.protocol_port)]
                    updated_members.append(m)

            # Find members that are deleted
            deleted_members = []
            for m in old_members:
                if (m.ip_address, m.protocol_port) not in new_member_uniques:
                    deleted_members.append(m)

            provider_members = []
            # Create new members
            for m in new_members:
                m = m.to_dict(render_unsets=False)
                m['project_id'] = db_pool.project_id
                created_member = self._graph_create(lock_session, m)
                provider_member = driver_utils.db_member_to_provider_member(
                    created_member)
                provider_members.append(provider_member)
            # Update old members
            for m in updated_members:
                m.provisioning_status = constants.PENDING_UPDATE
                db_member_dict = m.to_dict(render_unsets=False)
                db_member_dict.pop('id')
                self.repositories.member.update(
                    lock_session, m.id, **db_member_dict)

                m.pool_id = self.pool_id
                provider_members.append(
                    driver_utils.db_member_to_provider_member(m))
            # Delete old members
            for m in deleted_members:
                self.repositories.member.update(
                    lock_session, m.id,
                    provisioning_status=constants.PENDING_DELETE)

            # Dispatch to the driver
            LOG.info("Sending Pool %s batch member update to provider %s",
                     db_pool.id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.member_batch_update, provider_members)
Esempio n. 47
0
    def post(self, listener_):
        """Creates a listener on a load balancer."""
        listener = listener_.listener
        context = pecan.request.context.get('octavia_context')

        load_balancer_id = listener.loadbalancer_id
        listener.project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, listener.project_id,
                                   constants.RBAC_POST)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(
                    context.session,
                    lock_session,
                    data_models.Listener,
                    listener.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.Listener._name())

            listener_dict = db_prepare.create_listener(
                listener.to_dict(render_unsets=True), None)

            if listener_dict['default_pool_id']:
                self._validate_pool(context.session, load_balancer_id,
                                    listener_dict['default_pool_id'],
                                    listener.protocol)

            self._test_lb_and_listener_statuses(
                lock_session, lb_id=load_balancer_id)

            db_listener = self._validate_create_listener(
                lock_session, listener_dict)

            # Prepare the data for the driver data model
            provider_listener = (
                driver_utils.db_listener_to_provider_listener(db_listener))

            # re-inject the sni container references lost due to SNI
            # being a separate table in the DB
            provider_listener.sni_container_refs = listener.sni_container_refs

            # Dispatch to the driver
            LOG.info("Sending create Listener %s to provider %s",
                     db_listener.id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.listener_create, provider_listener)

            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_listener = self._get_db_listener(context.session, db_listener.id)
        result = self._convert_db_to_type(db_listener,
                                          listener_types.ListenerResponse)
        return listener_types.ListenerRootResponse(listener=result)
Esempio n. 48
0
    def put(self, id, availability_zone_profile_):
        """Updates an Availability Zone Profile."""
        availability_zone_profile = (
            availability_zone_profile_.availability_zone_profile)
        context = pecan_request.context.get('octavia_context')
        self._auth_validate_action(context, context.project_id,
                                   constants.RBAC_PUT)

        self._validate_update_azp(context, id, availability_zone_profile)
        if id == constants.NIL_UUID:
            raise exceptions.NotFound(resource='Availability Zone Profile',
                                      id=constants.NIL_UUID)

        if not isinstance(availability_zone_profile.availability_zone_data,
                          wtypes.UnsetType):
            # Do a basic JSON validation on the metadata
            try:
                availability_zone_data_dict = jsonutils.loads(
                    availability_zone_profile.availability_zone_data)
            except Exception:
                raise exceptions.InvalidOption(
                    value=availability_zone_profile.availability_zone_data,
                    option=constants.FLAVOR_DATA)

            if isinstance(availability_zone_profile.provider_name,
                          wtypes.UnsetType):
                db_availability_zone_profile = (
                    self._get_db_availability_zone_profile(
                        context.session, id))
                provider_driver = db_availability_zone_profile.provider_name
            else:
                provider_driver = availability_zone_profile.provider_name

            # Validate that the provider driver supports the metadata
            driver = driver_factory.get_driver(provider_driver)
            driver_utils.call_provider(
                driver.name, driver.validate_availability_zone,
                availability_zone_data_dict)

        lock_session = db_api.get_session(autocommit=False)
        try:
            availability_zone_profile_dict = availability_zone_profile.to_dict(
                render_unsets=False)
            if availability_zone_profile_dict:
                self.repositories.availability_zone_profile.update(
                    lock_session, id, **availability_zone_profile_dict)
            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_availability_zone_profile = self._get_db_availability_zone_profile(
            context.session, id)
        result = self._convert_db_to_type(
            db_availability_zone_profile,
            profile_types.AvailabilityZoneProfileResponse)
        return profile_types.AvailabilityZoneProfileRootResponse(
            availability_zone_profile=result)
Esempio n. 49
0
    def delete(self, id):
        """Deletes a listener from a load balancer."""
        context = pecan.request.context.get('octavia_context')
        db_listener = self._get_db_listener(context.session, id,
                                            show_deleted=False)
        load_balancer_id = db_listener.load_balancer_id

        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_DELETE)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:

            self._test_lb_and_listener_statuses(
                lock_session, load_balancer_id,
                id=id, listener_status=constants.PENDING_DELETE)

            LOG.info("Sending delete Listener %s to provider %s", id,
                     driver.name)
            provider_listener = (
                driver_utils.db_listener_to_provider_listener(db_listener))
            driver_utils.call_provider(driver.name, driver.listener_delete,
                                       provider_listener)

        # Revoke access of octavia service user to certificates
        tls_refs = []

        for sni in db_listener.sni_containers:
            filters = {'tls_container_id': sni.tls_container_id}
            snis = self.repositories.sni.get_all(context.session, **filters)[0]

            if len(snis) == 1:
                # referred only once, enqueue for access revoking
                tls_refs.append(sni.tls_container_id)
            else:
                blocking_listeners = [s.listener_id for s in snis if
                                      s.listener_id != id]
                LOG.debug("Listeners %s using TLS ref %s. Access to TLS ref "
                          "will not be revoked.", blocking_listeners,
                          sni.tls_container_id)

        if db_listener.tls_certificate_id:
            filters = {'tls_certificate_id': db_listener.tls_certificate_id}
            # Note get_all returns the list and links. We only want the list.
            listeners = self.repositories.listener.get_all(
                context.session, show_deleted=False, **filters)[0]

            if len(listeners) == 1:
                # referred only once, enqueue for access revoking
                tls_refs.append(db_listener.tls_certificate_id)
            else:
                blocking_listeners = [l.id for l in listeners if l.id != id]
                LOG.debug("Listeners %s using TLS ref %s. Access to TLS ref "
                          "will not be revoked.", blocking_listeners,
                          db_listener.tls_certificate_id)

        for ref in tls_refs:
            try:
                self.cert_manager.unset_acls(context, ref)
            except Exception:
                # certificate may have been removed already
                pass
Esempio n. 50
0
    def put(self, id, listener_):
        """Updates a listener on a load balancer."""
        listener = listener_.listener
        context = pecan.request.context.get('octavia_context')
        db_listener = self._get_db_listener(context.session, id,
                                            show_deleted=False)
        load_balancer_id = db_listener.load_balancer_id

        project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, project_id, constants.RBAC_PUT)

        # TODO(rm_work): Do we need something like this? What do we do on an
        # empty body for a PUT?
        if not listener:
            raise exceptions.ValidationException(
                detail='No listener object supplied.')

        if (db_listener.protocol == constants.PROTOCOL_UDP and
                self._is_tls_or_insert_header(listener)):
            raise exceptions.ValidationException(detail=_(
                "%s protocol listener does not support TLS or header "
                "insertion.") % constants.PROTOCOL_UDP)

        if listener.default_pool_id:
            self._validate_pool(context.session, load_balancer_id,
                                listener.default_pool_id, db_listener.protocol)

        sni_containers = listener.sni_container_refs or []
        tls_refs = [sni for sni in sni_containers]
        if listener.default_tls_container_ref:
            tls_refs.append(listener.default_tls_container_ref)
        self._validate_tls_refs(tls_refs)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        with db_api.get_lock_session() as lock_session:
            self._test_lb_and_listener_statuses(lock_session,
                                                load_balancer_id, id=id)

            # Prepare the data for the driver data model
            listener_dict = listener.to_dict(render_unsets=False)
            listener_dict['id'] = id
            provider_listener_dict = (
                driver_utils.listener_dict_to_provider_dict(listener_dict))

            # Also prepare the baseline object data
            old_provider_llistener = (
                driver_utils.db_listener_to_provider_listener(db_listener))

            # Dispatch to the driver
            LOG.info("Sending update Listener %s to provider %s", id,
                     driver.name)
            driver_utils.call_provider(
                driver.name, driver.listener_update,
                old_provider_llistener,
                driver_dm.Listener.from_dict(provider_listener_dict))

            # Update the database to reflect what the driver just accepted
            self.repositories.listener.update(
                lock_session, id, **listener.to_dict(render_unsets=False))

        # Force SQL alchemy to query the DB, otherwise we get inconsistent
        # results
        context.session.expire_all()
        db_listener = self._get_db_listener(context.session, id)
        result = self._convert_db_to_type(db_listener,
                                          listener_types.ListenerResponse)
        return listener_types.ListenerRootResponse(listener=result)
Esempio n. 51
0
    def post(self, l7policy_):
        """Creates a l7policy on a listener."""
        l7policy = l7policy_.l7policy
        context = pecan.request.context.get('octavia_context')
        # Make sure any pool specified by redirect_pool_id exists
        if l7policy.redirect_pool_id:
            db_pool = self._get_db_pool(
                context.session, l7policy.redirect_pool_id)
            self._escape_l7policy_udp_pool_request(db_pool)
        # Verify the parent listener exists
        listener_id = l7policy.listener_id
        listener = self._get_db_listener(
            context.session, listener_id)
        load_balancer_id = listener.load_balancer_id
        l7policy.project_id, provider = self._get_lb_project_id_provider(
            context.session, load_balancer_id)

        self._auth_validate_action(context, l7policy.project_id,
                                   constants.RBAC_POST)

        # Load the driver early as it also provides validation
        driver = driver_factory.get_driver(provider)

        lock_session = db_api.get_session(autocommit=False)
        try:
            if self.repositories.check_quota_met(
                    context.session,
                    lock_session,
                    data_models.L7Policy,
                    l7policy.project_id):
                raise exceptions.QuotaException(
                    resource=data_models.L7Policy._name())

            l7policy_dict = db_prepare.create_l7policy(
                l7policy.to_dict(render_unsets=True),
                load_balancer_id, listener_id)

            self._test_lb_and_listener_statuses(
                lock_session, lb_id=load_balancer_id,
                listener_ids=[listener_id])
            db_l7policy = self._validate_create_l7policy(
                lock_session, l7policy_dict)

            # Prepare the data for the driver data model
            provider_l7policy = (
                driver_utils.db_l7policy_to_provider_l7policy(db_l7policy))

            # Dispatch to the driver
            LOG.info("Sending create L7 Policy %s to provider %s",
                     db_l7policy.id, driver.name)
            driver_utils.call_provider(
                driver.name, driver.l7policy_create, provider_l7policy)

            lock_session.commit()
        except Exception:
            with excutils.save_and_reraise_exception():
                lock_session.rollback()

        db_l7policy = self._get_db_l7policy(context.session, db_l7policy.id)
        result = self._convert_db_to_type(db_l7policy,
                                          l7policy_types.L7PolicyResponse)
        return l7policy_types.L7PolicyRootResponse(l7policy=result)