From 9d7ffbc89e54bae1e9c3cdafec4c23edd77fc542 Mon Sep 17 00:00:00 2001 From: wangxiyuan Date: Thu, 15 Mar 2018 10:56:51 +0800 Subject: [PATCH] Limit description support This patch added description support for registered limit and project limit. Closes-Bug: #1754185 Change-Id: Ia2023ca809b8c2f58af648cb7377f41cd220725b --- api-ref/source/v3/parameters.yaml | 24 ++++++ .../v3/samples/admin/limit-show-response.json | 3 +- .../samples/admin/limits-create-request.json | 3 +- .../samples/admin/limits-create-response.json | 6 +- .../samples/admin/limits-list-response.json | 6 +- .../samples/admin/limits-update-request.json | 3 +- .../samples/admin/limits-update-response.json | 6 +- .../admin/registered-limit-show-response.json | 3 +- .../registered-limits-create-request.json | 3 +- .../registered-limits-create-response.json | 6 +- .../registered-limits-list-response.json | 6 +- .../registered-limits-update-request.json | 6 +- .../registered-limits-update-response.json | 6 +- api-ref/source/v3/unified_limits.inc | 12 +++ keystone/limit/backends/sql.py | 11 ++- keystone/limit/schema.py | 15 ++-- keystone/tests/unit/core.py | 6 +- keystone/tests/unit/limit/test_backends.py | 46 +++++++++- keystone/tests/unit/test_limits.py | 83 +++++++++++++++++-- keystone/tests/unit/test_validation.py | 37 ++++++--- ...dd-limit-description-c1f42641d9c6c33d.yaml | 7 ++ 21 files changed, 249 insertions(+), 49 deletions(-) create mode 100644 releasenotes/notes/add-limit-description-c1f42641d9c6c33d.yaml diff --git a/api-ref/source/v3/parameters.yaml b/api-ref/source/v3/parameters.yaml index d3e9c386ae..d3d005c1b1 100644 --- a/api-ref/source/v3/parameters.yaml +++ b/api-ref/source/v3/parameters.yaml @@ -626,6 +626,18 @@ default_project_id_update_body: in: body required: false type: string +description_limit_request_body: + description: | + The limit description. + in: body + required: false + type: string +description_limit_response_body: + description: | + The limit description. + in: body + required: true + type: string description_region_request_body: description: | The region description. @@ -638,6 +650,18 @@ description_region_response_body: in: body required: true type: string +description_registered_limit_request_body: + description: | + The registered limit description. + in: body + required: false + type: string +description_registered_limit_response_body: + description: | + The registered limit description. + in: body + required: true + type: string domain: description: | A ``domain`` object, containing: diff --git a/api-ref/source/v3/samples/admin/limit-show-response.json b/api-ref/source/v3/samples/admin/limit-show-response.json index 06f1d4f2ec..e7d5c94400 100644 --- a/api-ref/source/v3/samples/admin/limit-show-response.json +++ b/api-ref/source/v3/samples/admin/limit-show-response.json @@ -8,6 +8,7 @@ "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "project_id": "3a705b9f56bb439381b43c4fe59dccce", "id": "25a04c7a065c430590881c646cdcdd58", - "resource_limit": 11 + "resource_limit": 11, + "description": "" } } diff --git a/api-ref/source/v3/samples/admin/limits-create-request.json b/api-ref/source/v3/samples/admin/limits-create-request.json index b486a86d31..2ebf2ffbd8 100644 --- a/api-ref/source/v3/samples/admin/limits-create-request.json +++ b/api-ref/source/v3/samples/admin/limits-create-request.json @@ -11,7 +11,8 @@ "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "project_id": "3a705b9f56bb439381b43c4fe59dccce", "resource_name": "volume", - "resource_limit": 10 + "resource_limit": 10, + "description": "Number of volumes for project 3a705b9f56bb439381b43c4fe59dccce" } ] } diff --git a/api-ref/source/v3/samples/admin/limits-create-response.json b/api-ref/source/v3/samples/admin/limits-create-response.json index c01098606f..abf463b00d 100644 --- a/api-ref/source/v3/samples/admin/limits-create-response.json +++ b/api-ref/source/v3/samples/admin/limits-create-response.json @@ -9,7 +9,8 @@ "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "project_id": "3a705b9f56bb439381b43c4fe59dccce", "id": "25a04c7a065c430590881c646cdcdd58", - "resource_limit": 10 + "resource_limit": 10, + "description": "Number of volumes for project 3a705b9f56bb439381b43c4fe59dccce" }, { "resource_name": "snapshot", @@ -20,7 +21,8 @@ "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "project_id": "3a705b9f56bb439381b43c4fe59dccce", "id": "3229b3849f584faea483d6851f7aab05", - "resource_limit": 5 + "resource_limit": 5, + "description": "" } ] } diff --git a/api-ref/source/v3/samples/admin/limits-list-response.json b/api-ref/source/v3/samples/admin/limits-list-response.json index 4977dab1b6..4f77312ab4 100644 --- a/api-ref/source/v3/samples/admin/limits-list-response.json +++ b/api-ref/source/v3/samples/admin/limits-list-response.json @@ -14,7 +14,8 @@ "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "project_id": "3a705b9f56bb439381b43c4fe59dccce", "id": "25a04c7a065c430590881c646cdcdd58", - "resource_limit": 11 + "resource_limit": 11, + "description": "Number of volumes for project 3a705b9f56bb439381b43c4fe59dccce" }, { "resource_name": "snapshot", @@ -25,7 +26,8 @@ "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "project_id": "3a705b9f56bb439381b43c4fe59dccce", "id": "3229b3849f584faea483d6851f7aab05", - "resource_limit": 5 + "resource_limit": 5, + "description": "" } ] } diff --git a/api-ref/source/v3/samples/admin/limits-update-request.json b/api-ref/source/v3/samples/admin/limits-update-request.json index bb98fc4db0..99e38e6fb8 100644 --- a/api-ref/source/v3/samples/admin/limits-update-request.json +++ b/api-ref/source/v3/samples/admin/limits-update-request.json @@ -6,7 +6,8 @@ }, { "id": "3229b3849f584faea483d6851f7aab05", - "resource_limit": 5 + "resource_limit": 5, + "description": "Number of snapshots for project 3a705b9f56bb439381b43c4fe59dccce" } ] } diff --git a/api-ref/source/v3/samples/admin/limits-update-response.json b/api-ref/source/v3/samples/admin/limits-update-response.json index 4fc2544bb6..7b8222e5dd 100644 --- a/api-ref/source/v3/samples/admin/limits-update-response.json +++ b/api-ref/source/v3/samples/admin/limits-update-response.json @@ -9,7 +9,8 @@ "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "project_id": "3a705b9f56bb439381b43c4fe59dccce", "id": "25a04c7a065c430590881c646cdcdd58", - "resource_limit": 11 + "resource_limit": 11, + "description": "" }, { "resource_name": "snapshot", @@ -20,7 +21,8 @@ "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "project_id": "3a705b9f56bb439381b43c4fe59dccce", "id": "3229b3849f584faea483d6851f7aab05", - "resource_limit": 5 + "resource_limit": 5, + "description": "Number of snapshots for project 3a705b9f56bb439381b43c4fe59dccce" } ] } diff --git a/api-ref/source/v3/samples/admin/registered-limit-show-response.json b/api-ref/source/v3/samples/admin/registered-limit-show-response.json index e7400e132e..c1838e88b3 100644 --- a/api-ref/source/v3/samples/admin/registered-limit-show-response.json +++ b/api-ref/source/v3/samples/admin/registered-limit-show-response.json @@ -7,6 +7,7 @@ }, "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "default_limit": 10, - "id": "773147dd53cd4a17b921d555cf17c633" + "id": "773147dd53cd4a17b921d555cf17c633", + "description": "Number of volumes" } } diff --git a/api-ref/source/v3/samples/admin/registered-limits-create-request.json b/api-ref/source/v3/samples/admin/registered-limits-create-request.json index e2c924c7ca..75294289aa 100644 --- a/api-ref/source/v3/samples/admin/registered-limits-create-request.json +++ b/api-ref/source/v3/samples/admin/registered-limits-create-request.json @@ -9,7 +9,8 @@ { "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "resource_name": "volume", - "default_limit": 10 + "default_limit": 10, + "description": "Number of volumes" } ] } diff --git a/api-ref/source/v3/samples/admin/registered-limits-create-response.json b/api-ref/source/v3/samples/admin/registered-limits-create-response.json index dca0293be2..42da40c344 100644 --- a/api-ref/source/v3/samples/admin/registered-limits-create-response.json +++ b/api-ref/source/v3/samples/admin/registered-limits-create-response.json @@ -8,7 +8,8 @@ }, "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "default_limit": 10, - "id": "773147dd53cd4a17b921d555cf17c633" + "id": "773147dd53cd4a17b921d555cf17c633", + "description": "Number of volumes" }, { "resource_name": "snapshot", @@ -18,7 +19,8 @@ }, "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "default_limit": 5, - "id": "e35a965b2b244209bb0c2b193c55955f" + "id": "e35a965b2b244209bb0c2b193c55955f", + "description": "" } ] } diff --git a/api-ref/source/v3/samples/admin/registered-limits-list-response.json b/api-ref/source/v3/samples/admin/registered-limits-list-response.json index faecf513fc..c5a8537a3d 100644 --- a/api-ref/source/v3/samples/admin/registered-limits-list-response.json +++ b/api-ref/source/v3/samples/admin/registered-limits-list-response.json @@ -13,7 +13,8 @@ }, "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "default_limit": 10, - "id": "195acb8a093e43e9afb23d6628361e7c" + "id": "195acb8a093e43e9afb23d6628361e7c", + "description": "" }, { "resource_name": "volume", @@ -23,7 +24,8 @@ }, "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "default_limit": 5, - "id": "ea7f74f15cba4c6db1406fe52532f98d" + "id": "ea7f74f15cba4c6db1406fe52532f98d", + "description": "Number of volumes" } ] } diff --git a/api-ref/source/v3/samples/admin/registered-limits-update-request.json b/api-ref/source/v3/samples/admin/registered-limits-update-request.json index 6b0b1ae12b..d0a90e04f9 100644 --- a/api-ref/source/v3/samples/admin/registered-limits-update-request.json +++ b/api-ref/source/v3/samples/admin/registered-limits-update-request.json @@ -5,13 +5,15 @@ "id": "e35a965b2b244209bb0c2b193c55955f", "region_id": "RegionOne", "resource_name": "snapshot", - "default_limit": 5 + "default_limit": 5, + "description": "Number of snapshots" }, { "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "id": "773147dd53cd4a17b921d555cf17c633", "resource_name": "volume", - "default_limit": 10 + "default_limit": 10, + "description": "" } ] } diff --git a/api-ref/source/v3/samples/admin/registered-limits-update-response.json b/api-ref/source/v3/samples/admin/registered-limits-update-response.json index dca0293be2..461dc881f7 100644 --- a/api-ref/source/v3/samples/admin/registered-limits-update-response.json +++ b/api-ref/source/v3/samples/admin/registered-limits-update-response.json @@ -8,7 +8,8 @@ }, "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "default_limit": 10, - "id": "773147dd53cd4a17b921d555cf17c633" + "id": "773147dd53cd4a17b921d555cf17c633", + "description": "" }, { "resource_name": "snapshot", @@ -18,7 +19,8 @@ }, "service_id": "9408080f1970482aa0e38bc2d4ea34b7", "default_limit": 5, - "id": "e35a965b2b244209bb0c2b193c55955f" + "id": "e35a965b2b244209bb0c2b193c55955f", + "description": "Number of snapshots" } ] } diff --git a/api-ref/source/v3/unified_limits.inc b/api-ref/source/v3/unified_limits.inc index c8739cd443..f20a994181 100644 --- a/api-ref/source/v3/unified_limits.inc +++ b/api-ref/source/v3/unified_limits.inc @@ -48,6 +48,7 @@ Parameters - region_id: region_id_response_body - resource_name: resource_name - default_limit: default_limit + - description: description_registered_limit_response_body - links: link_response_body @@ -93,6 +94,7 @@ Parameters - region_id: region_id_request_body - resource_name: resource_name - default_limit: default_limit + - description: description_registered_limit_request_body Examples ~~~~~~~~ @@ -116,6 +118,7 @@ Parameters - region_id: region_id_response_body - resource_name: resource_name - default_limit: default_limit + - description: description_registered_limit_response_body - links: link_response_body Status Codes @@ -164,6 +167,7 @@ Parameters - region_id: region_id_request_body - resource_name: resource_name - default_limit: default_limit + - description: description_registered_limit_request_body Example ~~~~~~~ @@ -185,6 +189,7 @@ Parameters - region_id: region_id_response_body - resource_name: resource_name - default_limit: default_limit + - description: description_registered_limit_response_body - links: link_response_body @@ -243,6 +248,7 @@ Parameters - region_id: region_id_response_body - resource_name: resource_name - default_limit: default_limit + - description: description_registered_limit_response_body - links: link_response_body Status Codes @@ -339,6 +345,7 @@ Parameters - region_id: region_id_response_body - resource_name: resource_name - resource_limit: resource_limit + - description: description_limit_response_body - links: link_response_body @@ -383,6 +390,7 @@ Parameters - region_id: region_id_request_body - resource_name: resource_name - resource_limit: resource_limit + - description: description_limit_request_body Examples ~~~~~~~~ @@ -406,6 +414,7 @@ Parameters - region_id: region_id_response_body - resource_name: resource_name - resource_limit: resource_limit + - description: description_limit_response_body - links: link_response_body Status Codes @@ -451,6 +460,7 @@ Parameters - limits: limits - resource_limit: resource_limit + - description: description_limit_request_body Example ~~~~~~~ @@ -472,6 +482,7 @@ Parameters - region_id: region_id_response_body - resource_name: resource_name - resource_limit: resource_limit + - description: description_limit_response_body - links: link_response_body @@ -531,6 +542,7 @@ Parameters - region_id: region_id_response_body - resource_name: resource_name - resource_limit: resource_limit + - description: description_limit_response_body - links: link_response_body Status Codes diff --git a/keystone/limit/backends/sql.py b/keystone/limit/backends/sql.py index 5d3ef958b3..eeaad2fd4d 100644 --- a/keystone/limit/backends/sql.py +++ b/keystone/limit/backends/sql.py @@ -32,7 +32,8 @@ class RegisteredLimitModel(sql.ModelBase, sql.ModelDictMixin): 'service_id', 'region_id', 'resource_name', - 'default_limit' + 'default_limit', + 'description' ] id = sql.Column(sql.String(length=64), primary_key=True) @@ -42,6 +43,7 @@ class RegisteredLimitModel(sql.ModelBase, sql.ModelDictMixin): sql.ForeignKey('region.id'), nullable=True) resource_name = sql.Column(sql.String(255)) default_limit = sql.Column(sql.Integer, nullable=False) + description = sql.Column(sql.Text()) __table_args__ = ( sqlalchemy.UniqueConstraint('service_id', @@ -57,7 +59,8 @@ class LimitModel(sql.ModelBase, sql.ModelDictMixin): 'service_id', 'region_id', 'resource_name', - 'resource_limit' + 'resource_limit', + 'description' ] id = sql.Column(sql.String(length=64), primary_key=True) @@ -67,6 +70,7 @@ class LimitModel(sql.ModelBase, sql.ModelDictMixin): region_id = sql.Column(sql.String(64), nullable=True) resource_name = sql.Column(sql.String(255)) resource_limit = sql.Column(sql.Integer, nullable=False) + description = sql.Column(sql.Text()) __table_args__ = ( sqlalchemy.ForeignKeyConstraint(['service_id', @@ -227,9 +231,10 @@ class UnifiedLimit(base.UnifiedLimitDriverBase): for limit in limits: ref = self._get_limit(session, limit['id']) old_dict = ref.to_dict() - old_dict['resource_limit'] = limit['resource_limit'] + old_dict.update(limit) new_limit = LimitModel.from_dict(old_dict) ref.resource_limit = new_limit.resource_limit + ref.description = new_limit.description @driver_hints.truncated def list_limits(self, hints): diff --git a/keystone/limit/schema.py b/keystone/limit/schema.py index b764458657..95315529af 100644 --- a/keystone/limit/schema.py +++ b/keystone/limit/schema.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +from keystone.common import validation from keystone.common.validation import parameter_types _registered_limit_create_properties = { @@ -24,7 +25,8 @@ _registered_limit_create_properties = { }, 'default_limit': { 'type': 'integer' - } + }, + 'description': validation.nullable(parameter_types.description) } _registered_limit_create = { @@ -51,7 +53,8 @@ _registered_limit_update_properties = { }, 'default_limit': { 'type': 'integer' - } + }, + 'description': validation.nullable(parameter_types.description) } _registered_limit_update = { @@ -78,7 +81,8 @@ _limit_create_properties = { }, 'resource_limit': { 'type': 'integer' - } + }, + 'description': validation.nullable(parameter_types.description) } @@ -99,14 +103,15 @@ _limit_update_properties = { 'id': parameter_types.id_string, 'resource_limit': { 'type': 'integer' - } + }, + 'description': validation.nullable(parameter_types.description) } _limit_update = { 'type': 'object', 'properties': _limit_update_properties, 'additionalProperties': False, - 'required': ['id', 'resource_limit'] + 'required': ['id', ] } limit_update = { diff --git a/keystone/tests/unit/core.py b/keystone/tests/unit/core.py index c914e00b12..16a5683005 100644 --- a/keystone/tests/unit/core.py +++ b/keystone/tests/unit/core.py @@ -467,7 +467,8 @@ def new_registered_limit_ref(**kwargs): ref = { 'service_id': uuid.uuid4().hex, 'resource_name': uuid.uuid4().hex, - 'default_limit': 10 + 'default_limit': 10, + 'description': uuid.uuid4().hex } ref.update(kwargs) @@ -479,7 +480,8 @@ def new_limit_ref(**kwargs): 'project_id': uuid.uuid4().hex, 'service_id': uuid.uuid4().hex, 'resource_name': uuid.uuid4().hex, - 'resource_limit': 10 + 'resource_limit': 10, + 'description': uuid.uuid4().hex } ref.update(kwargs) diff --git a/keystone/tests/unit/limit/test_backends.py b/keystone/tests/unit/limit/test_backends.py index 491b15a1af..2be9034d36 100644 --- a/keystone/tests/unit/limit/test_backends.py +++ b/keystone/tests/unit/limit/test_backends.py @@ -28,7 +28,8 @@ class RegisteredLimitTests(object): registered_limit_1 = unit.new_registered_limit_ref( service_id=self.service_one['id'], region_id=self.region_one['id'], - resource_name='volume', default_limit=10, id=uuid.uuid4().hex) + resource_name='volume', default_limit=10, id=uuid.uuid4().hex, + description='test description') reg_limits = PROVIDERS.unified_limit_api.create_registered_limits( [registered_limit_1]) self.assertDictEqual(registered_limit_1, reg_limits[0]) @@ -111,6 +112,26 @@ class RegisteredLimitTests(object): PROVIDERS.unified_limit_api.create_registered_limits, [registered_limit_1]) + def test_create_registered_limit_description_none(self): + registered_limit = unit.new_registered_limit_ref( + service_id=self.service_one['id'], + region_id=self.region_one['id'], + resource_name='volume', default_limit=10, id=uuid.uuid4().hex, + description=None) + res = PROVIDERS.unified_limit_api.create_registered_limits( + [registered_limit]) + self.assertIsNone(res[0]['description']) + + def test_create_registered_limit_without_description(self): + registered_limit = unit.new_registered_limit_ref( + service_id=self.service_one['id'], + region_id=self.region_one['id'], + resource_name='volume', default_limit=10, id=uuid.uuid4().hex) + registered_limit.pop('description') + res = PROVIDERS.unified_limit_api.create_registered_limits( + [registered_limit]) + self.assertIsNone(res[0]['description']) + def test_update_registered_limit(self): # create two registered limits registered_limit_1 = unit.new_registered_limit_ref( @@ -380,7 +401,8 @@ class LimitTests(object): project_id=self.tenant_bar['id'], service_id=self.service_one['id'], region_id=self.region_one['id'], - resource_name='volume', resource_limit=10, id=uuid.uuid4().hex) + resource_name='volume', resource_limit=10, id=uuid.uuid4().hex, + description='test description') limits = PROVIDERS.unified_limit_api.create_limits([limit_1]) self.assertDictEqual(limit_1, limits[0]) @@ -452,6 +474,26 @@ class LimitTests(object): PROVIDERS.unified_limit_api.create_limits, [limit_1]) + def test_create_limit_description_none(self): + limit = unit.new_limit_ref( + project_id=self.tenant_bar['id'], + service_id=self.service_one['id'], + region_id=self.region_one['id'], + resource_name='volume', resource_limit=10, id=uuid.uuid4().hex, + description=None) + res = PROVIDERS.unified_limit_api.create_limits([limit]) + self.assertIsNone(res[0]['description']) + + def test_create_limit_without_description(self): + limit = unit.new_limit_ref( + project_id=self.tenant_bar['id'], + service_id=self.service_one['id'], + region_id=self.region_one['id'], + resource_name='volume', resource_limit=10, id=uuid.uuid4().hex) + limit.pop('description') + res = PROVIDERS.unified_limit_api.create_limits([limit]) + self.assertIsNone(res[0]['description']) + def test_update_limits(self): # create two limits limit_1 = unit.new_limit_ref( diff --git a/keystone/tests/unit/test_limits.py b/keystone/tests/unit/test_limits.py index 1e6fccea35..6347b4c168 100644 --- a/keystone/tests/unit/test_limits.py +++ b/keystone/tests/unit/test_limits.py @@ -53,7 +53,7 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase): expected_status=http_client.CREATED) registered_limits = r.result['registered_limits'] for key in ['service_id', 'region_id', 'resource_name', - 'default_limit']: + 'default_limit', 'description']: self.assertEqual(registered_limits[0][key], ref[key]) def test_create_registered_limit_without_region(self): @@ -67,6 +67,20 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase): self.assertEqual(registered_limits[0][key], ref[key]) self.assertIsNone(registered_limits[0].get('region_id')) + def test_create_registered_without_description(self): + ref = unit.new_registered_limit_ref(service_id=self.service_id, + region_id=self.region_id) + ref.pop('description') + r = self.post( + '/registered_limits', + body={'registered_limits': [ref]}, + expected_status=http_client.CREATED) + registered_limits = r.result['registered_limits'] + for key in ['service_id', 'region_id', 'resource_name', + 'default_limit']: + self.assertEqual(registered_limits[0][key], ref[key]) + self.assertIsNone(registered_limits[0]['description']) + def test_create_multi_registered_limit(self): ref1 = unit.new_registered_limit_ref(service_id=self.service_id, region_id=self.region_id, @@ -141,7 +155,8 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase): 'service_id': self.service_id2, 'region_id': self.region_id2, 'resource_name': 'snapshot', - 'default_limit': 5 + 'default_limit': 5, + 'description': 'test description' } r = self.put( '/registered_limits', @@ -153,6 +168,37 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase): self.assertEqual(new_registered_limits['region_id'], self.region_id2) self.assertEqual(new_registered_limits['resource_name'], 'snapshot') self.assertEqual(new_registered_limits['default_limit'], 5) + self.assertEqual(new_registered_limits['description'], + 'test description') + + def test_update_registered_limit_description(self): + 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) + update_ref = { + 'id': r.result['registered_limits'][0]['id'], + 'description': 'test description' + } + r = self.put( + '/registered_limits', + body={'registered_limits': [update_ref]}, + expected_status=http_client.OK) + new_registered_limits = r.result['registered_limits'][0] + self.assertEqual(new_registered_limits['description'], + 'test description') + + update_ref['description'] = '' + r = self.put( + '/registered_limits', + body={'registered_limits': [update_ref]}, + expected_status=http_client.OK) + new_registered_limits = r.result['registered_limits'][0] + self.assertEqual(new_registered_limits['description'], '') def test_update_multi_registered_limit(self): ref = unit.new_registered_limit_ref(service_id=self.service_id, @@ -213,8 +259,10 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase): 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) for input_limit in [update_ref1, update_ref2, update_ref3, - update_ref4]: + update_ref4, update_ref5]: self.put( '/registered_limits', body={'registered_limits': [input_limit]}, @@ -325,7 +373,7 @@ class RegisteredLimitsTestCase(test_v3.RestfulTestCase): expected_status=http_client.OK) registered_limit = r.result['registered_limit'] for key in ['service_id', 'region_id', 'resource_name', - 'default_limit']: + 'default_limit', 'description']: self.assertEqual(registered_limit[key], ref1[key]) def test_delete_registered_limit(self): @@ -420,7 +468,7 @@ class LimitsTestCase(test_v3.RestfulTestCase): self. assertIsNotNone(limits[0]['id']) self. assertIsNotNone(limits[0]['project_id']) for key in ['service_id', 'region_id', 'resource_name', - 'resource_limit']: + 'resource_limit', 'description']: self.assertEqual(limits[0][key], ref[key]) def test_create_limit_without_region(self): @@ -439,6 +487,25 @@ class LimitsTestCase(test_v3.RestfulTestCase): self.assertEqual(limits[0][key], ref[key]) self.assertIsNone(limits[0].get('region_id')) + def test_create_limit_without_description(self): + ref = unit.new_limit_ref(project_id=self.project_id, + service_id=self.service_id, + region_id=self.region_id, + resource_name='volume') + ref.pop('description') + r = self.post( + '/limits', + body={'limits': [ref]}, + expected_status=http_client.CREATED) + limits = r.result['limits'] + + self. assertIsNotNone(limits[0]['id']) + self. assertIsNotNone(limits[0]['project_id']) + for key in ['service_id', 'region_id', 'resource_name', + 'resource_limit']: + self.assertEqual(limits[0][key], ref[key]) + self.assertIsNone(limits[0]['description']) + def test_create_multi_limit(self): ref1 = unit.new_limit_ref(project_id=self.project_id, service_id=self.service_id, @@ -535,7 +602,8 @@ class LimitsTestCase(test_v3.RestfulTestCase): expected_status=http_client.CREATED) update_ref = { 'id': r.result['limits'][0]['id'], - 'resource_limit': 5 + 'resource_limit': 5, + 'description': 'test description' } r = self.put( '/limits', @@ -544,6 +612,7 @@ class LimitsTestCase(test_v3.RestfulTestCase): new_limits = r.result['limits'][0] self.assertEqual(new_limits['resource_limit'], 5) + self.assertEqual(new_limits['description'], 'test description') def test_update_multi_limit(self): ref = unit.new_limit_ref(project_id=self.project_id, @@ -687,7 +756,7 @@ class LimitsTestCase(test_v3.RestfulTestCase): expected_status=http_client.OK) limit = r.result['limit'] for key in ['service_id', 'region_id', 'resource_name', - 'resource_limit']: + 'resource_limit', 'description']: self.assertEqual(limit[key], ref1[key]) def test_delete_limit(self): diff --git a/keystone/tests/unit/test_validation.py b/keystone/tests/unit/test_validation.py index 485c0ba1c2..2ef214cee3 100644 --- a/keystone/tests/unit/test_validation.py +++ b/keystone/tests/unit/test_validation.py @@ -2519,16 +2519,17 @@ class LimitValidationTestCase(unit.BaseTestCase): request_to_validate = [{'service_id': uuid.uuid4().hex, 'region_id': 'RegionOne', 'resource_name': 'volume', - 'default_limit': 10}] + 'default_limit': 10, + 'description': 'test description'}] self.create_registered_limits_validator.validate(request_to_validate) - def test_validate_registered_limit_create_request_without_region(self): + def test_validate_registered_limit_create_request_without_optional(self): request_to_validate = [{'service_id': uuid.uuid4().hex, 'resource_name': 'volume', 'default_limit': 10}] self.create_registered_limits_validator.validate(request_to_validate) - def test_validate_registered_limit_update_request_without_region(self): + 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', @@ -2549,12 +2550,15 @@ class LimitValidationTestCase(unit.BaseTestCase): _INVALID_FORMATS = [{'service_id': 'fake_id'}, {'region_id': 123}, {'resource_name': 123}, - {'default_limit': 'not_int'}] + {'default_limit': 'not_int'}, + {'description': 123}, + {'description': True}] for invalid_desc in _INVALID_FORMATS: request_to_validate = [{'service_id': uuid.uuid4().hex, 'region_id': 'RegionOne', 'resource_name': 'volume', - 'default_limit': 10}] + 'default_limit': 10, + 'description': 'test description'}] request_to_validate[0].update(invalid_desc) self.assertRaises(exception.SchemaValidationError, @@ -2565,13 +2569,15 @@ class LimitValidationTestCase(unit.BaseTestCase): _INVALID_FORMATS = [{'service_id': 'fake_id'}, {'region_id': 123}, {'resource_name': 123}, - {'default_limit': 'not_int'}] + {'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}] + 'default_limit': 10, + 'description': 'test description'}] request_to_validate[0].update(invalid_desc) self.assertRaises(exception.SchemaValidationError, @@ -2624,10 +2630,11 @@ class LimitValidationTestCase(unit.BaseTestCase): 'service_id': uuid.uuid4().hex, 'region_id': 'RegionOne', 'resource_name': 'volume', - 'resource_limit': 10}] + 'resource_limit': 10, + 'description': 'test description'}] self.create_limits_validator.validate(request_to_validate) - def test_validate_limit_create_request_without_region(self): + def test_validate_limit_create_request_without_optional(self): request_to_validate = [{'project_id': uuid.uuid4().hex, 'service_id': uuid.uuid4().hex, 'resource_name': 'volume', @@ -2635,6 +2642,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'}] + 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}] self.update_limits_validator.validate(request_to_validate) @@ -2654,13 +2667,15 @@ class LimitValidationTestCase(unit.BaseTestCase): {'service_id': 'fake_id'}, {'region_id': 123}, {'resource_name': 123}, - {'resource_limit': 'not_int'}] + {'resource_limit': 'not_int'}, + {'description': 123}] for invalid_desc in _INVALID_FORMATS: request_to_validate = [{'project_id': uuid.uuid4().hex, 'service_id': uuid.uuid4().hex, 'region_id': 'RegionOne', 'resource_name': 'volume', - 'resource_limit': 10}] + 'resource_limit': 10, + 'description': 'test description'}] request_to_validate[0].update(invalid_desc) self.assertRaises(exception.SchemaValidationError, diff --git a/releasenotes/notes/add-limit-description-c1f42641d9c6c33d.yaml b/releasenotes/notes/add-limit-description-c1f42641d9c6c33d.yaml new file mode 100644 index 0000000000..145a7721f2 --- /dev/null +++ b/releasenotes/notes/add-limit-description-c1f42641d9c6c33d.yaml @@ -0,0 +1,7 @@ +--- +features: + - > + [`bug 1754185 `_] + Registered limits and project limits now support an optional, nullable + property called `description`. Users can create/update a registered limit + or project limit with `description` now.