Allow user list to filter by project
Adds a --project filter to `os user list`, which really calls the role assignment manager behind the scenes. Change-Id: I57a75018f12ed3acdf8f6611b6b58bd974f91da2 Closes-Bug: #1397251
This commit is contained in:
parent
cbb26724fc
commit
0ff28d5251
@ -101,28 +101,26 @@ List users
|
||||
.. code:: bash
|
||||
|
||||
os user list
|
||||
[--domain <domain>]
|
||||
[--project <project>]
|
||||
[--group <group>]
|
||||
[--domain <domain>]
|
||||
[--group <group> | --project <project>]
|
||||
[--long]
|
||||
|
||||
.. option:: --domain <domain>
|
||||
|
||||
Filter users by `<domain>` (name or ID)
|
||||
|
||||
.. versionadded:: 3
|
||||
|
||||
.. option:: --project <project>
|
||||
|
||||
Filter users by `<project>` (name or ID)
|
||||
|
||||
*Removed in version 3.*
|
||||
.. option:: --domain <domain>
|
||||
|
||||
Filter users by `<domain>` (name or ID)
|
||||
|
||||
*Identity version 3 only*
|
||||
|
||||
.. option:: --group <group>
|
||||
|
||||
Filter users by `<group>` membership (name or ID)
|
||||
|
||||
.. versionadded:: 3
|
||||
*Identity version 3 only*
|
||||
|
||||
.. option:: --long
|
||||
|
||||
|
@ -188,11 +188,17 @@ class ListUser(lister.Lister):
|
||||
metavar='<domain>',
|
||||
help='Filter users by <domain> (name or ID)',
|
||||
)
|
||||
parser.add_argument(
|
||||
project_or_group = parser.add_mutually_exclusive_group()
|
||||
project_or_group.add_argument(
|
||||
'--group',
|
||||
metavar='<group>',
|
||||
help='Filter users by <group> membership (name or ID)',
|
||||
)
|
||||
project_or_group.add_argument(
|
||||
'--project',
|
||||
metavar='<project>',
|
||||
help='Filter users by <project> (name or ID)',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--long',
|
||||
action='store_true',
|
||||
@ -219,7 +225,44 @@ class ListUser(lister.Lister):
|
||||
else:
|
||||
group = None
|
||||
|
||||
# List users
|
||||
if parsed_args.project:
|
||||
if domain is not None:
|
||||
project = utils.find_resource(
|
||||
identity_client.projects,
|
||||
parsed_args.project,
|
||||
domain_id=domain
|
||||
).id
|
||||
else:
|
||||
project = utils.find_resource(
|
||||
identity_client.projects,
|
||||
parsed_args.project,
|
||||
).id
|
||||
|
||||
assignments = identity_client.role_assignments.list(
|
||||
project=project)
|
||||
|
||||
# NOTE(stevemar): If a user has more than one role on a project
|
||||
# then they will have two entries in the returned data. Since we
|
||||
# are looking for any role, let's just track unique user IDs.
|
||||
user_ids = set()
|
||||
for assignment in assignments:
|
||||
if hasattr(assignment, 'user'):
|
||||
user_ids.add(assignment.user['id'])
|
||||
|
||||
# NOTE(stevemar): Call find_resource once we have unique IDs, so
|
||||
# it's fewer trips to the Identity API, then collect the data.
|
||||
data = []
|
||||
for user_id in user_ids:
|
||||
user = utils.find_resource(identity_client.users, user_id)
|
||||
data.append(user)
|
||||
|
||||
else:
|
||||
data = identity_client.users.list(
|
||||
domain=domain,
|
||||
group=group,
|
||||
)
|
||||
|
||||
# Column handling
|
||||
if parsed_args.long:
|
||||
columns = ['ID', 'Name', 'Default Project Id', 'Domain Id',
|
||||
'Description', 'Email', 'Enabled']
|
||||
@ -228,11 +271,7 @@ class ListUser(lister.Lister):
|
||||
column_headers[3] = 'Domain'
|
||||
else:
|
||||
columns = ['ID', 'Name']
|
||||
column_headers = copy.deepcopy(columns)
|
||||
data = identity_client.users.list(
|
||||
domain=domain,
|
||||
group=group,
|
||||
)
|
||||
column_headers = columns
|
||||
|
||||
return (
|
||||
column_headers,
|
||||
|
@ -44,6 +44,11 @@ class TestUser(identity_fakes.TestIdentityv3):
|
||||
self.users_mock = self.app.client_manager.identity.users
|
||||
self.users_mock.reset_mock()
|
||||
|
||||
# Shortcut for RoleAssignmentManager Mock
|
||||
self.role_assignments_mock = self.app.client_manager.identity.\
|
||||
role_assignments
|
||||
self.role_assignments_mock.reset_mock()
|
||||
|
||||
|
||||
class TestUserCreate(TestUser):
|
||||
|
||||
@ -511,6 +516,21 @@ class TestUserList(TestUser):
|
||||
loaded=True,
|
||||
)
|
||||
|
||||
self.projects_mock.get.return_value = fakes.FakeResource(
|
||||
None,
|
||||
copy.deepcopy(identity_fakes.PROJECT),
|
||||
loaded=True,
|
||||
)
|
||||
|
||||
self.role_assignments_mock.list.return_value = [
|
||||
fakes.FakeResource(
|
||||
None,
|
||||
copy.deepcopy(
|
||||
identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID),
|
||||
loaded=True,
|
||||
)
|
||||
]
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = user.ListUser(self.app, None)
|
||||
|
||||
@ -643,6 +663,33 @@ class TestUserList(TestUser):
|
||||
), )
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
def test_user_list_project(self):
|
||||
arglist = [
|
||||
'--project', identity_fakes.project_name,
|
||||
]
|
||||
verifylist = [
|
||||
('project', identity_fakes.project_name),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# DisplayCommandBase.take_action() returns two tuples
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
kwargs = {
|
||||
'project': identity_fakes.project_id,
|
||||
}
|
||||
|
||||
self.role_assignments_mock.list.assert_called_with(**kwargs)
|
||||
self.users_mock.get.assert_called_with(identity_fakes.user_id)
|
||||
|
||||
collist = ['ID', 'Name']
|
||||
self.assertEqual(columns, collist)
|
||||
datalist = ((
|
||||
identity_fakes.user_id,
|
||||
identity_fakes.user_name,
|
||||
), )
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
|
||||
class TestUserSet(TestUser):
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user