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:
wangxiyuan 2018-04-08 14:57:18 +08:00
parent 0e24f91075
commit b385864c5d
14 changed files with 207 additions and 328 deletions

View File

@ -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}

View File

@ -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",

View File

@ -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,

View File

@ -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,

View File

@ -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.

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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'),

View File

@ -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
}

View File

@ -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

View File

@ -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):

View File

@ -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'},

View 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.