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
This commit is contained in:
parent
9e107fdd64
commit
430d7f765a
@ -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.
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"role": {
|
||||
"description": "My new role"
|
||||
"domain_id": "92e782c4988642d783a95f4a87c3fdd7",
|
||||
"name": "developer"
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"role": {
|
||||
"description": "My new role",
|
||||
"name": "developer"
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
"links": {
|
||||
"self": "http://example.com/identity/v3/roles/1e443fa8cee3482a8a2b6954dd5c8f12"
|
||||
},
|
||||
"description": "My new role",
|
||||
"name": "developer"
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
|
@ -5,6 +5,7 @@
|
||||
"links": {
|
||||
"self": "http://example.com/identity/v3/roles/1e443fa8cee3482a8a2b6954dd5c8f12"
|
||||
},
|
||||
"description": "My new role",
|
||||
"name": "Developer"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"role": {
|
||||
"description": "My new role",
|
||||
"name": "Developer"
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"links": {
|
||||
"self": "http://example.com/identity/v3/roles/1e443fa8cee3482a8a2b6954dd5c8f12"
|
||||
},
|
||||
"description": "My new role",
|
||||
"name": "Developer"
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
|
@ -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'),)
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
@ -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
|
@ -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)
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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'}
|
||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user