def get_sorts(request, attr_info): """Extract sort_key and sort_dir from request. Return as: [(key1, value1), (key2, value2)] """ attributes.populate_project_info(attr_info) sort_keys = list_args(request, "sort_key") sort_dirs = list_args(request, "sort_dir") if len(sort_keys) != len(sort_dirs): msg = _("The number of sort_keys and sort_dirs must be same") raise exc.HTTPBadRequest(explanation=msg) valid_dirs = [constants.SORT_DIRECTION_ASC, constants.SORT_DIRECTION_DESC] absent_keys = [x for x in sort_keys if x not in attr_info] if absent_keys: msg = _("%s is invalid attribute for sort_keys") % absent_keys raise exc.HTTPBadRequest(explanation=msg) invalid_dirs = [x for x in sort_dirs if x not in valid_dirs] if invalid_dirs: msg = (_("%(invalid_dirs)s is invalid value for sort_dirs, " "valid value is '%(asc)s' and '%(desc)s'") % {'invalid_dirs': invalid_dirs, 'asc': constants.SORT_DIRECTION_ASC, 'desc': constants.SORT_DIRECTION_DESC}) raise exc.HTTPBadRequest(explanation=msg) return list(zip(sort_keys, [x == constants.SORT_DIRECTION_ASC for x in sort_dirs]))
def get_filters_from_dict(data, attr_info, skips=None): """Extracts the filters from a dict of query parameters. Returns a dict of lists for the filters: check=a&check=b&name=Bob& becomes: {'check': [u'a', u'b'], 'name': [u'Bob']} """ attributes.populate_project_info(attr_info) is_empty_string_supported = is_empty_string_filtering_supported() skips = skips or [] res = {} for key, values in data.items(): if key in skips or hasattr(model_base.BASEV2, key): continue values = [ v for v in values if v or (v == "" and is_empty_string_supported) ] key_attr_info = attr_info.get(key, {}) if 'convert_list_to' in key_attr_info: values = key_attr_info['convert_list_to'](values) elif 'convert_to' in key_attr_info: convert_to = key_attr_info['convert_to'] values = [convert_to(v) for v in values] if values: res[key] = values return res
def get_all_quotas(context, resources): """Given a list of resources, retrieve the quotas for the all tenants. :param context: The request context, for access checks. :param resources: A dictionary of the registered resource keys. :return: quotas list of dict of tenant_id:, resourcekey1: resourcekey2: ... """ tenant_default = dict((key, resource.default) for key, resource in resources.items()) all_tenant_quotas = {} for quota in quota_obj.Quota.get_objects(context): tenant_id = quota['project_id'] # avoid setdefault() because only want to copy when actually # required tenant_quota = all_tenant_quotas.get(tenant_id) if tenant_quota is None: tenant_quota = tenant_default.copy() tenant_quota['tenant_id'] = tenant_id attributes.populate_project_info(tenant_quota) all_tenant_quotas[tenant_id] = tenant_quota tenant_quota[quota['resource']] = quota['limit'] # Convert values to a list to as caller expect an indexable iterable, # where python3's dict_values does not support indexing return list(all_tenant_quotas.values())
def prepare_request_body(context, body, is_create, resource, attr_info, allow_bulk=False): """Verifies required attributes are in request body. Also checking that an attribute is only specified if it is allowed for the given operation (create/update). Attribute with default values are considered to be optional. body argument must be the deserialized body. """ collection = resource + "s" if not body: raise webob.exc.HTTPBadRequest(_("Resource body required")) LOG.debug("Request body: %(body)s", {'body': body}) try: if collection in body: if not allow_bulk: raise webob.exc.HTTPBadRequest( _("Bulk operation " "not supported")) if not body[collection]: raise webob.exc.HTTPBadRequest(_("Resources required")) bulk_body = [ Controller.prepare_request_body( context, item if resource in item else {resource: item}, is_create, resource, attr_info, allow_bulk) for item in body[collection] ] return {collection: bulk_body} res_dict = body.get(resource) except (AttributeError, TypeError): msg = _("Body contains invalid data") raise webob.exc.HTTPBadRequest(msg) if res_dict is None: msg = _("Unable to find '%s' in request body") % resource raise webob.exc.HTTPBadRequest(msg) attr_ops = attributes.AttributeInfo(attr_info) attr_ops.populate_project_id(context, res_dict, is_create) attributes.populate_project_info(attr_info) attr_ops.verify_attributes(res_dict) if is_create: # POST attr_ops.fill_post_defaults(res_dict, exc_cls=webob.exc.HTTPBadRequest) else: # PUT for attr, attr_vals in attr_info.items(): if attr in res_dict and not attr_vals['allow_put']: msg = _("Cannot update read-only attribute %s") % attr raise webob.exc.HTTPBadRequest(msg) attr_ops.convert_values(res_dict, exc_cls=webob.exc.HTTPBadRequest) return body
def get_sorts(request, attr_info): """Extract sort_key and sort_dir from request. Return as: [(key1, value1), (key2, value2)] """ attributes.populate_project_info(attr_info) sort_keys = list_args(request, "sort_key") sort_dirs = list_args(request, "sort_dir") if len(sort_keys) != len(sort_dirs): msg = _("The number of sort_keys and sort_dirs must be same") raise exc.HTTPBadRequest(explanation=msg) valid_dirs = [constants.SORT_DIRECTION_ASC, constants.SORT_DIRECTION_DESC] valid_sort_keys = set(attr for attr, schema in attr_info.items() if schema.get('is_sort_key', False)) absent_keys = [x for x in sort_keys if x not in valid_sort_keys] if absent_keys: msg = _("%s is invalid attribute for sort_keys") % absent_keys raise exc.HTTPBadRequest(explanation=msg) invalid_dirs = [x for x in sort_dirs if x not in valid_dirs] if invalid_dirs: msg = (_("%(invalid_dirs)s is invalid value for sort_dirs, " "valid value is '%(asc)s' and '%(desc)s'") % { 'invalid_dirs': invalid_dirs, 'asc': constants.SORT_DIRECTION_ASC, 'desc': constants.SORT_DIRECTION_DESC }) raise exc.HTTPBadRequest(explanation=msg) return list( zip(sort_keys, [x == constants.SORT_DIRECTION_ASC for x in sort_dirs]))
def get_all_quotas(context, resources): """Given a list of resources, retrieve the quotas for the all tenants. :param context: The request context, for access checks. :param resources: A dictionary of the registered resource keys. :return: quotas list of dict of tenant_id:, resourcekey1: resourcekey2: ... """ tenant_default = dict( (key, resource.default) for key, resource in resources.items()) all_tenant_quotas = {} for quota in quota_obj.Quota.get_objects(context): tenant_id = quota['project_id'] # avoid setdefault() because only want to copy when actually # required tenant_quota = all_tenant_quotas.get(tenant_id) if tenant_quota is None: tenant_quota = tenant_default.copy() tenant_quota['tenant_id'] = tenant_id attributes.populate_project_info(tenant_quota) all_tenant_quotas[tenant_id] = tenant_quota tenant_quota[quota['resource']] = quota['limit'] # Convert values to a list to as caller expect an indexable iterable, # where python3's dict_values does not support indexing return list(all_tenant_quotas.values())
def prepare_request_body(context, body, is_create, resource, attr_info, allow_bulk=False): """Verifies required attributes are in request body. Also checking that an attribute is only specified if it is allowed for the given operation (create/update). Attribute with default values are considered to be optional. body argument must be the deserialized body. """ collection = resource + "s" if not body: raise webob.exc.HTTPBadRequest(_("Resource body required")) LOG.debug("Request body: %(body)s", {'body': body}) try: if collection in body: if not allow_bulk: raise webob.exc.HTTPBadRequest(_("Bulk operation " "not supported")) if not body[collection]: raise webob.exc.HTTPBadRequest(_("Resources required")) bulk_body = [ Controller.prepare_request_body( context, item if resource in item else {resource: item}, is_create, resource, attr_info, allow_bulk) for item in body[collection] ] return {collection: bulk_body} res_dict = body.get(resource) except (AttributeError, TypeError): msg = _("Body contains invalid data") raise webob.exc.HTTPBadRequest(msg) if res_dict is None: msg = _("Unable to find '%s' in request body") % resource raise webob.exc.HTTPBadRequest(msg) if not isinstance(res_dict, dict): msg = _("Object '%s' contains invalid data") % resource raise webob.exc.HTTPBadRequest(msg) attr_ops = attributes.AttributeInfo(attr_info) attr_ops.populate_project_id(context, res_dict, is_create) attributes.populate_project_info(attr_info) attr_ops.verify_attributes(res_dict) if is_create: # POST attr_ops.fill_post_defaults( res_dict, exc_cls=webob.exc.HTTPBadRequest) else: # PUT for attr, attr_vals in attr_info.items(): if attr in res_dict and not attr_vals['allow_put']: msg = _("Cannot update read-only attribute %s") % attr raise webob.exc.HTTPBadRequest(msg) attr_ops.convert_values(res_dict, exc_cls=webob.exc.HTTPBadRequest) return body
def normalize_l7parameters(parameters): parameters = converters.convert_none_to_empty_dict(parameters) for key in parameters: if key not in SUPPORTED_L7_PARAMETERS: raise FlowClassifierInvalidL7Parameter( error_message='Unknown key %s.' % key) try: _l7_param_attrs.fill_post_defaults(parameters) attr.populate_project_info(SUPPORTED_L7_PARAMETERS) _l7_param_attrs.convert_values(parameters) except ValueError as error: raise FlowClassifierInvalidL7Parameter(error_message=str(error)) return parameters
def _fixup_res_dict(context, attr_name, res_dict, check_allow_post=True): attr_info = attributes.RESOURCE_ATTRIBUTE_MAP[attr_name] attr_ops = lib_attrs.AttributeInfo(attr_info) try: attr_ops.populate_project_id(context, res_dict, True) lib_attrs.populate_project_info(attr_info) attr_ops.verify_attributes(res_dict) except webob.exc.HTTPBadRequest as e: # convert webob exception into ValueError as these functions are # for internal use. webob exception doesn't make sense. raise ValueError(e.detail) attr_ops.fill_post_defaults(res_dict, check_allow_post=check_allow_post) attr_ops.convert_values(res_dict) return res_dict
def get_collection(context, model, dict_func, filters=None, fields=None, sorts=None, limit=None, marker_obj=None, page_reverse=False): """Get a collection for a said model. :param context: The context to use for the DB session. :param model: The model for the collection. :param dict_func: The function used to build the collection dict. :param filters: The filters to apply. :param fields: The fields to collect. :param sorts: The sort keys to use. :param limit: The limit for the query if applicable. :param marker_obj: The marker object if applicable. :param page_reverse: If reverse paging should be used. :returns: A list of dicts where each dict is an object in the collection. """ query = get_collection_query(context, model, filters=filters, sorts=sorts, limit=limit, marker_obj=marker_obj, page_reverse=page_reverse) items = [ attributes.populate_project_info( dict_func(c, fields) if dict_func else c) for c in query ] if limit and page_reverse: items.reverse() return items
def _fixup_res_dict(context, attr_name, res_dict, check_allow_post=True): # This method is a replacement of _fixup_res_dict which is used in # neutron.plugin.common.utils. All this mock does is insert a uuid # for the id field if one is not found ONLY if running in api_replay_mode. if cfg.CONF.api_replay_mode and 'id' not in res_dict: res_dict['id'] = uuidutils.generate_uuid() attr_info = attributes.RESOURCE_ATTRIBUTE_MAP[attr_name] attr_ops = lib_attrs.AttributeInfo(attr_info) try: attr_ops.populate_project_id(context, res_dict, True) lib_attrs.populate_project_info(attr_info) attr_ops.verify_attributes(res_dict) except webob.exc.HTTPBadRequest as e: # convert webob exception into ValueError as these functions are # for internal use. webob exception doesn't make sense. raise ValueError(e.detail) attr_ops.fill_post_defaults(res_dict, check_allow_post=check_allow_post) attr_ops.convert_values(res_dict) return res_dict
def resource_fields(resource, fields): """Return only the resource items that are in fields. :param resource: A resource dict. :param fields: A list of fields to select from the resource. :returns: A new dict that contains only fields from resource as well as its attribute project info. """ if fields: resource = {key: item for key, item in resource.items() if key in fields} return attributes.populate_project_info(resource)
def get_filters_from_dict(data, attr_info, skips=None, is_filter_validation_supported=False): """Extracts the filters from a dict of query parameters. Returns a dict of lists for the filters: check=a&check=b&name=Bob& becomes: {'check': [u'a', u'b'], 'name': [u'Bob']} """ attributes.populate_project_info(attr_info) is_empty_string_supported = is_empty_string_filtering_supported() skips = skips or [] res = {} invalid_keys = [] check_is_filter = False if is_filter_validation_supported and is_filter_validation_enabled(): check_is_filter = True for key, values in data.items(): if key in skips or hasattr(model_base.BASEV2, key): continue values = [ v for v in values if v or (v == "" and is_empty_string_supported) ] key_attr_info = attr_info.get(key, {}) if check_is_filter and not key_attr_info.get('is_filter'): invalid_keys.append(key) continue if 'convert_list_to' in key_attr_info: values = key_attr_info['convert_list_to'](values) elif 'convert_to' in key_attr_info: convert_to = key_attr_info['convert_to'] values = [convert_to(v) for v in values] if values: res[key] = values if invalid_keys: msg = _("%s is invalid attribute for filtering") % invalid_keys raise exc.HTTPBadRequest(explanation=msg) return res
def resource_fields(resource, fields): """Return only the resource items that are in fields. :param resource: a resource dictionary :type resource: dict :param fields: a list of fields to select from the resource :type fields: list """ if fields: resource = {key: item for key, item in resource.items() if key in fields} return attributes.populate_project_info(resource)
def _fixup_res_dict(context, attr_name, res_dict, check_allow_post=True): # This method is a replacement of _fixup_res_dict which is used in # neutron.plugin.common.utils. All this mock does is insert a uuid # for the id field if one is not found ONLY if running in api_replay_mode. if cfg.CONF.api_replay_mode and 'id' not in res_dict: # exclude gateway ports from this if (attr_name != 'ports' or res_dict.get('device_owner') != 'network:router_gateway'): res_dict['id'] = uuidutils.generate_uuid() attr_info = lib_attrs.RESOURCES[attr_name] attr_ops = lib_attrs.AttributeInfo(attr_info) try: attr_ops.populate_project_id(context, res_dict, True) lib_attrs.populate_project_info(attr_info) attr_ops.verify_attributes(res_dict) except webob.exc.HTTPBadRequest as e: # convert webob exception into ValueError as these functions are # for internal use. webob exception doesn't make sense. raise ValueError(e.detail) attr_ops.fill_post_defaults(res_dict, check_allow_post=check_allow_post) attr_ops.convert_values(res_dict) return res_dict
def get_filters_from_dict(data, attr_info, skips=None, is_filter_validation_supported=False): """Extracts the filters from a dict of query parameters. Returns a dict of lists for the filters: check=a&check=b&name=Bob& becomes: {'check': [u'a', u'b'], 'name': [u'Bob']} """ attributes.populate_project_info(attr_info) is_empty_string_supported = is_empty_string_filtering_supported() skips = skips or [] res = {} invalid_keys = [] check_is_filter = False if is_filter_validation_supported and is_filter_validation_enabled(): check_is_filter = True for key, values in data.items(): if key in skips or hasattr(model_base.BASEV2, key): continue values = [v for v in values if v or (v == "" and is_empty_string_supported)] key_attr_info = attr_info.get(key, {}) if check_is_filter and not key_attr_info.get('is_filter'): invalid_keys.append(key) continue if 'convert_list_to' in key_attr_info: values = key_attr_info['convert_list_to'](values) elif 'convert_to' in key_attr_info: convert_to = key_attr_info['convert_to'] values = [convert_to(v) for v in values] if values: res[key] = values if invalid_keys: msg = _("%s is invalid attribute for filtering") % invalid_keys raise exc.HTTPBadRequest(explanation=msg) return res
def get_collection(context, model, dict_func, filters=None, fields=None, sorts=None, limit=None, marker_obj=None, page_reverse=False): query = get_collection_query(context, model, filters=filters, sorts=sorts, limit=limit, marker_obj=marker_obj, page_reverse=page_reverse) items = [ attributes.populate_project_info( dict_func(c, fields) if dict_func else c) for c in query ] if limit and page_reverse: items.reverse() return items
def test_populate_project_info_ids_match(self): project_id = uuidutils.generate_uuid() attrs_in = {'project_id': project_id, 'tenant_id': project_id} attrs_out = attributes.populate_project_info(attrs_in) self.assertEqual(attrs_in, attrs_out)
def test_populate_project_info_add_tenant(self): attrs_in = {'project_id': uuidutils.generate_uuid()} attrs_out = attributes.populate_project_info(attrs_in) self.assertIn('tenant_id', attrs_out) self.assertEqual(attrs_in['project_id'], attrs_out['tenant_id']) self.assertEqual(2, len(attrs_out))