def request(self, method, url, token=None, args=None, headers=None, accepted_codes=[200, 201, 202, 204]): params = {} if args: # extract filter and fields if 'filters' in args: params = args.pop('filters') if 'fields' in args: params['fields'] = args.pop('fields') args = jsonutils.dumps(args) if not headers: headers = { 'Content-type': 'application/json', 'X-Auth-Token': token } headers['User-Agent'] = OCTAVIA_PROXY_CLIENT url = '{}/{}'.format(self.base_url, str(url)) LOG.debug("url = %s", url) LOG.debug("args = %s", args) LOG.debug("params = %s", str(params)) r = requests.request(method, url, data=args, params=params, headers=headers) LOG.debug("Octavia Response Code: {0}".format(r.status_code)) LOG.debug("Octavia Response Body: {0}".format(r.content)) LOG.debug("Octavia Response Headers: {0}".format(r.headers)) if r.status_code in accepted_codes: if method != 'DELETE': return r.json() elif r.status_code == 413: e = lib_exc.OverQuota() e.msg = str(r.content) raise e elif r.status_code == 409: e = lib_exc.Conflict() e.msg = str(r.content) raise e elif r.status_code == 401: e = lib_exc.NotAuthorized() e.msg = str(r.content) raise e elif r.status_code == 404: e = lib_exc.NotFound() e.msg = str(r.content) raise e elif r.status_code == 400: e = lib_exc.BadRequest(resource="", msg="") e.msg = str(r.content) raise e else: raise loadbalancerv2.DriverError(msg=str(r.content))
def limit_check(self, context, tenant_id, resources, values): """Check simple quota limits. For limits--those quotas for which there is no usage synchronization function--this method checks that a set of proposed values are permitted by the limit restriction. If any of the proposed values is over the defined quota, an OverQuota exception will be raised with the sorted list of the resources which are too high. Otherwise, the method returns nothing. :param context: The request context, for access checks. :param tenant_id: The tenant_id to check the quota. :param resources: A dictionary of the registered resources. :param values: A dictionary of the values to check against the quota. """ # Ensure no value is less than zero unders = [key for key, val in values.items() if val < 0] if unders: raise n_exc.InvalidQuotaValue(unders=sorted(unders)) # Get the applicable quotas quotas = self._get_quotas(context, tenant_id, resources) # Check the quotas and construct a list of the resources that # would be put over limit by the desired values overs = [key for key, val in values.items() if 0 <= quotas[key] < val] if overs: raise exceptions.OverQuota(overs=sorted(overs))
def make_reservation(self, context, project_id, resources, deltas, plugin): resources_over_limit = [] with db_api.CONTEXT_WRITER.using(context): # Filter out unlimited resources. limits = self.get_tenant_quotas(context, resources, project_id) unlimited_resources = set([ resource for (resource, limit) in limits.items() if limit < 0 ]) requested_resources = (set(deltas.keys()) - unlimited_resources) # Delete expired reservations before counting valid ones. This # operation is fast and by calling it before making any # reservation, we ensure the freshness of the reservations. quota_api.remove_expired_reservations(context, tenant_id=project_id) # Count the number of (1) used and (2) reserved resources for this # project_id. If any resource limit is exceeded, raise exception. for resource_name in requested_resources: tracked_resource = resources.get(resource_name) if not tracked_resource: continue used_and_reserved = tracked_resource.count( context, None, project_id, count_db_registers=True) resource_num = deltas[resource_name] if limits[resource_name] < (used_and_reserved + resource_num): resources_over_limit.append(resource_name) if resources_over_limit: raise exceptions.OverQuota(overs=sorted(resources_over_limit)) return quota_api.create_reservation(context, project_id, deltas)
def _resource_create(self, resource_type, obj): create_method = getattr(self._vnc_api, resource_type + '_create') try: try: obj_uuid = create_method(obj) except vnc_exc.RefsExistError: obj.uuid = str(uuid.uuid4()) obj.name += '-' + obj.uuid obj.fq_name[-1] += '-' + obj.uuid obj_uuid = create_method(obj) except (vnc_exc.PermissionDenied, vnc_exc.BadRequest) as e: neutron_exc.BadRequest(resource_type=resource_type, msg=str(e)) except vnc_exc.OverQuota as e: neutron_exc.OverQuota(overs=[resource_type], msg=str(e)) return obj_uuid
def make_reservation(self, context, project_id, resources, deltas, plugin): resources_over_limit = [] with db_api.CONTEXT_WRITER.using(context): # Filter out unlimited resources. limits = self.get_project_quotas(context, resources, project_id) unlimited_resources = set([ resource for (resource, limit) in limits.items() if limit < 0 ]) requested_resources = (set(deltas.keys()) - unlimited_resources) # Count the number of (1) used and (2) reserved resources for this # project_id. If any resource limit is exceeded, raise exception. for resource_name in requested_resources: used_and_reserved = self.get_resource_usage( context, project_id, resources, resource_name) resource_num = deltas[resource_name] if limits[resource_name] < (used_and_reserved + resource_num): resources_over_limit.append(resource_name) if resources_over_limit: raise exceptions.OverQuota(overs=sorted(resources_over_limit)) return quota_api.create_reservation(context, project_id, deltas)
def quota_limit_check(self, context, project_id, resources, deltas): # Ensure no value is less than zero unders = [key for key, val in deltas.items() if val < 0] if unders: raise exceptions.InvalidQuotaValue(unders=sorted(unders)) current_limits = self.get_project_quotas(context, resources, project_id) overs = set() for resource_name, delta in deltas.items(): resource_limit = current_limits.get(resource_name) if resource_limit in (None, quota_api.UNLIMITED_QUOTA): continue resource_usage = self.get_resource_usage(context, project_id, resources, resource_name) if resource_usage is None: continue if resource_usage + delta > resource_limit: overs.add(resource_name) if overs: raise exceptions.OverQuota(overs=sorted(overs))
def make_reservation(self, context, tenant_id, resources, deltas, plugin): # Lock current reservation table # NOTE(salv-orlando): This routine uses DB write locks. # These locks are acquired by the count() method invoked on resources. # Please put your shotguns aside. # A non locking algorithm for handling reservation is feasible, however # it will require two database writes even in cases when there are not # concurrent reservations. # For this reason it might be advisable to handle contention using # this kind of locks and paying the cost of a write set certification # failure when a MySQL Galera cluster is employed. Also, this class of # locks should be ok to use when support for sending "hotspot" writes # to a single node will be available. requested_resources = deltas.keys() with db_api.context_manager.writer.using(context): # get_tenant_quotes needs in input a dictionary mapping resource # name to BaseResosurce instances so that the default quota can be # retrieved current_limits = self.get_tenant_quotas(context, resources, tenant_id) unlimited_resources = set([ resource for (resource, limit) in current_limits.items() if limit < 0 ]) # Do not even bother counting resources and calculating headroom # for resources with unlimited quota LOG.debug( "Resources %s have unlimited quota limit. It is not " "required to calculate headroom ", ",".join(unlimited_resources)) requested_resources = (set(requested_resources) - unlimited_resources) # Gather current usage information # TODO(salv-orlando): calling count() for every resource triggers # multiple queries on quota usage. This should be improved, however # this is not an urgent matter as the REST API currently only # allows allocation of a resource at a time # NOTE: pass plugin too for compatibility with CountableResource # instances current_usages = dict((resource, resources[resource].count( context, plugin, tenant_id, resync_usage=False)) for resource in requested_resources) # Adjust for expired reservations. Apparently it is cheaper than # querying every time for active reservations and counting overall # quantity of resources reserved expired_deltas = quota_api.get_reservations_for_resources( context, tenant_id, requested_resources, expired=True) # Verify that the request can be accepted with current limits resources_over_limit = [] for resource in requested_resources: expired_reservations = expired_deltas.get(resource, 0) total_usage = current_usages[resource] - expired_reservations res_headroom = current_limits[resource] - total_usage LOG.debug( ("Attempting to reserve %(delta)d items for " "resource %(resource)s. Total usage: %(total)d; " "quota limit: %(limit)d; headroom:%(headroom)d"), { 'resource': resource, 'delta': deltas[resource], 'total': total_usage, 'limit': current_limits[resource], 'headroom': res_headroom }) if res_headroom < deltas[resource]: resources_over_limit.append(resource) if expired_reservations: self._handle_expired_reservations(context, tenant_id) if resources_over_limit: raise exceptions.OverQuota(overs=sorted(resources_over_limit)) # Success, store the reservation # TODO(salv-orlando): Make expiration time configurable return quota_api.create_reservation(context, tenant_id, deltas)