Unified limit update APIs Refactor
According to the API-WG's suggestion, the update registered limit/project limit APIs should be refactored as: 1. Change PUT to PATCH 2. Remove batch update limits support for PATCH Closes-Bug: #1754184 Change-Id: I1102166ab425a55d8eaf85c75d8fd3a7dfbaceb6
This commit is contained in:
parent
0e24f91075
commit
b385864c5d
@ -28,13 +28,13 @@ identity:delete_endpoint DELETE /v3/endpoints/
|
||||
identity:get_registered_limit GET /v3/registered_limits/{registered_limit_id}
|
||||
identity:list_registered_limits GET /v3/registered_limits
|
||||
identity:create_registered_limits POST /v3/registered_limits
|
||||
identity:update_registered_limits PUT /v3/registered_limits
|
||||
identity:update_registered_limit PATCH /v3/registered_limits/{registered_limit_id}
|
||||
identity:delete_registered_limit DELETE /v3/registered_limits/{registered_limit_id}
|
||||
|
||||
identity:get_limit GET /v3/limits/{limit_id}
|
||||
identity:list_limits GET /v3/limits
|
||||
identity:create_limits POST /v3/limits
|
||||
identity:update_limits PUT /v3/limits
|
||||
identity:update_limit PATCH /v3/limits/{limit_id}
|
||||
identity:delete_limit DELETE /v3/limits/{limit_id}
|
||||
|
||||
identity:get_domain GET /v3/domains/{domain_id}
|
||||
|
@ -31,13 +31,13 @@
|
||||
"identity:get_registered_limit": "",
|
||||
"identity:list_registered_limits": "",
|
||||
"identity:create_registered_limits": "rule:admin_required",
|
||||
"identity:update_registered_limits": "rule:admin_required",
|
||||
"identity:update_registered_limit": "rule:admin_required",
|
||||
"identity:delete_registered_limit": "rule:admin_required",
|
||||
|
||||
"identity:get_limit": "",
|
||||
"identity:list_limits": "",
|
||||
"identity:create_limits": "rule:admin_required",
|
||||
"identity:update_limits": "rule:admin_required",
|
||||
"identity:update_limit": "rule:admin_required",
|
||||
"identity:delete_limit": "rule:admin_required",
|
||||
|
||||
"identity:get_domain": "rule:cloud_admin or rule:admin_and_matching_domain_id or token.project.domain.id:%(target.domain.id)s",
|
||||
|
@ -47,12 +47,12 @@ limit_policies = [
|
||||
operations=[{'path': '/v3/limits',
|
||||
'method': 'POST'}]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.IDENTITY % 'update_limits',
|
||||
name=base.IDENTITY % 'update_limit',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
scope_types=['system'],
|
||||
description='Update limits.',
|
||||
description='Update limit.',
|
||||
operations=[{'path': '/v3/limits/{limit_id}',
|
||||
'method': 'PUT'}]),
|
||||
'method': 'PATCH'}]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.IDENTITY % 'delete_limit',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
|
@ -47,12 +47,12 @@ registered_limit_policies = [
|
||||
operations=[{'path': '/v3/registered_limits',
|
||||
'method': 'POST'}]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.IDENTITY % 'update_registered_limits',
|
||||
name=base.IDENTITY % 'update_registered_limit',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
scope_types=['system'],
|
||||
description='Update registered limits.',
|
||||
description='Update registered limit.',
|
||||
operations=[{'path': '/v3/registered_limits/{registered_limit_id}',
|
||||
'method': 'PUT'}]),
|
||||
'method': 'PATCH'}]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.IDENTITY % 'delete_registered_limit',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
|
@ -47,13 +47,13 @@ class UnifiedLimitDriverBase(object):
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_registered_limits(self, registered_limits):
|
||||
def update_registered_limit(self, registered_limit_id, registered_limit):
|
||||
"""Update existing registered limits.
|
||||
|
||||
:param registered_limits: a list of dictionaries representing limits to
|
||||
update.
|
||||
|
||||
:returns: all the registered limits.
|
||||
:param registered_limit_id: the id of the registered limit.
|
||||
:param registered_limit: a dict containing the registered limit
|
||||
attributes to update.
|
||||
:returns: the updated registered limit.
|
||||
:raises keystone.exception.RegisteredLimitNotFound: If registered limit
|
||||
doesn't exist.
|
||||
:raises keystone.exception.Conflict: If update to a duplicate
|
||||
@ -115,12 +115,13 @@ class UnifiedLimitDriverBase(object):
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_limits(self, limits):
|
||||
def update_limit(self, limit_id, limit):
|
||||
"""Update existing limits.
|
||||
|
||||
:param limits: a list of dictionaries representing limits to update.
|
||||
:param limit_id: the id of the limit.
|
||||
:param limit: a dict containing the limit attributes to update.
|
||||
|
||||
:returns: all the limits.
|
||||
:returns: the updated limit.
|
||||
:raises keystone.exception.LimitNotFound: If limit doesn't
|
||||
exist.
|
||||
:raises keystone.exception.Conflict: If update to a duplicate limit.
|
||||
|
@ -149,34 +149,23 @@ class UnifiedLimit(base.UnifiedLimitDriverBase):
|
||||
return new_registered_limits
|
||||
|
||||
@sql.handle_conflicts(conflict_type='registered_limit')
|
||||
def update_registered_limits(self, registered_limits):
|
||||
def update_registered_limit(self, registered_limit_id, registered_limit):
|
||||
try:
|
||||
with sql.session_for_write() as session:
|
||||
for registered_limit in registered_limits:
|
||||
ref = self._get_registered_limit(session,
|
||||
registered_limit['id'])
|
||||
if not ref.region_id:
|
||||
self._check_referenced_limit_without_region(ref)
|
||||
old_dict = ref.to_dict()
|
||||
old_dict.update(registered_limit)
|
||||
new_registered_limit = RegisteredLimitModel.from_dict(
|
||||
old_dict)
|
||||
for attr in RegisteredLimitModel.attributes:
|
||||
if attr != 'id':
|
||||
setattr(ref, attr, getattr(new_registered_limit,
|
||||
attr))
|
||||
except db_exception.DBReferenceError as e:
|
||||
try:
|
||||
reg_id = e.inner_exception.params['registered_limit_id']
|
||||
except (TypeError, KeyError):
|
||||
# TODO(wxy): For SQLite, the registered_limit_id is not
|
||||
# contained in the error message. We should find a way to
|
||||
# handle it, maybe to improve the message in oslo.db.
|
||||
error_message = _("Unable to update the registered limits "
|
||||
"because there are project limits "
|
||||
"associated with it.")
|
||||
raise exception.RegisteredLimitError(message=error_message)
|
||||
raise exception.RegisteredLimitError(id=reg_id)
|
||||
ref = self._get_registered_limit(session, registered_limit_id)
|
||||
if not ref.region_id:
|
||||
self._check_referenced_limit_without_region(ref)
|
||||
old_dict = ref.to_dict()
|
||||
old_dict.update(registered_limit)
|
||||
new_registered_limit = RegisteredLimitModel.from_dict(
|
||||
old_dict)
|
||||
for attr in registered_limit:
|
||||
if attr != 'id':
|
||||
setattr(ref, attr, getattr(new_registered_limit,
|
||||
attr))
|
||||
return ref.to_dict()
|
||||
except db_exception.DBReferenceError:
|
||||
raise exception.RegisteredLimitError(id=registered_limit_id)
|
||||
|
||||
@driver_hints.truncated
|
||||
def list_registered_limits(self, hints):
|
||||
@ -226,15 +215,15 @@ class UnifiedLimit(base.UnifiedLimitDriverBase):
|
||||
raise exception.NoLimitReference()
|
||||
|
||||
@sql.handle_conflicts(conflict_type='limit')
|
||||
def update_limits(self, limits):
|
||||
def update_limit(self, limit_id, limit):
|
||||
with sql.session_for_write() as session:
|
||||
for limit in limits:
|
||||
ref = self._get_limit(session, limit['id'])
|
||||
old_dict = ref.to_dict()
|
||||
old_dict.update(limit)
|
||||
new_limit = LimitModel.from_dict(old_dict)
|
||||
ref.resource_limit = new_limit.resource_limit
|
||||
ref.description = new_limit.description
|
||||
ref = self._get_limit(session, limit_id)
|
||||
old_dict = ref.to_dict()
|
||||
old_dict.update(limit)
|
||||
new_limit = LimitModel.from_dict(old_dict)
|
||||
ref.resource_limit = new_limit.resource_limit
|
||||
ref.description = new_limit.description
|
||||
return ref.to_dict()
|
||||
|
||||
@driver_hints.truncated
|
||||
def list_limits(self, hints):
|
||||
|
@ -37,39 +37,37 @@ class RegisteredLimitV3(controller.V3Controller):
|
||||
registered_limits)
|
||||
registered_limits = [self._assign_unique_id(self._normalize_dict(
|
||||
registered_limit)) for registered_limit in registered_limits]
|
||||
refs = self.unified_limit_api.create_registered_limits(
|
||||
refs = PROVIDERS.unified_limit_api.create_registered_limits(
|
||||
registered_limits)
|
||||
refs = RegisteredLimitV3.wrap_collection(request.context_dict, refs)
|
||||
refs.pop("links")
|
||||
return refs
|
||||
|
||||
@controller.protected()
|
||||
def update_registered_limits(self, request, registered_limits):
|
||||
def update_registered_limit(self, request, registered_limit_id,
|
||||
registered_limit):
|
||||
validation.lazy_validate(schema.registered_limit_update,
|
||||
registered_limits)
|
||||
refs = self.unified_limit_api.update_registered_limits(
|
||||
[self._normalize_dict(registered_limit) for registered_limit in
|
||||
registered_limits])
|
||||
refs = RegisteredLimitV3.wrap_collection(request.context_dict, refs)
|
||||
refs.pop("links")
|
||||
return refs
|
||||
registered_limit)
|
||||
ref = PROVIDERS.unified_limit_api.update_registered_limit(
|
||||
registered_limit_id, registered_limit)
|
||||
return RegisteredLimitV3.wrap_member(request.context_dict, ref)
|
||||
|
||||
@controller.filterprotected('service_id', 'region_id', 'resource_name')
|
||||
def list_registered_limits(self, request, filters):
|
||||
hints = RegisteredLimitV3.build_driver_hints(request, filters)
|
||||
refs = self.unified_limit_api.list_registered_limits(hints)
|
||||
refs = PROVIDERS.unified_limit_api.list_registered_limits(hints)
|
||||
return RegisteredLimitV3.wrap_collection(request.context_dict, refs,
|
||||
hints=hints)
|
||||
|
||||
@controller.protected()
|
||||
def get_registered_limit(self, request, registered_limit_id):
|
||||
ref = self.unified_limit_api.get_registered_limit(
|
||||
ref = PROVIDERS.unified_limit_api.get_registered_limit(
|
||||
registered_limit_id)
|
||||
return RegisteredLimitV3.wrap_member(request.context_dict, ref)
|
||||
|
||||
@controller.protected()
|
||||
def delete_registered_limit(self, request, registered_limit_id):
|
||||
return self.unified_limit_api.delete_registered_limit(
|
||||
return PROVIDERS.unified_limit_api.delete_registered_limit(
|
||||
registered_limit_id)
|
||||
|
||||
|
||||
@ -92,13 +90,11 @@ class LimitV3(controller.V3Controller):
|
||||
return refs
|
||||
|
||||
@controller.protected()
|
||||
def update_limits(self, request, limits):
|
||||
validation.lazy_validate(schema.limit_update, limits)
|
||||
refs = PROVIDERS.unified_limit_api.update_limits(
|
||||
[self._normalize_dict(limit) for limit in limits])
|
||||
refs = LimitV3.wrap_collection(request.context_dict, refs)
|
||||
refs.pop("links")
|
||||
return refs
|
||||
def update_limit(self, request, limit_id, limit):
|
||||
validation.lazy_validate(schema.limit_update, limit)
|
||||
ref = PROVIDERS.unified_limit_api.update_limit(
|
||||
limit_id, limit)
|
||||
return LimitV3.wrap_member(request.context_dict, ref)
|
||||
|
||||
@controller.filterprotected('service_id', 'region_id', 'resource_name')
|
||||
def list_limits(self, request, filters):
|
||||
|
@ -61,13 +61,13 @@ class Manager(manager.Manager):
|
||||
self._assert_resource_exist(registered_limit, 'registered_limit')
|
||||
return self.driver.create_registered_limits(registered_limits)
|
||||
|
||||
def update_registered_limits(self, registered_limits):
|
||||
for registered_limit in registered_limits:
|
||||
self._assert_resource_exist(registered_limit, 'registered_limit')
|
||||
self.driver.update_registered_limits(registered_limits)
|
||||
for registered_limit in registered_limits:
|
||||
self.get_registered_limit.invalidate(self, registered_limit['id'])
|
||||
return self.list_registered_limits()
|
||||
def update_registered_limit(self, registered_limit_id, registered_limit):
|
||||
self._assert_resource_exist(registered_limit, 'registered_limit')
|
||||
updated_registered_limit = self.driver.update_registered_limit(
|
||||
registered_limit_id, registered_limit)
|
||||
self.get_registered_limit.invalidate(self,
|
||||
updated_registered_limit['id'])
|
||||
return updated_registered_limit
|
||||
|
||||
@manager.response_truncated
|
||||
def list_registered_limits(self, hints=None):
|
||||
@ -87,13 +87,11 @@ class Manager(manager.Manager):
|
||||
self._assert_resource_exist(limit, 'limit')
|
||||
return self.driver.create_limits(limits)
|
||||
|
||||
def update_limits(self, limits):
|
||||
for limit in limits:
|
||||
self._assert_resource_exist(limit, 'limit')
|
||||
self.driver.update_limits(limits)
|
||||
for limit in limits:
|
||||
self.get_limit.invalidate(self, limit['id'])
|
||||
return self.list_limits()
|
||||
def update_limit(self, limit_id, limit):
|
||||
self._assert_resource_exist(limit, 'limit')
|
||||
updated_limit = self.driver.update_limit(limit_id, limit)
|
||||
self.get_limit.invalidate(self, updated_limit['id'])
|
||||
return updated_limit
|
||||
|
||||
@manager.response_truncated
|
||||
def list_limits(self, hints=None):
|
||||
|
@ -26,7 +26,6 @@ class Routers(wsgi.RoutersBase):
|
||||
mapper, controllers.RegisteredLimitV3(),
|
||||
path='/registered_limits',
|
||||
post_action='create_registered_limits',
|
||||
put_action='update_registered_limits',
|
||||
get_head_action='list_registered_limits',
|
||||
status=json_home.Status.EXPERIMENTAL,
|
||||
rel=json_home.build_v3_resource_relation('registered_limits')
|
||||
@ -36,6 +35,7 @@ class Routers(wsgi.RoutersBase):
|
||||
mapper, controllers.RegisteredLimitV3(),
|
||||
path='/registered_limits/{registered_limit_id}',
|
||||
get_head_action='get_registered_limit',
|
||||
patch_action='update_registered_limit',
|
||||
delete_action='delete_registered_limit',
|
||||
status=json_home.Status.EXPERIMENTAL,
|
||||
rel=json_home.build_v3_resource_relation('registered_limits'),
|
||||
@ -48,7 +48,6 @@ class Routers(wsgi.RoutersBase):
|
||||
mapper, controllers.LimitV3(),
|
||||
path='/limits',
|
||||
post_action='create_limits',
|
||||
put_action='update_limits',
|
||||
get_head_action='list_limits',
|
||||
status=json_home.Status.EXPERIMENTAL,
|
||||
rel=json_home.build_v3_resource_relation('limits')
|
||||
@ -58,6 +57,7 @@ class Routers(wsgi.RoutersBase):
|
||||
mapper, controllers.LimitV3(),
|
||||
path='/limits/{limit_id}',
|
||||
get_head_action='get_limit',
|
||||
patch_action='update_limit',
|
||||
delete_action='delete_limit',
|
||||
status=json_home.Status.EXPERIMENTAL,
|
||||
rel=json_home.build_v3_resource_relation('limits'),
|
||||
|
@ -15,7 +15,7 @@
|
||||
from keystone.common import validation
|
||||
from keystone.common.validation import parameter_types
|
||||
|
||||
_registered_limit_create_properties = {
|
||||
_registered_limit_properties = {
|
||||
'service_id': parameter_types.id_string,
|
||||
'region_id': {
|
||||
'type': 'string'
|
||||
@ -31,7 +31,7 @@ _registered_limit_create_properties = {
|
||||
|
||||
_registered_limit_create = {
|
||||
'type': 'object',
|
||||
'properties': _registered_limit_create_properties,
|
||||
'properties': _registered_limit_properties,
|
||||
'additionalProperties': False,
|
||||
'required': ['service_id', 'resource_name', 'default_limit']
|
||||
}
|
||||
@ -41,33 +41,10 @@ registered_limit_create = {
|
||||
'items': _registered_limit_create,
|
||||
'minItems': 1
|
||||
}
|
||||
|
||||
_registered_limit_update_properties = {
|
||||
'id': parameter_types.id_string,
|
||||
'service_id': parameter_types.id_string,
|
||||
'region_id': {
|
||||
'type': 'string'
|
||||
},
|
||||
'resource_name': {
|
||||
'type': 'string'
|
||||
},
|
||||
'default_limit': {
|
||||
'type': 'integer'
|
||||
},
|
||||
'description': validation.nullable(parameter_types.description)
|
||||
}
|
||||
|
||||
_registered_limit_update = {
|
||||
'type': 'object',
|
||||
'properties': _registered_limit_update_properties,
|
||||
'additionalProperties': False,
|
||||
'required': ['id', ]
|
||||
}
|
||||
|
||||
registered_limit_update = {
|
||||
'type': 'array',
|
||||
'items': _registered_limit_update,
|
||||
'minItems': 1
|
||||
'type': 'object',
|
||||
'properties': _registered_limit_properties,
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
_limit_create_properties = {
|
||||
@ -85,7 +62,6 @@ _limit_create_properties = {
|
||||
'description': validation.nullable(parameter_types.description)
|
||||
}
|
||||
|
||||
|
||||
_limit_create = {
|
||||
'type': 'object',
|
||||
'properties': _limit_create_properties,
|
||||
@ -100,22 +76,14 @@ limit_create = {
|
||||
}
|
||||
|
||||
_limit_update_properties = {
|
||||
'id': parameter_types.id_string,
|
||||
'resource_limit': {
|
||||
'type': 'integer'
|
||||
},
|
||||
'description': validation.nullable(parameter_types.description)
|
||||
}
|
||||
|
||||
_limit_update = {
|
||||
limit_update = {
|
||||
'type': 'object',
|
||||
'properties': _limit_update_properties,
|
||||
'additionalProperties': False,
|
||||
'required': ['id', ]
|
||||
}
|
||||
|
||||
limit_update = {
|
||||
'type': 'array',
|
||||
'items': _limit_update,
|
||||
'minItems': 1
|
||||
'additionalProperties': False
|
||||
}
|
||||
|
@ -145,16 +145,18 @@ class RegisteredLimitTests(object):
|
||||
PROVIDERS.unified_limit_api.create_registered_limits(
|
||||
[registered_limit_1, registered_limit_2])
|
||||
|
||||
# update one, return all registered_limits
|
||||
expect_region = 'region_two'
|
||||
registered_limit_update = {'id': registered_limit_1['id'],
|
||||
'region_id': 'region_two'}
|
||||
res = PROVIDERS.unified_limit_api.update_registered_limits(
|
||||
[registered_limit_update])
|
||||
for re in res:
|
||||
if re['id'] == registered_limit_1['id']:
|
||||
self.assertEqual('region_two', re['region_id'])
|
||||
if re['id'] == registered_limit_2['id']:
|
||||
self.assertDictEqual(registered_limit_2, re)
|
||||
'region_id': expect_region}
|
||||
res = PROVIDERS.unified_limit_api.update_registered_limit(
|
||||
registered_limit_1['id'], registered_limit_update)
|
||||
self.assertEqual(expect_region, res['region_id'])
|
||||
|
||||
# 'id' can be omitted in the update body
|
||||
registered_limit_update = {'region_id': expect_region}
|
||||
res = PROVIDERS.unified_limit_api.update_registered_limit(
|
||||
registered_limit_2['id'], registered_limit_update)
|
||||
self.assertEqual(expect_region, res['region_id'])
|
||||
|
||||
def test_update_registered_limit_invalid_input_return_bad_request(self):
|
||||
registered_limit_1 = unit.new_registered_limit_ref(
|
||||
@ -167,14 +169,14 @@ class RegisteredLimitTests(object):
|
||||
update_ref = {'id': registered_limit_1['id'],
|
||||
'service_id': uuid.uuid4().hex}
|
||||
self.assertRaises(exception.ValidationError,
|
||||
PROVIDERS.unified_limit_api.update_registered_limits,
|
||||
[update_ref])
|
||||
PROVIDERS.unified_limit_api.update_registered_limit,
|
||||
registered_limit_1['id'], update_ref)
|
||||
|
||||
update_ref = {'id': registered_limit_1['id'],
|
||||
'region_id': 'fake_id'}
|
||||
self.assertRaises(exception.ValidationError,
|
||||
PROVIDERS.unified_limit_api.update_registered_limits,
|
||||
[update_ref])
|
||||
PROVIDERS.unified_limit_api.update_registered_limit,
|
||||
registered_limit_1['id'], update_ref)
|
||||
|
||||
def test_update_registered_limit_duplicate(self):
|
||||
registered_limit_1 = unit.new_registered_limit_ref(
|
||||
@ -193,8 +195,8 @@ class RegisteredLimitTests(object):
|
||||
'region_id': self.region_two['id'],
|
||||
'resource_name': 'snapshot'}
|
||||
self.assertRaises(exception.Conflict,
|
||||
PROVIDERS.unified_limit_api.update_registered_limits,
|
||||
[update_ref])
|
||||
PROVIDERS.unified_limit_api.update_registered_limit,
|
||||
registered_limit_1['id'], update_ref)
|
||||
|
||||
@test_utils.wip("Skipped until Bug 1744195 is resolved")
|
||||
def test_update_registered_limit_when_reference_limit_exist(self):
|
||||
@ -215,8 +217,8 @@ class RegisteredLimitTests(object):
|
||||
'region_id': 'region_two'}
|
||||
|
||||
self.assertRaises(exception.RegisteredLimitError,
|
||||
PROVIDERS.unified_limit_api.update_registered_limits,
|
||||
[registered_limit_update])
|
||||
PROVIDERS.unified_limit_api.update_registered_limit,
|
||||
registered_limit_1['id'], registered_limit_update)
|
||||
|
||||
registered_limit_2 = unit.new_registered_limit_ref(
|
||||
service_id=self.service_one['id'],
|
||||
@ -233,8 +235,8 @@ class RegisteredLimitTests(object):
|
||||
'region_id': 'region_two'}
|
||||
|
||||
self.assertRaises(exception.RegisteredLimitError,
|
||||
PROVIDERS.unified_limit_api.update_registered_limits,
|
||||
[registered_limit_update])
|
||||
PROVIDERS.unified_limit_api.update_registered_limit,
|
||||
registered_limit_2['id'], registered_limit_update)
|
||||
|
||||
def test_list_registered_limits(self):
|
||||
# create two registered limits
|
||||
@ -494,7 +496,7 @@ class LimitTests(object):
|
||||
res = PROVIDERS.unified_limit_api.create_limits([limit])
|
||||
self.assertIsNone(res[0]['description'])
|
||||
|
||||
def test_update_limits(self):
|
||||
def test_update_limit(self):
|
||||
# create two limits
|
||||
limit_1 = unit.new_limit_ref(
|
||||
project_id=self.tenant_bar['id'],
|
||||
@ -508,15 +510,18 @@ class LimitTests(object):
|
||||
resource_name='snapshot', resource_limit=5, id=uuid.uuid4().hex)
|
||||
PROVIDERS.unified_limit_api.create_limits([limit_1, limit_2])
|
||||
|
||||
# update one, return all limits
|
||||
expect_limit = 8
|
||||
limit_update = {'id': limit_1['id'],
|
||||
'resource_limit': 8}
|
||||
res = PROVIDERS.unified_limit_api.update_limits([limit_update])
|
||||
for re in res:
|
||||
if re['id'] == limit_1['id']:
|
||||
self.assertEqual(8, re['resource_limit'])
|
||||
if re['id'] == limit_2['id']:
|
||||
self.assertDictEqual(limit_2, re)
|
||||
'resource_limit': expect_limit}
|
||||
res = PROVIDERS.unified_limit_api.update_limit(limit_1['id'],
|
||||
limit_update)
|
||||
self.assertEqual(expect_limit, res['resource_limit'])
|
||||
|
||||
# 'id' can be omitted in the update body
|
||||
limit_update = {'resource_limit': expect_limit}
|
||||
res = PROVIDERS.unified_limit_api.update_limit(limit_2['id'],
|
||||
limit_update)
|
||||
self.assertEqual(expect_limit, res['resource_limit'])
|
||||
|
||||
def test_list_limits(self):
|
||||
# create two limits
|
||||
|
@ -151,18 +151,17 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase):
|
||||
body={'registered_limits': [ref]},
|
||||
expected_status=http_client.CREATED)
|
||||
update_ref = {
|
||||
'id': r.result['registered_limits'][0]['id'],
|
||||
'service_id': self.service_id2,
|
||||
'region_id': self.region_id2,
|
||||
'resource_name': 'snapshot',
|
||||
'default_limit': 5,
|
||||
'description': 'test description'
|
||||
}
|
||||
r = self.put(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [update_ref]},
|
||||
r = self.patch(
|
||||
'/registered_limits/%s' % r.result['registered_limits'][0]['id'],
|
||||
body={'registered_limit': update_ref},
|
||||
expected_status=http_client.OK)
|
||||
new_registered_limits = r.result['registered_limits'][0]
|
||||
new_registered_limits = r.result['registered_limit']
|
||||
|
||||
self.assertEqual(new_registered_limits['service_id'], self.service_id2)
|
||||
self.assertEqual(new_registered_limits['region_id'], self.region_id2)
|
||||
@ -181,91 +180,58 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase):
|
||||
body={'registered_limits': [ref]},
|
||||
expected_status=http_client.CREATED)
|
||||
update_ref = {
|
||||
'id': r.result['registered_limits'][0]['id'],
|
||||
'description': 'test description'
|
||||
}
|
||||
r = self.put(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [update_ref]},
|
||||
registered_limit_id = r.result['registered_limits'][0]['id']
|
||||
r = self.patch(
|
||||
'/registered_limits/%s' % registered_limit_id,
|
||||
body={'registered_limit': update_ref},
|
||||
expected_status=http_client.OK)
|
||||
new_registered_limits = r.result['registered_limits'][0]
|
||||
new_registered_limits = r.result['registered_limit']
|
||||
self.assertEqual(new_registered_limits['description'],
|
||||
'test description')
|
||||
|
||||
update_ref['description'] = ''
|
||||
r = self.put(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [update_ref]},
|
||||
r = self.patch(
|
||||
'/registered_limits/%s' % registered_limit_id,
|
||||
body={'registered_limit': update_ref},
|
||||
expected_status=http_client.OK)
|
||||
new_registered_limits = r.result['registered_limits'][0]
|
||||
new_registered_limits = r.result['registered_limit']
|
||||
self.assertEqual(new_registered_limits['description'], '')
|
||||
|
||||
def test_update_multi_registered_limit(self):
|
||||
ref = unit.new_registered_limit_ref(service_id=self.service_id,
|
||||
region_id=self.region_id,
|
||||
resource_name='volume',
|
||||
default_limit=10)
|
||||
ref2 = unit.new_registered_limit_ref(service_id=self.service_id,
|
||||
region_id=self.region_id,
|
||||
resource_name='snapshot',
|
||||
default_limit=10)
|
||||
r = self.post(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [ref, ref2]},
|
||||
expected_status=http_client.CREATED)
|
||||
update_ref = {
|
||||
'id': r.result['registered_limits'][0]['id'],
|
||||
'service_id': self.service_id2,
|
||||
'region_id': self.region_id2,
|
||||
'resource_name': 'snapshot',
|
||||
'default_limit': 5
|
||||
}
|
||||
update_ref2 = {
|
||||
'id': r.result['registered_limits'][1]['id'],
|
||||
'service_id': self.service_id2,
|
||||
'region_id': self.region_id2,
|
||||
'resource_name': 'volume',
|
||||
'default_limit': 5
|
||||
}
|
||||
r = self.put(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [update_ref, update_ref2]},
|
||||
expected_status=http_client.OK)
|
||||
new_registered_limits = r.result['registered_limits']
|
||||
for key in ['id', 'service_id', 'region_id', 'resource_name',
|
||||
'default_limit']:
|
||||
self.assertEqual(new_registered_limits[0][key], update_ref[key])
|
||||
self.assertEqual(new_registered_limits[1][key], update_ref2[key])
|
||||
|
||||
def test_update_registered_limit_not_found(self):
|
||||
update_ref = {
|
||||
'id': uuid.uuid4().hex,
|
||||
'service_id': self.service_id,
|
||||
'region_id': self.region_id,
|
||||
'resource_name': 'snapshot',
|
||||
'default_limit': 5
|
||||
}
|
||||
self.put(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [update_ref]},
|
||||
self.patch(
|
||||
'/registered_limits/%s' % uuid.uuid4().hex,
|
||||
body={'registered_limit': update_ref},
|
||||
expected_status=http_client.NOT_FOUND)
|
||||
|
||||
def test_update_registered_limit_with_invalid_input(self):
|
||||
update_ref1 = unit.new_registered_limit_ref(id=uuid.uuid4().hex,
|
||||
service_id='fake_id')
|
||||
update_ref2 = unit.new_registered_limit_ref(id=uuid.uuid4().hex,
|
||||
default_limit='not_int')
|
||||
update_ref3 = unit.new_registered_limit_ref(id=uuid.uuid4().hex,
|
||||
resource_name=123)
|
||||
update_ref4 = unit.new_registered_limit_ref(id=uuid.uuid4().hex,
|
||||
region_id='fake_region')
|
||||
update_ref5 = unit.new_registered_limit_ref(id=uuid.uuid4().hex,
|
||||
description=123)
|
||||
ref = unit.new_registered_limit_ref(service_id=self.service_id,
|
||||
region_id=self.region_id,
|
||||
resource_name='volume',
|
||||
default_limit=10)
|
||||
r = self.post(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [ref]},
|
||||
expected_status=http_client.CREATED)
|
||||
reg_id = r.result['registered_limits'][0]['id']
|
||||
|
||||
update_ref1 = unit.new_registered_limit_ref(service_id='fake_id')
|
||||
update_ref2 = unit.new_registered_limit_ref(default_limit='not_int')
|
||||
update_ref3 = unit.new_registered_limit_ref(resource_name=123)
|
||||
update_ref4 = unit.new_registered_limit_ref(region_id='fake_region')
|
||||
update_ref5 = unit.new_registered_limit_ref(description=123)
|
||||
for input_limit in [update_ref1, update_ref2, update_ref3,
|
||||
update_ref4, update_ref5]:
|
||||
self.put(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [input_limit]},
|
||||
self.patch(
|
||||
'/registered_limits/%s' % reg_id,
|
||||
body={'registered_limit': input_limit},
|
||||
expected_status=http_client.BAD_REQUEST)
|
||||
|
||||
@test_utils.wip("Skipped until Bug 1744195 is resolved")
|
||||
@ -289,15 +255,14 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase):
|
||||
expected_status=http_client.CREATED)
|
||||
|
||||
update_ref = {
|
||||
'id': r.result['registered_limits'][0]['id'],
|
||||
'service_id': self.service_id2,
|
||||
'region_id': self.region_id2,
|
||||
'resource_name': 'snapshot',
|
||||
'default_limit': 5
|
||||
}
|
||||
self.put(
|
||||
'/registered_limits',
|
||||
body={'registered_limits': [update_ref]},
|
||||
self.patch(
|
||||
'/registered_limits/%s' % r.result['registered_limits'][0]['id'],
|
||||
body={'registered_limit': update_ref},
|
||||
expected_status=http_client.FORBIDDEN)
|
||||
|
||||
def test_list_registered_limit(self):
|
||||
@ -601,78 +566,50 @@ class LimitsTestCase(test_v3.RestfulTestCase):
|
||||
body={'limits': [ref]},
|
||||
expected_status=http_client.CREATED)
|
||||
update_ref = {
|
||||
'id': r.result['limits'][0]['id'],
|
||||
'resource_limit': 5,
|
||||
'description': 'test description'
|
||||
}
|
||||
r = self.put(
|
||||
'/limits',
|
||||
body={'limits': [update_ref]},
|
||||
r = self.patch(
|
||||
'/limits/%s' % r.result['limits'][0]['id'],
|
||||
body={'limit': update_ref},
|
||||
expected_status=http_client.OK)
|
||||
new_limits = r.result['limits'][0]
|
||||
new_limits = r.result['limit']
|
||||
|
||||
self.assertEqual(new_limits['resource_limit'], 5)
|
||||
self.assertEqual(new_limits['description'], 'test description')
|
||||
|
||||
def test_update_multi_limit(self):
|
||||
def test_update_limit_not_found(self):
|
||||
update_ref = {
|
||||
'resource_limit': 5
|
||||
}
|
||||
self.patch(
|
||||
'/limits/%s' % uuid.uuid4().hex,
|
||||
body={'limit': update_ref},
|
||||
expected_status=http_client.NOT_FOUND)
|
||||
|
||||
def test_update_limit_with_invalid_input(self):
|
||||
ref = unit.new_limit_ref(project_id=self.project_id,
|
||||
service_id=self.service_id,
|
||||
region_id=self.region_id,
|
||||
resource_name='volume',
|
||||
resource_limit=10)
|
||||
ref2 = unit.new_limit_ref(project_id=self.project_id,
|
||||
service_id=self.service_id2,
|
||||
resource_name='snapshot',
|
||||
resource_limit=10)
|
||||
r = self.post(
|
||||
'/limits',
|
||||
body={'limits': [ref, ref2]},
|
||||
body={'limits': [ref]},
|
||||
expected_status=http_client.CREATED)
|
||||
id1 = r.result['limits'][0]['id']
|
||||
update_ref = {
|
||||
'id': id1,
|
||||
'resource_limit': 5
|
||||
}
|
||||
update_ref2 = {
|
||||
'id': r.result['limits'][1]['id'],
|
||||
'resource_limit': 6
|
||||
}
|
||||
r = self.put(
|
||||
'/limits',
|
||||
body={'limits': [update_ref, update_ref2]},
|
||||
expected_status=http_client.OK)
|
||||
new_limits = r.result['limits']
|
||||
for limit in new_limits:
|
||||
if limit['id'] == id1:
|
||||
self.assertEqual(limit['resource_limit'],
|
||||
update_ref['resource_limit'])
|
||||
else:
|
||||
self.assertEqual(limit['resource_limit'],
|
||||
update_ref2['resource_limit'])
|
||||
limit_id = r.result['limits'][0]['id']
|
||||
|
||||
def test_update_limit_not_found(self):
|
||||
update_ref = {
|
||||
'id': uuid.uuid4().hex,
|
||||
'resource_limit': 5
|
||||
}
|
||||
self.put(
|
||||
'/limits',
|
||||
body={'limits': [update_ref]},
|
||||
expected_status=http_client.NOT_FOUND)
|
||||
|
||||
def test_update_limit_with_invalid_input(self):
|
||||
update_ref1 = {
|
||||
'id': 'fake_id',
|
||||
'resource_limit': 5
|
||||
}
|
||||
update_ref2 = {
|
||||
'id': uuid.uuid4().hex,
|
||||
invalid_resource_limit_update = {
|
||||
'resource_limit': 'not_int'
|
||||
}
|
||||
for input_limit in [update_ref1, update_ref2]:
|
||||
self.put(
|
||||
'/limits',
|
||||
body={'limits': [input_limit]},
|
||||
invalid_description_update = {
|
||||
'description': 123
|
||||
}
|
||||
for input_limit in [invalid_resource_limit_update,
|
||||
invalid_description_update]:
|
||||
self.patch(
|
||||
'/limits/%s' % limit_id,
|
||||
body={'limit': input_limit},
|
||||
expected_status=http_client.BAD_REQUEST)
|
||||
|
||||
def test_list_limit(self):
|
||||
|
@ -2529,11 +2529,10 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
'default_limit': 10}]
|
||||
self.create_registered_limits_validator.validate(request_to_validate)
|
||||
|
||||
def test_validate_registered_limit_update_request_without_optional(self):
|
||||
request_to_validate = [{'id': uuid.uuid4().hex,
|
||||
'service_id': uuid.uuid4().hex,
|
||||
'resource_name': 'volume',
|
||||
'default_limit': 10}]
|
||||
def test_validate_registered_limit_update_request_without_region(self):
|
||||
request_to_validate = {'service_id': uuid.uuid4().hex,
|
||||
'resource_name': 'volume',
|
||||
'default_limit': 10}
|
||||
self.update_registered_limits_validator.validate(request_to_validate)
|
||||
|
||||
def test_validate_registered_limit_request_with_no_parameters(self):
|
||||
@ -2542,9 +2541,6 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_registered_limits_validator.validate,
|
||||
request_to_validate)
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_registered_limits_validator.validate,
|
||||
request_to_validate)
|
||||
|
||||
def test_validate_registered_limit_create_request_with_invalid_input(self):
|
||||
_INVALID_FORMATS = [{'service_id': 'fake_id'},
|
||||
@ -2572,13 +2568,12 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
{'default_limit': 'not_int'},
|
||||
{'description': 123}]
|
||||
for invalid_desc in _INVALID_FORMATS:
|
||||
request_to_validate = [{'id': uuid.uuid4().hex,
|
||||
'service_id': uuid.uuid4().hex,
|
||||
'region_id': 'RegionOne',
|
||||
'resource_name': 'volume',
|
||||
'default_limit': 10,
|
||||
'description': 'test description'}]
|
||||
request_to_validate[0].update(invalid_desc)
|
||||
request_to_validate = {'service_id': uuid.uuid4().hex,
|
||||
'region_id': 'RegionOne',
|
||||
'resource_name': 'volume',
|
||||
'default_limit': 10,
|
||||
'description': 'test description'}
|
||||
request_to_validate.update(invalid_desc)
|
||||
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_registered_limits_validator.validate,
|
||||
@ -2595,12 +2590,11 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
request_to_validate)
|
||||
|
||||
def test_validate_registered_limit_update_request_with_addition(self):
|
||||
request_to_validate = [{'id': uuid.uuid4().hex,
|
||||
'service_id': uuid.uuid4().hex,
|
||||
'region_id': 'RegionOne',
|
||||
'resource_name': 'volume',
|
||||
'default_limit': 10,
|
||||
'more_key': 'more_value'}]
|
||||
request_to_validate = {'service_id': uuid.uuid4().hex,
|
||||
'region_id': 'RegionOne',
|
||||
'resource_name': 'volume',
|
||||
'default_limit': 10,
|
||||
'more_key': 'more_value'}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_registered_limits_validator.validate,
|
||||
request_to_validate)
|
||||
@ -2616,15 +2610,6 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
self.create_registered_limits_validator.validate,
|
||||
request_to_validate)
|
||||
|
||||
def test_validate_registered_limit_update_request_without_id(self):
|
||||
request_to_validate = [{'service_id': uuid.uuid4().hex,
|
||||
'region_id': 'RegionOne',
|
||||
'resource_name': 'volume',
|
||||
'default_limit': 10}]
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_registered_limits_validator.validate,
|
||||
request_to_validate)
|
||||
|
||||
def test_validate_limit_create_request_succeeds(self):
|
||||
request_to_validate = [{'project_id': uuid.uuid4().hex,
|
||||
'service_id': uuid.uuid4().hex,
|
||||
@ -2642,14 +2627,12 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
self.create_limits_validator.validate(request_to_validate)
|
||||
|
||||
def test_validate_limit_update_request_succeeds(self):
|
||||
request_to_validate = [{'id': uuid.uuid4().hex,
|
||||
'resource_limit': 10,
|
||||
'description': 'test description'}]
|
||||
request_to_validate = {'resource_limit': 10,
|
||||
'description': 'test description'}
|
||||
self.update_limits_validator.validate(request_to_validate)
|
||||
|
||||
def test_validate_limit_update_request_without_optional(self):
|
||||
request_to_validate = [{'id': uuid.uuid4().hex,
|
||||
'resource_limit': 10}]
|
||||
request_to_validate = {'resource_limit': 10}
|
||||
self.update_limits_validator.validate(request_to_validate)
|
||||
|
||||
def test_validate_limit_request_with_no_parameters(self):
|
||||
@ -2658,9 +2641,6 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_limits_validator.validate,
|
||||
request_to_validate)
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_limits_validator.validate,
|
||||
request_to_validate)
|
||||
|
||||
def test_validate_limit_create_request_with_invalid_input(self):
|
||||
_INVALID_FORMATS = [{'project_id': 'fake_id'},
|
||||
@ -2683,8 +2663,7 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
request_to_validate)
|
||||
|
||||
def test_validate_limit_update_request_with_invalid_input(self):
|
||||
request_to_validate = [{'id': uuid.uuid4().hex,
|
||||
'resource_limit': 'not_int'}]
|
||||
request_to_validate = {'resource_limit': 'not_int'}
|
||||
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_limits_validator.validate,
|
||||
@ -2701,9 +2680,9 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
request_to_validate)
|
||||
|
||||
def test_validate_limit_update_request_with_addition_input_fails(self):
|
||||
request_to_validate = [{'id': uuid.uuid4().hex,
|
||||
'resource_limit': 10,
|
||||
'more_key': 'more_value'}]
|
||||
request_to_validate = {'id': uuid.uuid4().hex,
|
||||
'resource_limit': 10,
|
||||
'more_key': 'more_value'}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_limits_validator.validate,
|
||||
request_to_validate)
|
||||
@ -2719,12 +2698,6 @@ class LimitValidationTestCase(unit.BaseTestCase):
|
||||
self.create_limits_validator.validate,
|
||||
request_to_validate)
|
||||
|
||||
def test_validate_limit_update_request_without_id_fails(self):
|
||||
request_to_validate = [{'resource_limit': 10}]
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_limits_validator.validate,
|
||||
request_to_validate)
|
||||
|
||||
|
||||
class ApplicationCredentialValidatorTestCase(unit.TestCase):
|
||||
_valid_roles = [{'name': 'member'},
|
||||
|
12
releasenotes/notes/limits-api-refactor-05abf9e6c2e75852.yaml
Normal file
12
releasenotes/notes/limits-api-refactor-05abf9e6c2e75852.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
[`bug 1754184 <https://bugs.launchpad.net/keystone/+bug/1754184>`_]
|
||||
The unified limit APIs has been refactored to align with the following
|
||||
API-WG guidelines:
|
||||
1. POST unified limits no longer returns all the limits during create
|
||||
operations. It now only returns the newly created limits.
|
||||
2. Support for updating multiple limits in a single request has been
|
||||
removed by implementing PATCH instead of PUT.
|
||||
Please note that the unified limits APIs is still experimental making it
|
||||
possible to include these improvements.
|
Loading…
x
Reference in New Issue
Block a user