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