diff --git a/doc/source/command-objects/role-assignment.rst b/doc/source/command-objects/role-assignment.rst index 6bb24cb34c..893ebdc4e9 100644 --- a/doc/source/command-objects/role-assignment.rst +++ b/doc/source/command-objects/role-assignment.rst @@ -66,3 +66,7 @@ List role assignments .. option:: --inherited Specifies if the role grant is inheritable to the sub projects + +.. option:: --names + + Returns role assignments with names instead of IDs diff --git a/openstackclient/identity/v3/role_assignment.py b/openstackclient/identity/v3/role_assignment.py index 169c6cb970..771afeb2f5 100644 --- a/openstackclient/identity/v3/role_assignment.py +++ b/openstackclient/identity/v3/role_assignment.py @@ -39,6 +39,11 @@ class ListRoleAssignment(lister.Lister): metavar='', help='Role to filter (name or ID)', ) + parser.add_argument( + '--names', + action="store_true", + help='Display names instead of IDs', + ) user_or_group = parser.add_mutually_exclusive_group() user_or_group.add_argument( '--user', @@ -113,6 +118,7 @@ class ListRoleAssignment(lister.Lister): parsed_args.group_domain, ) + include_names = True if parsed_args.names else False effective = True if parsed_args.effective else False self.log.debug('take_action(%s)' % parsed_args) columns = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') @@ -125,17 +131,26 @@ class ListRoleAssignment(lister.Lister): project=project, role=role, effective=effective, - os_inherit_extension_inherited_to=inherited_to) + os_inherit_extension_inherited_to=inherited_to, + include_names=include_names) data_parsed = [] for assignment in data: # Removing the extra "scope" layer in the assignment json scope = assignment.scope if 'project' in scope: - setattr(assignment, 'project', scope['project']['id']) + if include_names: + prj = '@'.join([scope['project']['name'], + scope['project']['domain']['name']]) + setattr(assignment, 'project', prj) + else: + setattr(assignment, 'project', scope['project']['id']) assignment.domain = '' elif 'domain' in scope: - setattr(assignment, 'domain', scope['domain']['id']) + if include_names: + setattr(assignment, 'domain', scope['domain']['name']) + else: + setattr(assignment, 'domain', scope['domain']['id']) assignment.project = '' else: @@ -148,17 +163,30 @@ class ListRoleAssignment(lister.Lister): del assignment.scope if hasattr(assignment, 'user'): - setattr(assignment, 'user', assignment.user['id']) + if include_names: + usr = '@'.join([assignment.user['name'], + assignment.user['domain']['name']]) + setattr(assignment, 'user', usr) + else: + setattr(assignment, 'user', assignment.user['id']) assignment.group = '' elif hasattr(assignment, 'group'): - setattr(assignment, 'group', assignment.group['id']) + if include_names: + grp = '@'.join([assignment.group['name'], + assignment.group['domain']['name']]) + setattr(assignment, 'group', grp) + else: + setattr(assignment, 'group', assignment.group['id']) assignment.user = '' else: assignment.user = '' assignment.group = '' if hasattr(assignment, 'role'): - setattr(assignment, 'role', assignment.role['id']) + if include_names: + setattr(assignment, 'role', assignment.role['name']) + else: + setattr(assignment, 'role', assignment.role['id']) else: assignment.role = '' diff --git a/openstackclient/tests/identity/v3/fakes.py b/openstackclient/tests/identity/v3/fakes.py index 9fe341ed6a..59b08973b1 100644 --- a/openstackclient/tests/identity/v3/fakes.py +++ b/openstackclient/tests/identity/v3/fakes.py @@ -314,6 +314,22 @@ ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID = { 'role': {'id': role_id}, } +ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INCLUDE_NAMES = { + 'scope': { + 'project': { + 'domain': {'id': domain_id, + 'name': domain_name}, + 'id': project_id, + 'name': project_name}}, + 'user': { + 'domain': {'id': domain_id, + 'name': domain_name}, + 'id': user_id, + 'name': user_name}, + 'role': {'id': role_id, + 'name': role_name}, +} + ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INHERITED = { 'scope': {'project': {'id': project_id}, 'OS-INHERIT:inherited_to': 'projects'}, @@ -333,6 +349,19 @@ ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID = { 'role': {'id': role_id}, } +ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INCLUDE_NAMES = { + 'scope': { + 'domain': {'id': domain_id, + 'name': domain_name}}, + 'user': { + 'domain': {'id': domain_id, + 'name': domain_name}, + 'id': user_id, + 'name': user_name}, + 'role': {'id': role_id, + 'name': role_name}, +} + ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INHERITED = { 'scope': {'domain': {'id': domain_id}, 'OS-INHERIT:inherited_to': 'projects'}, diff --git a/openstackclient/tests/identity/v3/test_role_assignment.py b/openstackclient/tests/identity/v3/test_role_assignment.py index 5723a33477..067a9537e6 100644 --- a/openstackclient/tests/identity/v3/test_role_assignment.py +++ b/openstackclient/tests/identity/v3/test_role_assignment.py @@ -96,7 +96,8 @@ class TestRoleAssignmentList(TestRoleAssignment): role=None, user=None, project=None, - os_inherit_extension_inherited_to=None) + os_inherit_extension_inherited_to=None, + include_names=False) self.assertEqual(self.columns, columns) datalist = (( @@ -143,6 +144,7 @@ class TestRoleAssignmentList(TestRoleAssignment): ('role', None), ('effective', False), ('inherited', False), + ('names', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -156,7 +158,8 @@ class TestRoleAssignmentList(TestRoleAssignment): project=None, role=None, effective=False, - os_inherit_extension_inherited_to=None) + os_inherit_extension_inherited_to=None, + include_names=False) self.assertEqual(self.columns, columns) datalist = (( @@ -203,6 +206,7 @@ class TestRoleAssignmentList(TestRoleAssignment): ('role', None), ('effective', False), ('inherited', False), + ('names', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -216,7 +220,8 @@ class TestRoleAssignmentList(TestRoleAssignment): project=None, role=None, user=None, - os_inherit_extension_inherited_to=None) + os_inherit_extension_inherited_to=None, + include_names=False) self.assertEqual(self.columns, columns) datalist = (( @@ -263,6 +268,7 @@ class TestRoleAssignmentList(TestRoleAssignment): ('role', None), ('effective', False), ('inherited', False), + ('names', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -276,7 +282,8 @@ class TestRoleAssignmentList(TestRoleAssignment): project=None, role=None, user=None, - os_inherit_extension_inherited_to=None) + os_inherit_extension_inherited_to=None, + include_names=False) self.assertEqual(self.columns, columns) datalist = (( @@ -323,6 +330,7 @@ class TestRoleAssignmentList(TestRoleAssignment): ('role', None), ('effective', False), ('inherited', False), + ('names', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -336,7 +344,8 @@ class TestRoleAssignmentList(TestRoleAssignment): project=self.projects_mock.get(), role=None, user=None, - os_inherit_extension_inherited_to=None) + os_inherit_extension_inherited_to=None, + include_names=False) self.assertEqual(self.columns, columns) datalist = (( @@ -381,6 +390,7 @@ class TestRoleAssignmentList(TestRoleAssignment): ('role', None), ('effective', True), ('inherited', False), + ('names', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -394,7 +404,8 @@ class TestRoleAssignmentList(TestRoleAssignment): project=None, role=None, user=None, - os_inherit_extension_inherited_to=None) + os_inherit_extension_inherited_to=None, + include_names=False) self.assertEqual(self.columns, columns) datalist = (( @@ -441,6 +452,7 @@ class TestRoleAssignmentList(TestRoleAssignment): ('role', None), ('effective', False), ('inherited', True), + ('names', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -454,7 +466,8 @@ class TestRoleAssignmentList(TestRoleAssignment): project=None, role=None, user=None, - os_inherit_extension_inherited_to='projects') + os_inherit_extension_inherited_to='projects', + include_names=False) self.assertEqual(self.columns, columns) datalist = (( @@ -472,3 +485,72 @@ class TestRoleAssignmentList(TestRoleAssignment): True ),) self.assertEqual(datalist, tuple(data)) + + def test_role_assignment_list_include_names(self): + + self.role_assignments_mock.list.return_value = [ + fakes.FakeResource( + None, + copy.deepcopy( + identity_fakes + .ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INCLUDE_NAMES), + loaded=True, + ), + fakes.FakeResource( + None, + copy.deepcopy( + identity_fakes + .ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INCLUDE_NAMES), + loaded=True, + ), + ] + + arglist = ['--names'] + verifylist = [ + ('user', None), + ('group', None), + ('domain', None), + ('project', None), + ('role', None), + ('effective', False), + ('inherited', False), + ('names', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + + # This test will not run correctly until the patch in the python + # client is merged. Once that is done 'data' should return the + # correct information + columns, data = self.cmd.take_action(parsed_args) + + self.role_assignments_mock.list.assert_called_with( + domain=None, + group=None, + effective=False, + project=None, + role=None, + user=None, + os_inherit_extension_inherited_to=None, + include_names=True) + + collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') + self.assertEqual(columns, collist) + + datalist1 = (( + identity_fakes.role_name, + '@'.join([identity_fakes.user_name, identity_fakes.domain_name]), + '', + '@'.join([identity_fakes.project_name, + identity_fakes.domain_name]), + '', + False + ), (identity_fakes.role_name, + '@'.join([identity_fakes.user_name, identity_fakes.domain_name]), + '', + '', + identity_fakes.domain_name, + False + ),) + self.assertEqual(tuple(data), datalist1) diff --git a/releasenotes/notes/list_role_assignment_names-0db89f50259d4be2.yaml b/releasenotes/notes/list_role_assignment_names-0db89f50259d4be2.yaml new file mode 100644 index 0000000000..6f5df8d89c --- /dev/null +++ b/releasenotes/notes/list_role_assignment_names-0db89f50259d4be2.yaml @@ -0,0 +1,6 @@ +--- +features: + - > + [`bug 1479569 `_] + Add an optional ``--names`` argument to the `role assignment list`` command. This + will output names instead of IDs for users, groups, roles, projects, and domains. \ No newline at end of file