diff options
author | M V P Nitesh <m.nitesh@nectechnologies.in> | 2017-08-07 18:41:35 +0530 |
---|---|---|
committer | Deepak Mourya <deepakmoriya7@gmail.com> | 2018-09-06 05:09:10 +0000 |
commit | 430d7f765a75830ae377545bc57195d38e44e172 (patch) | |
tree | 9315e209364c09a91fbb8806667e365719eee525 | |
parent | 9e107fdd64adc0c9507d3810db9010e05ce72ba8 (diff) | |
download | keystone-430d7f765a75830ae377545bc57195d38e44e172.tar.gz |
Added support for a ``description`` attribute for Identity Roles
Now user can add the description to the role when user creates the role.
Added support for a ``description`` attribute for V3 Identity Roles.
Co-Authored-By: wangxiyuan<wangxiyuan@huawei.com>
Co-Authored-By: Deepak Mourya<deepakmoriya7@gmail.com>
Change-Id: I230af9cc833af13064636b5d9a7ce6334c3f6e9a
Closes-Bug: #1669080
21 files changed, 185 insertions, 2 deletions
diff --git a/api-ref/source/v3/parameters.yaml b/api-ref/source/v3/parameters.yaml index 6e77e51da..0b9690065 100644 --- a/api-ref/source/v3/parameters.yaml +++ b/api-ref/source/v3/parameters.yaml @@ -1665,6 +1665,24 @@ role_assignments: in: body required: true type: array +role_description_create_body: + description: | + Add description about the role. + in: body + required: false + type: string +role_description_response_body: + description: | + The role description. + in: body + required: false + type: string +role_description_update_body: + description: | + The new role description. + in: body + required: false + type: string role_domain_id_request_body: description: | The ID of the domain of the role. diff --git a/api-ref/source/v3/roles.inc b/api-ref/source/v3/roles.inc index 076017717..3d9435058 100644 --- a/api-ref/source/v3/roles.inc +++ b/api-ref/source/v3/roles.inc @@ -133,6 +133,7 @@ Parameters - id: role_id_response_body - links: link_response_body - name: role_name_response_body + - description: role_description_response_body Status Codes ~~~~~~~~~~~~ @@ -174,6 +175,7 @@ Parameters - role: role - name: role_name_create_body - domain_id: role_domain_id_request_body + - description: role_description_create_body Example ~~~~~~~ @@ -200,6 +202,7 @@ Parameters - id: role_id_response_body - links: link_response_body - name: role_name_response_body + - description: role_description_response_body Status Codes ~~~~~~~~~~~~ @@ -248,6 +251,7 @@ Parameters - id: role_id_response_body - links: link_response_body - name: role_name_response_body + - description: role_description_response_body Status Codes ~~~~~~~~~~~~ @@ -290,6 +294,7 @@ Parameters - role_id: role_id_path - role: role - name: role_name_update_body + - description: role_description_update_body Example ~~~~~~~ @@ -310,6 +315,7 @@ Parameters - id: role_id_response_body - links: link_response_body - name: role_name_response_body + - description: role_description_response_body Status Codes ~~~~~~~~~~~~ diff --git a/api-ref/source/v3/samples/admin/domain-specific-role-create-request.json b/api-ref/source/v3/samples/admin/domain-specific-role-create-request.json index 428022c8a..d328c14a3 100644 --- a/api-ref/source/v3/samples/admin/domain-specific-role-create-request.json +++ b/api-ref/source/v3/samples/admin/domain-specific-role-create-request.json @@ -1,5 +1,6 @@ { "role": { + "description": "My new role" "domain_id": "92e782c4988642d783a95f4a87c3fdd7", "name": "developer" } diff --git a/api-ref/source/v3/samples/admin/role-create-request.json b/api-ref/source/v3/samples/admin/role-create-request.json index 67e4099eb..21f1e43e3 100644 --- a/api-ref/source/v3/samples/admin/role-create-request.json +++ b/api-ref/source/v3/samples/admin/role-create-request.json @@ -1,5 +1,6 @@ { "role": { + "description": "My new role", "name": "developer" } } diff --git a/api-ref/source/v3/samples/admin/role-create-response.json b/api-ref/source/v3/samples/admin/role-create-response.json index 77f457d10..3a1c8ae8d 100644 --- a/api-ref/source/v3/samples/admin/role-create-response.json +++ b/api-ref/source/v3/samples/admin/role-create-response.json @@ -4,6 +4,7 @@ "links": { "self": "http://example.com/identity/v3/roles/1e443fa8cee3482a8a2b6954dd5c8f12" }, + "description": "My new role", "name": "developer" } } diff --git a/api-ref/source/v3/samples/admin/role-inferences-response.json b/api-ref/source/v3/samples/admin/role-inferences-response.json index 505a6e1ea..077a7ea04 100644 --- a/api-ref/source/v3/samples/admin/role-inferences-response.json +++ b/api-ref/source/v3/samples/admin/role-inferences-response.json @@ -6,6 +6,7 @@ "links": { "self": "http://example.com/identity/v3/roles/1acd3c5aa0e246b9a7427d252160dcd1" }, + "description": "My new role", "name": "prior role name" }, "implies": [ @@ -14,6 +15,7 @@ "links": { "self": "http://example.com/identity/v3/roles/3602510e2e1f499589f78a0724dcf614" }, + "description": "My new role", "name": "implied role1 name" }, { @@ -21,6 +23,7 @@ "links": { "self": "http://example.com/identity/v3/roles/738289aeef684e73a987f7cf2ec6d925" }, + "description": "My new role", "name": "implied role2 name" } ] @@ -31,6 +34,7 @@ "links": { "self" : "http://example.com/identity/v3/roles/bbf7a5098bb34407b7164eb6ff9f144e" }, + "description": "My new role", "name": "prior role name" }, "implies": [ @@ -39,6 +43,7 @@ "links": { "self": "http://example.com/identity/v3/roles/872b20ad124c4c1bafaef2b1aae316ab" }, + "description": null, "name": "implied role1 name" }, { @@ -46,6 +51,7 @@ "links": { "self": "http://example.com/identity/v3/roles/1d865b1b2da14cb7b05254677e5f36a2" }, + "description": null, "name": "implied role2 name" } ] diff --git a/api-ref/source/v3/samples/admin/role-show-response.json b/api-ref/source/v3/samples/admin/role-show-response.json index e93de6da1..4cb7000c4 100644 --- a/api-ref/source/v3/samples/admin/role-show-response.json +++ b/api-ref/source/v3/samples/admin/role-show-response.json @@ -5,6 +5,7 @@ "links": { "self": "http://example.com/identity/v3/roles/1e443fa8cee3482a8a2b6954dd5c8f12" }, + "description": "My new role", "name": "Developer" } } diff --git a/api-ref/source/v3/samples/admin/role-update-request.json b/api-ref/source/v3/samples/admin/role-update-request.json index 9a13ea724..b24a2bd2e 100644 --- a/api-ref/source/v3/samples/admin/role-update-request.json +++ b/api-ref/source/v3/samples/admin/role-update-request.json @@ -1,5 +1,6 @@ { "role": { + "description": "My new role", "name": "Developer" } } diff --git a/api-ref/source/v3/samples/admin/role-update-response.json b/api-ref/source/v3/samples/admin/role-update-response.json index b9c86efdd..1fd075f3e 100644 --- a/api-ref/source/v3/samples/admin/role-update-response.json +++ b/api-ref/source/v3/samples/admin/role-update-response.json @@ -5,6 +5,7 @@ "links": { "self": "http://example.com/identity/v3/roles/1e443fa8cee3482a8a2b6954dd5c8f12" }, + "description": "My new role", "name": "Developer" } } diff --git a/api-ref/source/v3/samples/admin/roles-list-response.json b/api-ref/source/v3/samples/admin/roles-list-response.json index 1f380b370..096ea0dd7 100644 --- a/api-ref/source/v3/samples/admin/roles-list-response.json +++ b/api-ref/source/v3/samples/admin/roles-list-response.json @@ -10,6 +10,7 @@ "links": { "self": "http://example.com/identity/v3/roles/5318e65d75574c17bf5339d3df33a5a3" }, + "description": "My new role", "name": "admin" }, { @@ -17,6 +18,7 @@ "links": { "self": "http://example.com/identity/v3/roles/642bcfc75c384fd181adf34d9b2df897" }, + "description": "My new role", "name": "anotherrole" }, { @@ -24,6 +26,7 @@ "links": { "self": "http://example.com/identity/v3/roles/779a76d74f544224a7ef8762ca0de627" }, + "description": "My new role", "name": "Member" }, { @@ -38,6 +41,7 @@ "links": { "self": "http://example.com/identity/v3/roles/ba2dfba61c934ee89e3110de36273229" }, + "description": "My new role", "name": "ResellerAdmin" }, { @@ -45,6 +49,7 @@ "links": { "self": "http://example.com/identity/v3/roles/f127b97616f24d3ebceb7be840210adc" }, + "description": null, "name": "service" } ] diff --git a/keystone/assignment/role_backends/sql.py b/keystone/assignment/role_backends/sql.py index 081e1517d..a8b7cbf7e 100644 --- a/keystone/assignment/role_backends/sql.py +++ b/keystone/assignment/role_backends/sql.py @@ -83,6 +83,7 @@ class Role(base.RoleDriverBase): if attr != 'id': setattr(ref, attr, getattr(new_role, attr)) ref.extra = new_role.extra + ref.description = new_role.description return ref.to_dict() def delete_role(self, role_id): @@ -193,10 +194,11 @@ class RoleTable(sql.ModelBase, sql.ModelDictMixinWithExtras): return super(RoleTable, cls).from_dict(new_dict) __tablename__ = 'role' - attributes = ['id', 'name', 'domain_id'] + attributes = ['id', 'name', 'domain_id', 'description'] id = sql.Column(sql.String(64), primary_key=True) name = sql.Column(sql.String(255), nullable=False) domain_id = sql.Column(sql.String(64), nullable=False, server_default=NULL_DOMAIN_ID) + description = sql.Column(sql.String(255), nullable=True) extra = sql.Column(sql.JsonBlob()) __table_args__ = (sql.UniqueConstraint('name', 'domain_id'),) diff --git a/keystone/assignment/schema.py b/keystone/assignment/schema.py index 000c00229..564ab0aec 100644 --- a/keystone/assignment/schema.py +++ b/keystone/assignment/schema.py @@ -15,7 +15,8 @@ from keystone.common.validation import parameter_types # Schema for Identity v3 API _role_properties = { - 'name': parameter_types.name + 'name': parameter_types.name, + 'description': parameter_types.description } role_create = { diff --git a/keystone/common/sql/contract_repo/versions/053_contract_add_role_description_to_role_table.py b/keystone/common/sql/contract_repo/versions/053_contract_add_role_description_to_role_table.py new file mode 100644 index 000000000..8aa15c1ef --- /dev/null +++ b/keystone/common/sql/contract_repo/versions/053_contract_add_role_description_to_role_table.py @@ -0,0 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +def upgrade(migrate_engine): + pass diff --git a/keystone/common/sql/data_migration_repo/versions/053_migrate_add_role_description_to_role_table.py b/keystone/common/sql/data_migration_repo/versions/053_migrate_add_role_description_to_role_table.py new file mode 100644 index 000000000..8aa15c1ef --- /dev/null +++ b/keystone/common/sql/data_migration_repo/versions/053_migrate_add_role_description_to_role_table.py @@ -0,0 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +def upgrade(migrate_engine): + pass diff --git a/keystone/common/sql/expand_repo/versions/053_expand_add_role_description_to_role_table.py b/keystone/common/sql/expand_repo/versions/053_expand_add_role_description_to_role_table.py new file mode 100644 index 000000000..99e41ff15 --- /dev/null +++ b/keystone/common/sql/expand_repo/versions/053_expand_add_role_description_to_role_table.py @@ -0,0 +1,23 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import sqlalchemy as sql + + +def upgrade(migrate_engine): + meta = sql.MetaData() + meta.bind = migrate_engine + + role_table = sql.Table('role', meta, autoload=True) + description = sql.Column('description', sql.String(255), + nullable=True) + role_table.create_column(description) diff --git a/keystone/tests/unit/assignment/test_core.py b/keystone/tests/unit/assignment/test_core.py index 1eac5ba2e..003b9b0aa 100644 --- a/keystone/tests/unit/assignment/test_core.py +++ b/keystone/tests/unit/assignment/test_core.py @@ -82,6 +82,31 @@ class RoleTests(object): PROVIDERS.role_api.get_role, role['id']) + def test_role_crud_without_description(self): + role = { + 'id': uuid.uuid4().hex, + 'name': uuid.uuid4().hex, + 'domain_id': None, + } + self.role_api.create_role(role['id'], role) + role_ref = self.role_api.get_role(role['id']) + role_ref_dict = {x: role_ref[x] for x in role_ref} + self.assertIsNone(role_ref_dict['description']) + role_ref_dict.pop('description') + self.assertDictEqual(role, role_ref_dict) + + role['name'] = uuid.uuid4().hex + updated_role_ref = self.role_api.update_role(role['id'], role) + role_ref = self.role_api.get_role(role['id']) + role_ref_dict = {x: role_ref[x] for x in role_ref} + self.assertIsNone(updated_role_ref['description']) + self.assertDictEqual(role_ref_dict, updated_role_ref) + + self.role_api.delete_role(role['id']) + self.assertRaises(exception.RoleNotFound, + self.role_api.get_role, + role['id']) + def test_update_role_returns_not_found(self): role = unit.new_role_ref() self.assertRaises(exception.RoleNotFound, diff --git a/keystone/tests/unit/core.py b/keystone/tests/unit/core.py index 2034ba5fe..1c13a776a 100644 --- a/keystone/tests/unit/core.py +++ b/keystone/tests/unit/core.py @@ -385,6 +385,7 @@ def new_role_ref(**kwargs): ref = { 'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex, + 'description': uuid.uuid4().hex, 'domain_id': None } ref.update(kwargs) diff --git a/keystone/tests/unit/test_sql_upgrade.py b/keystone/tests/unit/test_sql_upgrade.py index a1a328eb3..06477614d 100644 --- a/keystone/tests/unit/test_sql_upgrade.py +++ b/keystone/tests/unit/test_sql_upgrade.py @@ -3140,6 +3140,45 @@ class FullMigration(SqlMigrateBase, unit.TestCase): ) self.assertTrue(self.does_fk_exist('limit', 'registered_limit_id')) + def test_migration_053_adds_description_to_role(self): + self.expand(52) + self.migrate(52) + self.contract(52) + + role_table_name = 'role' + self.assertTableColumns( + role_table_name, + ['id', 'name', 'domain_id', 'extra'] + ) + + self.expand(53) + self.migrate(53) + self.contract(53) + + self.assertTableColumns( + role_table_name, + ['id', 'name', 'domain_id', 'extra', 'description'] + ) + + role_table = sqlalchemy.Table( + role_table_name, self.metadata, autoload=True + ) + + role = { + 'id': uuid.uuid4().hex, + 'name': "test", + 'domain_id': resource_base.NULL_DOMAIN_ID, + 'description': "This is a string" + } + role_table.insert().values(role).execute() + + role_without_description = { + 'id': uuid.uuid4().hex, + 'name': "test1", + 'domain_id': resource_base.NULL_DOMAIN_ID + } + role_table.insert().values(role_without_description).execute() + class MySQLOpportunisticFullMigration(FullMigration): FIXTURE = db_fixtures.MySQLOpportunisticFixture diff --git a/keystone/tests/unit/test_v3.py b/keystone/tests/unit/test_v3.py index 447be08e1..29a5e93f5 100644 --- a/keystone/tests/unit/test_v3.py +++ b/keystone/tests/unit/test_v3.py @@ -53,6 +53,7 @@ class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase, 'properties': { 'id': {'type': 'string', }, 'name': {'type': 'string', }, + 'description': {'type': 'string', }, }, 'required': ['id', 'name', ], 'additionalProperties': False, diff --git a/keystone/tests/unit/test_validation.py b/keystone/tests/unit/test_validation.py index cd34a5a27..800d0ab7d 100644 --- a/keystone/tests/unit/test_validation.py +++ b/keystone/tests/unit/test_validation.py @@ -755,6 +755,20 @@ class RoleValidationTestCase(unit.BaseTestCase): self.create_role_validator.validate, request_to_validate) + def test_validate_role_request_with_valid_description(self): + """Test we can validate`description` in create role request.""" + request_to_validate = {'name': self.role_name, + 'description': 'My Role'} + self.create_role_validator.validate(request_to_validate) + + def test_validate_role_request_fails_with_invalid_description(self): + """Exception is raised when `description` as a non-string value.""" + request_to_validate = {'name': self.role_name, + 'description': False} + self.assertRaises(exception.SchemaValidationError, + self.create_role_validator.validate, + request_to_validate) + def test_validate_role_update_request(self): """Test that we validate a role update request.""" request_to_validate = {'name': 'My New Role'} diff --git a/releasenotes/notes/add-description-to-role-88ab5bb8a96cc002.yaml b/releasenotes/notes/add-description-to-role-88ab5bb8a96cc002.yaml new file mode 100644 index 000000000..f1d9ad17e --- /dev/null +++ b/releasenotes/notes/add-description-to-role-88ab5bb8a96cc002.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + [`bug 1669080 <https://bugs.launchpad.net/keystone/+bug/1669080>`_] + Added support for a ``description`` attribute for V3 Identity Roles, see + API docs for details. |