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:
		| @@ -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): | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Steve Martinelli
					Steve Martinelli