def create_bgpvpn_network_association(self, context, bgpvpn_id, network_association): net_assoc = network_association['network_association'] # check net exists net = self._validate_network(context, net_assoc) # check every resource belong to the same tenant bgpvpn = self.get_bgpvpn(context, bgpvpn_id) if net['tenant_id'] != bgpvpn['tenant_id']: msg = 'network doesn\'t belong to the bgpvpn owner' raise n_exc.NotAuthorized(resource='bgpvpn', msg=msg) if net_assoc['tenant_id'] != bgpvpn['tenant_id']: msg = 'network association and bgpvpn should belong to\ the same tenant' raise n_exc.NotAuthorized(resource='bgpvpn', msg=msg) return self.driver.create_net_assoc(context, bgpvpn_id, net_assoc)
def create_pool_health_monitor(self, context, health_monitor, pool_id): """ Associate an health monitor with a pool. """ m = health_monitor['health_monitor'] try: pool = self._api.loadbalancer_pool_read(id=pool_id) except vnc_exc.NoIdError: raise loadbalancer.PoolNotFound(pool_id=pool_id) try: monitor = self._api.loadbalancer_healthmonitor_read(id=m['id']) except vnc_exc.NoIdError: raise loadbalancer.HealthMonitorNotFound(monitor_id=m['id']) if not context.is_admin: tenant_id = str(uuid.UUID(context.tenant_id)) if tenant_id != pool.parent_uuid or \ tenant_id != monitor.parent_uuid: raise n_exc.NotAuthorized() pool_refs = monitor.get_loadbalancer_pool_back_refs() if pool_refs is not None: for ref in pool_refs: if ref['uuid'] == pool_id: raise loadbalancer.PoolMonitorAssociationExists( monitor_id=m['id'], pool_id=pool_id) pool.add_loadbalancer_healthmonitor(monitor) self._api.loadbalancer_pool_update(pool) res = { 'id': monitor.uuid, 'tenant_id': monitor.parent_uuid.replace('-', '') } return res
def get_mac_address_ranges(context): LOG.info("get_mac_address_ranges for tenant %s" % context.tenant_id) if not context.is_admin: raise exceptions.NotAuthorized() ranges = db_api.mac_address_range_find(context) return [v._make_mac_range_dict(m) for m in ranges]
def update_object(self, vip_db, id, v): if 'pool_id' in v and self._get_vip_pool_id(vip_db) != v['pool_id']: try: pool = self._api.loadbalancer_pool_read(id=v['pool_id']) except NoIdError: raise loadbalancer.PoolNotFound(pool_id=v['pool_id']) if vip_db.parent_uuid != pool.parent_uuid: raise n_exc.NotAuthorized() # check that the pool has no vip configured if pool.get_virtual_ip_back_refs(): raise loadbalancer.VipExists(pool_id=pool_obj.uuid) # check that the protocol matches pool_props = pool.get_loadbalancer_pool_properties() vip_props = vip_db.get_virtual_ip_properties() if pool_props.get_protocol() != vip_props.get_protocol(): raise loadbalancer.ProtocolMismatch( vip_proto=vip_props.get_protocol(), pool_proto=pool_props.get_protocol()) # update vip vip_db.set_loadbalancer_pool(pool) return True return False
def _v3_client_init(self): kwargs = {'insecure': self.context.insecure} if self.context.auth_token is not None: kwargs['project_name'] = self.context.tenant kwargs['token'] = self.context.auth_token kwargs['auth_url'] = self.context.auth_url.replace('v2.0', 'v3') kwargs['endpoint'] = kwargs['auth_url'] elif self.context.trust_id is not None: # We got a trust_id, so we use the admin credentials and get a # Token back impersonating the trustor user kwargs.update(self._service_admin_creds(api_version=3)) kwargs['trust_id'] = self.context.trust_id elif self.context.password is not None: kwargs['username'] = self.context.username kwargs['password'] = self.context.password kwargs['project_name'] = self.context.tenant kwargs['project_id'] = self.context.tenant_id kwargs['auth_url'] = self.context.auth_url.replace('v2.0', 'v3') kwargs['endpoint'] = kwargs['auth_url'] else: logger.error("Keystone v3 API connection failed, no password or " "auth_token!") raise exceptions.NotAuthorized() client = kc_v3.Client(**kwargs) # Have to explicitly authenticate() or client.auth_ref is None client.authenticate() return client
def diagnose_subnet(context, id, fields): if not context.is_admin: raise exceptions.NotAuthorized() if id == "*": return {'subnets': get_subnets(context, filters={})} return {'subnets': get_subnet(context, id)}
def create(self, context, member): """ Create a loadbalancer_member object. """ m = member['member'] try: pool = self._api.loadbalancer_pool_read(id=m['pool_id']) except NoIdError: raise loadbalancer.PoolNotFound(pool_id=m['pool_id']) tenant_id = self._get_tenant_id_for_create(context, m) if str(uuid.UUID(tenant_id)) != pool.parent_uuid: raise n_exc.NotAuthorized() obj_uuid = uuidutils.generate_uuid() props = self.make_properties(m) id_perms = IdPermsType(enable=True) member_db = LoadbalancerMember(obj_uuid, pool, loadbalancer_member_properties=props, id_perms=id_perms) member_db.uuid = obj_uuid self._api.loadbalancer_member_create(member_db) return self.make_dict(member_db)
def create(self, context, listener): l = listener['listener'] tenant_id = self._get_tenant_id_for_create(context, l) project = self._project_read(project_id=tenant_id) if l['loadbalancer_id']: try: lb = self._api.loadbalancer_read(id=l['loadbalancer_id']) except NoIdError: raise loadbalancer.EntityNotFound(id=v['loadbalancer_id']) project_id = lb.parent_uuid if str(uuid.UUID(tenant_id)) != project_id: raise n_exc.NotAuthorized() else: lb = None obj_uuid = uuidutils.generate_uuid() name = self._get_resource_name('listener', project, l['name'], obj_uuid) id_perms = IdPermsType(enable=True, description=l['description']) ll = LoadbalancerListener(name, project, id_perms=id_perms, display_name=l['name']) ll.uuid = obj_uuid if lb: ll.set_loadbalancer(lb) props = self.make_properties(l) ll.set_loadbalancer_listener_properties(props) self._api.loadbalancer_listener_create(ll) return self.make_dict(ll)
def get_segment_allocation_ranges(context, **filters): LOG.info("get_segment_allocation_ranges for tenant %s" % context.tenant_id) if not context.is_admin: raise exceptions.NotAuthorized() sa_ranges = db_api.segment_allocation_range_find( context, scope=db_api.ALL, **filters) return [v._make_segment_allocation_range_dict(m) for m in sa_ranges]
def create_bgpvpn_router_association(self, context, bgpvpn_id, router_association): router_assoc = router_association['router_association'] router = self._validate_router(context, router_assoc) bgpvpn = self.get_bgpvpn(context, bgpvpn_id) if not bgpvpn['type'] == constants.BGPVPN_L3: msg = ("Router associations require the bgpvpn to be of type %s" % constants.BGPVPN_L3) raise n_exc.BadRequest(resource='bgpvpn', msg=msg) if not router['tenant_id'] == bgpvpn['tenant_id']: msg = "router doesn't belong to the bgpvpn owner" raise n_exc.NotAuthorized(resource='bgpvpn', msg=msg) if not (router_assoc['tenant_id'] == bgpvpn['tenant_id']): msg = "router association and bgpvpn should " \ "belong to the same tenant" raise n_exc.NotAuthorized(resource='bgpvpn', msg=msg) return self.driver.create_router_assoc(context, bgpvpn_id, router_assoc)
def _v2_client_init(self): kwargs = { 'auth_url': self.context.auth_url, 'insecure': self.context.insecure } auth_kwargs = {} # Note try trust_id first, as we can't reuse auth_token in that case if self.context.trust_id is not None: # We got a trust_id, so we use the admin credentials # to authenticate, then re-scope the token to the # trust impersonating the trustor user. # Note that this currently requires the trustor tenant_id # to be passed to the authenticate(), unlike the v3 call kwargs.update(self._service_admin_creds(api_version=2)) auth_kwargs['trust_id'] = self.context.trust_id auth_kwargs['tenant_id'] = self.context.tenant_id elif self.context.auth_token is not None: kwargs['tenant_name'] = self.context.tenant kwargs['token'] = self.context.auth_token elif self.context.password is not None: kwargs['username'] = self.context.username kwargs['password'] = self.context.password kwargs['tenant_name'] = self.context.tenant kwargs['tenant_id'] = self.context.tenant_id else: logger.error("Keystone v2 API connection failed, no password or " "auth_token!") raise exceptions.NotAuthorized() client_v2 = kc.Client(**kwargs) client_v2.authenticate(**auth_kwargs) # If we are authenticating with a trust auth_kwargs are set, so set # the context auth_token with the re-scoped trust token if auth_kwargs: # Sanity check if not client_v2.auth_ref.trust_scoped: logger.error("v2 trust token re-scoping failed!") raise exceptions.NotAuthorized() # All OK so update the context with the token self.context.auth_token = client_v2.auth_ref.auth_token self.context.auth_url = kwargs.get('auth_url') return client_v2
def get_ports(context, limit=None, sorts=None, marker=None, page_reverse=False, filters=None, fields=None): """Retrieve a list of ports. The contents of the list depends on the identity of the user making the request (as indicated by the context) as well as any filters. : param context: neutron api request context : param filters: a dictionary with keys that are valid keys for a port as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. Values in this dictionary are an iterable containing values that will be used for an exact match comparison for that value. Each result returned by this function will have matched one of the values for each key in filters. : param fields: a list of strings that are valid keys in a port dictionary as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. Only these fields will be returned. """ LOG.info("get_ports for tenant %s filters %s fields %s" % (context.tenant_id, filters, fields)) if filters is None: filters = {} if "ip_address" in filters: if not context.is_admin: raise exceptions.NotAuthorized() ips = [] try: ips = [netaddr.IPAddress(ip) for ip in filters.pop("ip_address")] except netaddr.AddrFormatError: raise exceptions.InvalidInput( error_message="Invalid format provided for ip_address") query = db_api.port_find_by_ip_address(context, ip_address=ips, scope=db_api.ALL, **filters) ports = [] for ip in query: ports.extend(ip.ports) else: ports = db_api.port_find(context, limit, sorts, marker, fields=fields, join_security_groups=True, **filters) return v._make_ports_list(ports, fields)
def ping_agent(self, request, id, body=None): context = request.context if not context.is_admin: raise qexception.NotAuthorized() host = body['agent']['host'] topic = body['agent']['topic'] if topic == topics.LOADBALANCER_AGENT: x = helo_rpc_agent_api.HeloAgentNotifyAPI(version='2.0') else: x = helo_rpc_agent_api.HeloAgentNotifyAPI() return x.helo_agent_host(context, host, topic)
def _validate(self, context, tenant_id): """Validate and return the tenant to be associated to the topology.""" if tenant_id == 'None': # NOTE(HenryG): the client might be sending us astray by # passing no tenant; this is really meant to be the tenant # issuing the request, therefore let's get it from the context tenant_id = context.tenant_id if not context.is_admin and tenant_id != context.tenant_id: raise n_exc.NotAuthorized() return tenant_id
def update_vip(self, context, id, vip): v = vip['vip'] sess_persist = v.pop('session_persistence', None) with context.session.begin(subtransactions=True): vip_db = self._get_resource(context, Vip, id) self.assert_modification_allowed(vip_db) if sess_persist: self._update_vip_session_persistence(context, id, sess_persist) else: self._delete_session_persistence(context, id) if v: try: # in case new pool already has a vip # update will raise integrity error at first query old_pool_id = vip_db['pool_id'] vip_db.update(v) # If the pool_id is changed, we need to update # the associated pools if 'pool_id' in v: new_pool = self._get_resource(context, Pool, v['pool_id']) self.assert_modification_allowed(new_pool) # check that the pool matches the tenant_id if new_pool['tenant_id'] != vip_db['tenant_id']: raise n_exc.NotAuthorized() # validate that the pool has same protocol if new_pool['protocol'] != vip_db['protocol']: raise loadbalancer.ProtocolMismatch( vip_proto=vip_db['protocol'], pool_proto=new_pool['protocol']) if new_pool['status'] == constants.PENDING_DELETE: raise loadbalancer.StateInvalid( state=new_pool['status'], id=new_pool['id']) if old_pool_id: old_pool = self._get_resource( context, Pool, old_pool_id ) old_pool['vip_id'] = None new_pool['vip_id'] = vip_db['id'] except exception.DBDuplicateEntry: raise loadbalancer.VipExists(pool_id=v['pool_id']) return self._make_vip_dict(vip_db)
def diagnose_port(context, id, fields): if not context.is_admin: raise exceptions.NotAuthorized() if id == "*": return {'ports': [_diag_port(context, port, fields) for port in db_api.port_find(context).all()]} db_port = db_api.port_find(context, id=id, scope=db_api.ONE) if not db_port: raise exceptions.PortNotFound(port_id=id, net_id='') port = _diag_port(context, db_port, fields) return {'ports': port}
def create_vip(self, context, vip): v = vip['vip'] tenant_id = self._get_tenant_id_for_create(context, v) with context.session.begin(subtransactions=True): if v['pool_id']: pool = self._get_resource(context, Pool, v['pool_id']) # validate that the pool has same tenant if pool['tenant_id'] != tenant_id: raise n_exc.NotAuthorized() # validate that the pool has same protocol if pool['protocol'] != v['protocol']: raise loadbalancer.ProtocolMismatch( vip_proto=v['protocol'], pool_proto=pool['protocol']) if pool['status'] == constants.PENDING_DELETE: raise loadbalancer.StateInvalid(state=pool['status'], id=pool['id']) else: pool = None vip_db = Vip(id=uuidutils.generate_uuid(), tenant_id=tenant_id, name=v['name'], description=v['description'], port_id=None, protocol_port=v['protocol_port'], protocol=v['protocol'], pool_id=v['pool_id'], connection_limit=v['connection_limit'], admin_state_up=v['admin_state_up'], status=constants.PENDING_CREATE) session_info = v['session_persistence'] if session_info: s_p = self._create_session_persistence_db( session_info, vip_db['id']) vip_db.session_persistence = s_p try: context.session.add(vip_db) context.session.flush() except exception.DBDuplicateEntry: raise loadbalancer.VipExists(pool_id=v['pool_id']) # create a port to reserve address for IPAM self._create_port_for_vip(context, vip_db, v['subnet_id'], v.get('address')) if pool: pool['vip_id'] = vip_db['id'] return self._make_vip_dict(vip_db)
def create_mac_address_range(context, mac_range): LOG.info("create_mac_address_range for tenant %s" % context.tenant_id) if not context.is_admin: raise exceptions.NotAuthorized() cidr = mac_range["mac_address_range"]["cidr"] cidr, first_address, last_address = _to_mac_range(cidr) with context.session.begin(): new_range = db_api.mac_address_range_create( context, cidr=cidr, first_address=first_address, last_address=last_address, next_auto_assign_mac=first_address) return v._make_mac_range_dict(new_range)
def get_fip_usage(self, request, id, **kwargs): context = request.context if not context.is_admin: raise qexception.NotAuthorized() router = self._get_service_plugin(constants.L3_ROUTER_NAT) core_plugin = manager.NeutronManager.get_plugin() nets = core_plugin.get_networks(context, filters={"router:external": [True]}) results = [] for net in nets: subnets = core_plugin.get_subnets( context, filters={"network_id": [net['id']]}) for subnet in subnets: if (subnet['name'] and subnet['name'].startswith("ext_shadow_subnet")): continue fips = router.get_floatingips( context, filters={"floating_subnet_id": [subnet['id']]}) fip_ips = [] fip_map = {} for fip in fips: fip_ips.append(fip['floating_ip_address']) fip_map[fip['floating_ip_address']] = fip ipcidr = subnet['cidr'] ip = netaddr.IPNetwork(ipcidr) num_ips = len(ip) allocation_pools = subnet['allocation_pools'] for index in range(num_ips): anyallo = [] for allo in allocation_pools: start = netaddr.IPAddress(allo['start']).value end = netaddr.IPAddress(allo['end']).value anyallo.append(start <= ip[index].value <= end) if any(anyallo): if str(ip[index]) in fip_ips: tenant_id = fip_map[str(ip[index])]['tenant_id'] results.append({ "subnet_id": subnet['id'], "subnet_name": subnet['name'], "tenant_id": tenant_id, "fip": str(ip[index]), "used": "yes" }) else: results.append({ "subnet_id": subnet['id'], "fip": str(ip[index]), "subnet_name": subnet['name'], "tenant_id": "", "used": "no" }) return {"fip_usages": results}
def delete(self, context, id): if not context.is_admin: try: obj = self.resource_read(id=id) except NoIdError: raise self.get_exception_notfound(id=id) if context.tenant_id != obj.parent_uuid: raise n_exc.NotAuthorized() # TODO: possible exceptions: RefsExistError try: self.resource_delete(id=id) except NoIdError: raise self.get_exception_notfound(id=id)
def create_segment_allocation_range(context, sa_range): LOG.info("create_segment_allocation_range for tenant %s" % context.tenant_id) if not context.is_admin: raise exceptions.NotAuthorized() sa_range = sa_range.get("segment_allocation_range") if not sa_range: raise exceptions.BadRequest(resource="segment_allocation_range", msg=("segment_allocation_range not in " "request body.")) # TODO(morgabra) Figure out how to get the api extension to validate this # for us. # parse required fields for k in ["first_id", "last_id", "segment_id", "segment_type"]: sa_range[k] = sa_range.get(k, None) if sa_range[k] is None: raise exceptions.BadRequest( resource="segment_allocation_range", msg=("Missing required key %s in request body." % (k))) # parse optional fields for k in ["do_not_use"]: sa_range[k] = sa_range.get(k, None) # use the segment registry to validate and create/populate the range if not SA_REGISTRY.is_valid_strategy(sa_range["segment_type"]): raise exceptions.BadRequest( resource="segment_allocation_range", msg=("Unknown segment type '%s'" % (k))) strategy = SA_REGISTRY.get_strategy(sa_range["segment_type"]) # Create the new range with context.session.begin(): new_range = strategy.create_range(context, sa_range) # Bulk-populate the range, this could take a while for huge ranges # (millions) so we do this in chunks outside the transaction. That # means we need to rollback the range creation if it fails for # whatever reason (and it will cascade delete any added allocations) try: strategy.populate_range(context, new_range) except Exception: LOG.exception("Failed to populate segment allocation range.") delete_segment_allocation_range(context, new_range["id"]) raise return v._make_segment_allocation_range_dict(new_range)
def create(self, context, vip): """ Create a VIP. """ v = vip['vip'] tenant_id = self._get_tenant_id_for_create(context, v) project = self._project_read(project_id=tenant_id) if v['pool_id']: try: pool = self._api.loadbalancer_pool_read(id=v['pool_id']) except NoIdError: raise loadbalancer.PoolNotFound(pool_id=v['pool_id']) project_id = pool.parent_uuid if str(uuid.UUID(tenant_id)) != project_id: raise n_exc.NotAuthorized() protocol = pool.get_loadbalancer_pool_properties().get_protocol() if protocol != v['protocol']: raise loadbalancer.ProtocolMismatch(vip_proto=v['protocol'], pool_proto=protocol) if pool.get_virtual_ip_back_refs(): raise loadbalancer.VipExists(pool_id=v['pool_id']) else: pool = None obj_uuid = uuidutils.generate_uuid() name = self._get_resource_name('virtual-ip', project, v['name'], obj_uuid) id_perms = IdPermsType(enable=True, description=v['description']) vip = VirtualIp(name, project, id_perms=id_perms, display_name=v['name']) vip.uuid = obj_uuid if pool: vip.set_loadbalancer_pool(pool) vmi, vip_address = self._create_virtual_interface( project, obj_uuid, v['subnet_id'], v.get('address')) vip.set_virtual_machine_interface(vmi) props = self.make_properties(v) props.set_address(vip_address) vip.set_virtual_ip_properties(props) self._api.virtual_ip_create(vip) return self.make_dict(vip)
def diagnose_network(context, id, fields): if not context.is_admin: raise exceptions.NotAuthorized() if id == "*": return { 'networks': [ _diag_network(context, net, fields) for net in db_api.network_find(context, scope=db_api.ALL) ] } db_net = db_api.network_find(context, id=id, scope=db_api.ONE) if not db_net: raise exceptions.NetworkNotFound(net_id=id) net = _diag_network(context, db_net, fields) return {'networks': net}
def update_object(self, vip_db, id, v): if 'pool_id' in v and self._get_vip_pool_id(vip_db) != v['pool_id']: try: pool = self._api.loadbalancer_pool_read(id=v['pool_id']) except NoIdError: raise loadbalancer.PoolNotFound(pool_id=v['pool_id']) if vip_db.parent_uuid != pool.parent_uuid: raise n_exc.NotAuthorized() # TODO: check that the pool has no vip configured # TODO: check that the protocol matches # TODO: check that the pool is in valid state # TODO: check that the provider is the same. vip_db.set_localbalancer_pool(pool) return True return False
def _allocate_ips(fixed_ips, net, port_id, segment_id, mac): fixed_ip_kwargs = {} if fixed_ips: if STRATEGY.is_parent_network(net_id) and not context.is_admin: raise exceptions.NotAuthorized() ips, subnets = split_and_validate_requested_subnets(context, net_id, segment_id, fixed_ips) fixed_ip_kwargs["ip_addresses"] = ips fixed_ip_kwargs["subnets"] = subnets ipam_driver.allocate_ip_address( context, addresses, net["id"], port_id, CONF.QUARK.ipam_reuse_after, segment_id=segment_id, mac_address=mac, **fixed_ip_kwargs)
def create(self, context, vip): """ Create a VIP. """ v = vip['vip'] tenant_id = self._get_tenant_id_for_create(context, v) project = self._project_read(project_id=tenant_id) if v['pool_id']: try: pool = self._api.loadbalancer_pool_read(id=v['pool_id']) except NoIdError: raise loadbalancer.PoolNotFound(pool_id=v['pool_id']) project_id = pool.parent_uuid if tenant_id != project_id: raise n_exc.NotAuthorized() # TODO: check that the pool has no vip configured # if pool.protocol != v['protocol']: # raise loadbalancer.ProtocolMismatch( # vip_proto=v['protocol'], pool_proto=pool.protocol) else: pool = None uuid = uuidutils.generate_uuid() name = self._get_resource_name('virtual-ip', project, v['name'], uuid) props = self.make_properties(v) id_perms = IdPermsType(uuid=uuid, enable=True, description=v['description']) vip = VirtualIp(name, project, virtual_ip_properties=props, id_perms=id_perms, display_name=v['name']) vip.uuid = uuid if pool: vip.set_loadbalancer_pool(pool) vmi = self._create_virtual_interface(project, uuid, v['subnet_id'], v.get('address')) vip.set_virtual_machine_interface(vmi) self._api.virtual_ip_create(vip) return self.make_dict(vip)
def delete_mac_address_range(context, id): """Delete a mac_address_range. : param context: neutron api request context : param id: UUID representing the mac_address_range to delete. """ LOG.info("delete_mac_address_range %s for tenant %s" % (id, context.tenant_id)) if not context.is_admin: raise exceptions.NotAuthorized() with context.session.begin(): mar = db_api.mac_address_range_find(context, id=id, scope=db_api.ONE) if not mar: raise quark_exceptions.MacAddressRangeNotFound( mac_address_range_id=id) _delete_mac_address_range(context, mar)
def delete(self, context, id): if not context.is_admin: try: obj = self.resource_read(id=id) except NoIdError: raise self.get_exception_notfound(id=id) tenant_id = str(uuid.UUID(context.tenant_id)) project_id = self._get_object_tenant_id(obj) if tenant_id != project_id: raise n_exc.NotAuthorized() try: self.resource_delete(id=id) except NoIdError: raise self.get_exception_notfound(id=id) except RefsExistError: raise self.get_exception_inuse(id=id)
def delete_segment_allocation_range(context, sa_id): """Delete a segment_allocation_range. : param context: neutron api request context : param id: UUID representing the segment_allocation_range to delete. """ LOG.info("delete_segment_allocation_range %s for tenant %s" % (sa_id, context.tenant_id)) if not context.is_admin: raise exceptions.NotAuthorized() with context.session.begin(): sa_range = db_api.segment_allocation_range_find( context, id=sa_id, scope=db_api.ONE) if not sa_range: raise quark_exceptions.SegmentAllocationRangeNotFound( segment_allocation_range_id=sa_id) _delete_segment_allocation_range(context, sa_range)
def get_segment_allocation_range(context, id, fields=None): LOG.info("get_segment_allocation_range %s for tenant %s fields %s" % (id, context.tenant_id, fields)) if not context.is_admin: raise exceptions.NotAuthorized() sa_range = db_api.segment_allocation_range_find( context, id=id, scope=db_api.ONE) if not sa_range: raise quark_exceptions.SegmentAllocationRangeNotFound( segment_allocation_range_id=id) # Count up allocations so we can calculate how many are free. allocs = db_api.segment_allocation_find( context, segment_allocation_range_id=sa_range["id"], deallocated=False).count() return v._make_segment_allocation_range_dict( sa_range, allocations=allocs)