def put(self, id, flavor_): flavor = flavor_.flavor context = pecan_request.context.get('octavia_context') self._auth_validate_action(context, context.project_id, constants.RBAC_PUT) if id == constants.NIL_UUID: raise exceptions.NotFound(resource='Flavor', id=constants.NIL_UUID) lock_session = db_api.get_session(autocommit=False) try: flavor_dict = flavor.to_dict(render_unsets=False) if flavor_dict: self.repositories.flavor.update(lock_session, id, **flavor_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 = self._get_db_flavor(context.session, id) result = self._convert_db_to_type(db_flavor, flavor_types.FlavorResponse) return flavor_types.FlavorRootResponse(flavor=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_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 test_exception(self): try: raise exc.NotFound() except exc.NotFound: pass else: raise Exception()
def put(self, name, availability_zone_): availability_zone = availability_zone_.availability_zone context = pecan_request.context.get('octavia_context') self._auth_validate_action(context, context.project_id, constants.RBAC_PUT) if name == constants.NIL_UUID: raise exceptions.NotFound(resource='Availability Zone', id=constants.NIL_UUID) lock_session = db_api.get_session(autocommit=False) try: availability_zone_dict = availability_zone.to_dict( render_unsets=False) if availability_zone_dict: self.repositories.availability_zone.update( lock_session, name, **availability_zone_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 = self._get_db_availability_zone( context.session, name) result = self._convert_db_to_type( db_availability_zone, availability_zone_types.AvailabilityZoneResponse) return availability_zone_types.AvailabilityZoneRootResponse( availability_zone=result)
def post(self, member_): """Creates a pool member on a pool.""" member = member_.member context = pecan.request.context.get('octavia_context') # 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 = self._get_lb_project_id(context.session, pool.load_balancer_id) self._auth_validate_action(context, member.project_id, constants.RBAC_POST) 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 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) lock_session.commit() except Exception: with excutils.save_and_reraise_exception(): lock_session.rollback() return self._send_member_to_handler(context.session, db_member)
def _validate_pool(self, session, pool_id): """Validate pool given exists on same load balancer as listener.""" db_pool = self.repositories.pool.get( session, load_balancer_id=self.load_balancer_id, id=pool_id) if not db_pool: raise exceptions.NotFound(resource=data_models.Pool._name(), id=pool_id)
def get_interface_name(ip_address, net_ns=None): """Gets the interface name from an IP address. :param ip_address: The IP address to lookup. :param net_ns: The network namespace to find the interface in. :returns: The interface name. :raises exceptions.InvalidIPAddress: Invalid IP address provided. :raises octavia.common.exceptions.NotFound: No interface was found. """ # We need to normalize the address as IPv6 has multiple representations # fe80:0000:0000:0000:f816:3eff:fef2:2058 == fe80::f816:3eff:fef2:2058 try: normalized_addr = ipaddress.ip_address(ip_address).compressed except ValueError as e: raise exceptions.InvalidIPAddress(ip_addr=ip_address) from e if net_ns: with pyroute2.NetNS(net_ns) as rtnl_api: interface = _find_interface(ip_address, rtnl_api, normalized_addr) else: with pyroute2.IPRoute() as rtnl_api: interface = _find_interface(ip_address, rtnl_api, normalized_addr) if interface is not None: return interface raise exceptions.NotFound(resource='IP address', id=ip_address)
def delete(self, id): """Deletes a pool member.""" session = db_api.get_session() db_member = self.repositories.member.get(session, id=id) if not db_member: LOG.info(_LI("Member %s not found"), id) raise exceptions.NotFound(resource=data_models.Member._name(), id=id) # Verify load balancer is in a mutable status. If so it can be assumed # that the listener is also in a mutable status because a load balancer # will only be ACTIVE when all its listeners as ACTIVE. if not self.repositories.test_and_set_lb_and_listener_prov_status( session, self.load_balancer_id, self.listener_id, constants.PENDING_UPDATE, constants.PENDING_UPDATE): LOG.info( _LI("Member %s cannot be deleted because its Load " "Balancer is in an immutable state."), id) lb_repo = self.repositories.load_balancer db_lb = lb_repo.get(session, id=self.load_balancer_id) raise exceptions.ImmutableObject(resource=db_lb._name(), id=self.load_balancer_id) db_member = self.repositories.member.get(session, id=id) try: LOG.info(_LI("Sending Deletion of Member %s to handler"), db_member.id) self.handler.delete(db_member) except Exception: with excutils.save_and_reraise_exception(reraise=False): self.repositories.listener.update( session, self.listener_id, operating_status=constants.ERROR) db_member = self.repositories.member.get(session, id=id) return self._convert_db_to_type(db_member, member_types.MemberResponse)
def _lookup(self, lb_id, *remainder): """Overridden pecan _lookup method for custom routing. Verifies that the load balancer passed in the url exists, and if so decides which controller, if any, should control be passed. """ context = pecan.request.context.get('octavia_context') possible_remainder = ('listeners', 'pools', 'delete_cascade', 'stats') if lb_id and len(remainder) and (remainder[0] in possible_remainder): controller = remainder[0] remainder = remainder[1:] db_lb = self.repositories.load_balancer.get(context.session, id=lb_id) if not db_lb: LOG.info(_LI("Load Balancer %s was not found."), lb_id) raise exceptions.NotFound( resource=data_models.LoadBalancer._name(), id=lb_id) if controller == 'listeners': return listener.ListenersController( load_balancer_id=db_lb.id), remainder elif controller == 'pools': return pool.PoolsController( load_balancer_id=db_lb.id), remainder elif (controller == 'delete_cascade'): return LBCascadeDeleteController(db_lb.id), '' elif (controller == 'stats'): return lb_stats.LoadBalancerStatisticsController( loadbalancer_id=db_lb.id), remainder
def _lookup(self, listener_id, *remainder): """Overridden pecan _lookup method for custom routing. Verifies that the listener passed in the url exists, and if so decides which controller, if any, should control be passed. """ context = pecan.request.context.get('octavia_context') is_children = ( listener_id and remainder and (remainder[0] == 'pools' or (remainder[0] == 'l7policies' or remainder[0] == 'stats'))) if is_children: controller = remainder[0] remainder = remainder[1:] db_listener = self.repositories.listener.get(context.session, id=listener_id) if not db_listener: LOG.info("Listener %s not found.", listener_id) raise exceptions.NotFound( resource=data_models.Listener._name(), id=listener_id) if controller == 'pools': return pool.PoolsController( load_balancer_id=self.load_balancer_id, listener_id=db_listener.id), remainder elif controller == 'l7policies': return l7policy.L7PolicyController( load_balancer_id=self.load_balancer_id, listener_id=db_listener.id), remainder elif controller == 'stats': return listener_statistics.ListenerStatisticsController( listener_id=db_listener.id), remainder return None
def _get_db_obj(session, repo, data_model, id): """Gets an object from the database and returns it.""" db_obj = repo.get(session, id=id) if not db_obj: LOG.info(_LI("%s not found"), data_model._name() + id) raise exceptions.NotFound(resource=data_model._name(), id=id) return db_obj
def _pool_check(self, session, pool_id, lb_id, project_id): """Sanity checks for the redirect_pool if specified.""" pool_db = (session.query(models.Pool).filter_by(id=pool_id).filter_by( project_id=project_id).filter_by(load_balancer_id=lb_id).first()) if not pool_db: raise exceptions.NotFound(resource=data_models.Pool._name(), id=pool_id)
def update(self, session, id, **model_kwargs): with session.begin(subtransactions=True): l7rule_db = session.query( self.model_class).filter_by(id=id).first() if not l7rule_db: raise exceptions.NotFound(resource=data_models.L7Rule._name(), id=id) l7rule_dict = l7rule_db.to_data_model().to_dict() # Ignore values that are None for k, v in model_kwargs.items(): if v is not None: l7rule_dict.update({k: v}) # Clear out the 'key' attribute for rule types that don't use it. if ('type' in l7rule_dict.keys() and l7rule_dict['type'] in (constants.L7RULE_TYPE_HOST_NAME, constants.L7RULE_TYPE_PATH, constants.L7RULE_TYPE_FILE_TYPE)): l7rule_dict['key'] = None model_kwargs.update({'key': None}) validate.l7rule_data(self.model_class(**l7rule_dict)) l7rule_db.update(model_kwargs) l7rule_db = self.get(session, id=id) return l7rule_db
def put(self, id, load_balancer): """Updates a load balancer.""" session = db_api.get_session() # Purely to make lines smaller length lb_repo = self.repositories.load_balancer db_lb = self.repositories.load_balancer.get(session, id=id) if not db_lb: LOG.info(_LI("Load Balancer %s was not found."), id) raise exceptions.NotFound( resource=data_models.LoadBalancer._name(), id=id) # Check load balancer is in a mutable status if not lb_repo.test_and_set_provisioning_status( session, id, constants.PENDING_UPDATE): LOG.info(_LI("Load Balancer %s is immutable."), id) raise exceptions.ImmutableObject(resource=db_lb._name(), id=id) try: LOG.info(_LI("Sending updated Load Balancer %s to the handler"), id) self.handler.update(db_lb, load_balancer) except Exception: with excutils.save_and_reraise_exception(reraise=False): self.repositories.load_balancer.update( session, id, provisioning_status=constants.ERROR) lb = self.repositories.load_balancer.get(session, id=id) return self._convert_db_to_type(lb, lb_types.LoadBalancerResponse)
def _lookup(self, pool_id, *remainder): """Overriden pecan _lookup method for custom routing. Verifies that the pool passed in the url exists, and if so decides which controller, if any, should control be passed. """ context = pecan.request.context.get('octavia_context') if pool_id and len(remainder) and (remainder[0] == 'members' or remainder[0] == 'healthmonitor'): controller = remainder[0] remainder = remainder[1:] db_pool = self.repositories.pool.get(context.session, id=pool_id) if not db_pool: LOG.info(_LI("Pool %s not found."), pool_id) raise exceptions.NotFound(resource=data_models.Pool._name(), id=pool_id) if controller == 'members': return member.MembersController( load_balancer_id=self.load_balancer_id, pool_id=db_pool.id, listener_id=self.listener_id), remainder elif controller == 'healthmonitor': return health_monitor.HealthMonitorController( load_balancer_id=self.load_balancer_id, pool_id=db_pool.id, listener_id=self.listener_id), remainder
def get(self, id): """Gets a pool's details.""" session = db_api.get_session() db_pool = self.repositories.pool.get(session, id=id) if not db_pool: LOG.info(_LI("Pool %s not found."), id) raise exceptions.NotFound(resource=data_models.Pool._name(), id=id) return self._convert_db_to_type(db_pool, pool_types.PoolResponse)
def _get_db_amp(self, session, amp_id): """Gets the current amphora object from the database.""" db_amp = self.repositories.amphora.get(session, id=amp_id) if not db_amp: LOG.info("Amphora %s was not found", amp_id) raise exceptions.NotFound(resource=data_models.Amphora._name(), id=amp_id) return db_amp
def _get_db_hm(self, session, hm_id): """Gets the current health monitor object from the database.""" db_hm = self.repositories.health_monitor.get(session, id=hm_id) if not db_hm: LOG.info(_LI("Health Monitor %s was not found"), hm_id) raise exceptions.NotFound( resource=data_models.HealthMonitor._name(), id=hm_id) return db_hm
def _get_db_obj(session, repo, data_model, id): """Gets an object from the database and returns it.""" db_obj = repo.get(session, id=id) if not db_obj: LOG.exception( _LE("{name} {id} not found").format(name=data_model._name(), id=id)) raise exceptions.NotFound(resource=data_model._name(), id=id) return db_obj
def _get_db_listener(self, session, id): """Gets a listener object from the database.""" db_listener = self.repositories.listener.get( session, load_balancer_id=self.load_balancer_id, id=id) if not db_listener: LOG.info(_LI("Listener %s not found."), id) raise exceptions.NotFound(resource=data_models.Listener._name(), id=id) return db_listener
def get(self, id): """Gets a single pool member's details.""" session = db_api.get_session() db_member = self.repositories.member.get(session, id=id) if not db_member: LOG.info(_LI("Member %s not found"), id) raise exceptions.NotFound(resource=data_models.Member._name(), id=id) return self._convert_db_to_type(db_member, member_types.MemberResponse)
def _get_db_obj(session, repo, data_model, id): """Gets an object from the database and returns it.""" db_obj = repo.get(session, id=id) if not db_obj: LOG.exception('%(name)s %(id)s not found', {'name': data_model._name(), 'id': id}) raise exceptions.NotFound( resource=data_model._name(), id=id) return db_obj
def _get_db_availability_zone(self, session, name): """Get an availability zone from the database.""" db_obj = self.repositories.availability_zone.get(session, name=name) if not db_obj: LOG.debug('%(obj_name)s %(name)s not found', { 'obj_name': data_models.AvailabilityZone._name(), 'name': name }) raise exceptions.NotFound( resource=data_models.AvailabilityZone._name(), id=name) return db_obj
def _get_db_ls(self, session): """Gets the current listener statistics object from the database.""" db_ls = self.repositories.listener_stats.get( session, listener_id=self.listener_id) if not db_ls: LOG.info(_LI("Listener Statistics for Listener %s was not found"), self.listener_id) raise exceptions.NotFound( resource=data_models.ListenerStatistics._name(), id=self.listener_id) return db_ls
def get_one(self, id): """Gets a single load balancer's details.""" session = db_api.get_session() load_balancer = self.repositories.load_balancer.get( session, id=id) if not load_balancer: LOG.info(_LI("Load Balancer %s was not found."), id) raise exceptions.NotFound( resource=data_models.LoadBalancer._name(), id=id) return self._convert_db_to_type(load_balancer, lb_types.LoadBalancerResponse)
def delete(self, availability_zone_profile_id): """Deletes an Availability Zone Profile""" context = pecan_request.context.get('octavia_context') self._auth_validate_action(context, context.project_id, constants.RBAC_DELETE) if availability_zone_profile_id == constants.NIL_UUID: raise exceptions.NotFound(resource='Availability Zone Profile', id=constants.NIL_UUID) # Don't allow it to be deleted if it is in use by an availability zone if self.repositories.availability_zone.count( context.session, availability_zone_profile_id=availability_zone_profile_id) > 0: raise exceptions.ObjectInUse(object='Availability Zone Profile', id=availability_zone_profile_id) try: self.repositories.availability_zone_profile.delete( context.session, id=availability_zone_profile_id) except sa_exception.NoResultFound: raise exceptions.NotFound(resource='Availability Zone Profile', id=availability_zone_profile_id)
def post(self, member): """Creates a pool member on a pool.""" context = pecan.request.context.get('octavia_context') member.project_id = self._get_lb_project_id(context.session, self.load_balancer_id) # Validate member subnet if member.subnet_id and not validate.subnet_exists(member.subnet_id): raise exceptions.NotFound(resource='Subnet', id=member.subnet_id) lock_session = db_api.get_session(autocommit=False) if self.repositories.check_quota_met(context.session, lock_session, data_models.Member, member.project_id): lock_session.rollback() raise exceptions.QuotaException try: member_dict = db_prepare.create_member( member.to_dict(render_unsets=True), self.pool_id) self._test_lb_and_listener_statuses(lock_session) db_member = self.repositories.member.create( lock_session, **member_dict) db_new_member = self._get_db_member(lock_session, db_member.id) lock_session.commit() except oslo_exc.DBDuplicateEntry as de: lock_session.rollback() if ['id'] == de.columns: raise exceptions.IDAlreadyExists() raise exceptions.DuplicateMemberEntry( ip_address=member_dict.get('ip_address'), port=member_dict.get('protocol_port')) except Exception: with excutils.save_and_reraise_exception(): lock_session.rollback() try: LOG.info(_LI("Sending Creation of Member %s to handler"), db_member.id) self.handler.create(db_member) except Exception: for listener_id in self._get_affected_listener_ids( context.session): with excutils.save_and_reraise_exception(reraise=False): self.repositories.listener.update( context.session, listener_id, operating_status=constants.ERROR) return self._convert_db_to_type(db_new_member, member_types.MemberResponse)
def _validate_pool(self, session, lb_id, pool_id, listener_protocol): """Validate pool given exists on same load balancer as listener.""" db_pool = self.repositories.pool.get( session, load_balancer_id=lb_id, id=pool_id) if not db_pool: raise exceptions.NotFound( resource=data_models.Pool._name(), id=pool_id) if (db_pool.protocol == constants.PROTOCOL_UDP and db_pool.protocol != listener_protocol): msg = _("Listeners of type %s can only have pools of " "type UDP.") % constants.PROTOCOL_UDP raise exceptions.ValidationException(detail=msg)
def delete(self, flavor_profile_id): """Deletes a Flavor Profile""" context = pecan_request.context.get('octavia_context') self._auth_validate_action(context, context.project_id, constants.RBAC_DELETE) if flavor_profile_id == constants.NIL_UUID: raise exceptions.NotFound(resource='Flavor profile', id=constants.NIL_UUID) # Don't allow it to be deleted if it is in use by a flavor if self.repositories.flavor.count( context.session, flavor_profile_id=flavor_profile_id) > 0: raise exceptions.ObjectInUse(object='Flavor profile', id=flavor_profile_id) try: self.repositories.flavor_profile.delete(context.session, id=flavor_profile_id) except sa_exception.NoResultFound as e: raise exceptions.NotFound( resource='Flavor profile', id=flavor_profile_id) from e
def delete(self, flavor_id): """Deletes a Flavor""" context = pecan.request.context.get('octavia_context') self._auth_validate_action(context, context.project_id, constants.RBAC_DELETE) try: self.repositories.flavor.delete(context.session, id=flavor_id) # Handle when load balancers still reference this flavor except odb_exceptions.DBReferenceError: raise exceptions.ObjectInUse(object='Flavor', id=flavor_id) except sa_exception.NoResultFound: raise exceptions.NotFound(resource='Flavor', id=flavor_id)