Add support for 'keypairs list --project' parameter
It would be lovely to do this server side but doing so requires a new microversion, a blueprint and a spec. This is less performant but should do the trick for the odd time users want to do this. Change-Id: I26e7d38966304dd67be5da8ed0bb24f87191b82f Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
This commit is contained in:
parent
98a0016cfa
commit
5645fad762
@ -166,7 +166,8 @@ class ListKeypair(command.Lister):
|
|||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument(
|
user_group = parser.add_mutually_exclusive_group()
|
||||||
|
user_group.add_argument(
|
||||||
'--user',
|
'--user',
|
||||||
metavar='<user>',
|
metavar='<user>',
|
||||||
help=_(
|
help=_(
|
||||||
@ -175,15 +176,44 @@ class ListKeypair(command.Lister):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
identity_common.add_user_domain_option_to_parser(parser)
|
identity_common.add_user_domain_option_to_parser(parser)
|
||||||
|
user_group.add_argument(
|
||||||
|
'--project',
|
||||||
|
metavar='<project>',
|
||||||
|
help=_(
|
||||||
|
'Show keypairs for all users associated with project '
|
||||||
|
'(admin only) (name or ID). '
|
||||||
|
'Requires ``--os-compute-api-version`` 2.10 or greater.'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
identity_common.add_project_domain_option_to_parser(parser)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
compute_client = self.app.client_manager.compute
|
compute_client = self.app.client_manager.compute
|
||||||
identity_client = self.app.client_manager.identity
|
identity_client = self.app.client_manager.identity
|
||||||
|
|
||||||
kwargs = {}
|
if parsed_args.project:
|
||||||
|
if compute_client.api_version < api_versions.APIVersion('2.10'):
|
||||||
|
msg = _(
|
||||||
|
'--os-compute-api-version 2.10 or greater is required to '
|
||||||
|
'support the --project option'
|
||||||
|
)
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
if parsed_args.user:
|
# NOTE(stephenfin): This is done client side because nova doesn't
|
||||||
|
# currently support doing so server-side. If this is slow, we can
|
||||||
|
# think about spinning up a threadpool or similar.
|
||||||
|
project = identity_common.find_project(
|
||||||
|
identity_client,
|
||||||
|
parsed_args.project,
|
||||||
|
parsed_args.project_domain,
|
||||||
|
).id
|
||||||
|
users = identity_client.users.list(tenant_id=project)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for user in users:
|
||||||
|
data.extend(compute_client.keypairs.list(user_id=user.id))
|
||||||
|
elif parsed_args.user:
|
||||||
if compute_client.api_version < api_versions.APIVersion('2.10'):
|
if compute_client.api_version < api_versions.APIVersion('2.10'):
|
||||||
msg = _(
|
msg = _(
|
||||||
'--os-compute-api-version 2.10 or greater is required to '
|
'--os-compute-api-version 2.10 or greater is required to '
|
||||||
@ -191,13 +221,15 @@ class ListKeypair(command.Lister):
|
|||||||
)
|
)
|
||||||
raise exceptions.CommandError(msg)
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
kwargs['user_id'] = identity_common.find_user(
|
user = identity_common.find_user(
|
||||||
identity_client,
|
identity_client,
|
||||||
parsed_args.user,
|
parsed_args.user,
|
||||||
parsed_args.user_domain,
|
parsed_args.user_domain,
|
||||||
).id
|
)
|
||||||
|
|
||||||
data = compute_client.keypairs.list(**kwargs)
|
data = compute_client.keypairs.list(user_id=user.id)
|
||||||
|
else:
|
||||||
|
data = compute_client.keypairs.list()
|
||||||
|
|
||||||
columns = (
|
columns = (
|
||||||
"Name",
|
"Name",
|
||||||
|
@ -310,14 +310,6 @@ class TestKeypairList(TestKeypair):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestKeypairList, self).setUp()
|
super(TestKeypairList, self).setUp()
|
||||||
|
|
||||||
self.users_mock = self.app.client_manager.identity.users
|
|
||||||
self.users_mock.reset_mock()
|
|
||||||
self.users_mock.get.return_value = fakes.FakeResource(
|
|
||||||
None,
|
|
||||||
copy.deepcopy(identity_fakes.USER),
|
|
||||||
loaded=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.keypairs_mock.list.return_value = self.keypairs
|
self.keypairs_mock.list.return_value = self.keypairs
|
||||||
|
|
||||||
# Get the command object to test
|
# Get the command object to test
|
||||||
@ -378,6 +370,14 @@ class TestKeypairList(TestKeypair):
|
|||||||
self.app.client_manager.compute.api_version = \
|
self.app.client_manager.compute.api_version = \
|
||||||
api_versions.APIVersion('2.10')
|
api_versions.APIVersion('2.10')
|
||||||
|
|
||||||
|
users_mock = self.app.client_manager.identity.users
|
||||||
|
users_mock.reset_mock()
|
||||||
|
users_mock.get.return_value = fakes.FakeResource(
|
||||||
|
None,
|
||||||
|
copy.deepcopy(identity_fakes.USER),
|
||||||
|
loaded=True,
|
||||||
|
)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
'--user', identity_fakes.user_name,
|
'--user', identity_fakes.user_name,
|
||||||
]
|
]
|
||||||
@ -388,7 +388,7 @@ class TestKeypairList(TestKeypair):
|
|||||||
|
|
||||||
columns, data = self.cmd.take_action(parsed_args)
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
self.users_mock.get.assert_called_with(identity_fakes.user_name)
|
users_mock.get.assert_called_with(identity_fakes.user_name)
|
||||||
self.keypairs_mock.list.assert_called_with(
|
self.keypairs_mock.list.assert_called_with(
|
||||||
user_id=identity_fakes.user_id,
|
user_id=identity_fakes.user_id,
|
||||||
)
|
)
|
||||||
@ -423,6 +423,83 @@ class TestKeypairList(TestKeypair):
|
|||||||
self.assertIn(
|
self.assertIn(
|
||||||
'--os-compute-api-version 2.10 or greater is required', str(ex))
|
'--os-compute-api-version 2.10 or greater is required', str(ex))
|
||||||
|
|
||||||
|
def test_keypair_list_with_project(self):
|
||||||
|
|
||||||
|
# Filtering by user is support for nova api 2.10 or above
|
||||||
|
self.app.client_manager.compute.api_version = \
|
||||||
|
api_versions.APIVersion('2.10')
|
||||||
|
|
||||||
|
projects_mock = self.app.client_manager.identity.tenants
|
||||||
|
projects_mock.reset_mock()
|
||||||
|
projects_mock.get.return_value = fakes.FakeResource(
|
||||||
|
None,
|
||||||
|
copy.deepcopy(identity_fakes.PROJECT),
|
||||||
|
loaded=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
users_mock = self.app.client_manager.identity.users
|
||||||
|
users_mock.reset_mock()
|
||||||
|
users_mock.list.return_value = [
|
||||||
|
fakes.FakeResource(
|
||||||
|
None,
|
||||||
|
copy.deepcopy(identity_fakes.USER),
|
||||||
|
loaded=True,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
arglist = ['--project', identity_fakes.project_name]
|
||||||
|
verifylist = [('project', identity_fakes.project_name)]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
projects_mock.get.assert_called_with(identity_fakes.project_name)
|
||||||
|
users_mock.list.assert_called_with(tenant_id=identity_fakes.project_id)
|
||||||
|
self.keypairs_mock.list.assert_called_with(
|
||||||
|
user_id=identity_fakes.user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(('Name', 'Fingerprint', 'Type'), columns)
|
||||||
|
self.assertEqual(
|
||||||
|
((
|
||||||
|
self.keypairs[0].name,
|
||||||
|
self.keypairs[0].fingerprint,
|
||||||
|
self.keypairs[0].type,
|
||||||
|
), ),
|
||||||
|
tuple(data)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_keypair_list_with_project_pre_v210(self):
|
||||||
|
|
||||||
|
self.app.client_manager.compute.api_version = \
|
||||||
|
api_versions.APIVersion('2.9')
|
||||||
|
|
||||||
|
arglist = ['--project', identity_fakes.project_name]
|
||||||
|
verifylist = [('project', identity_fakes.project_name)]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
ex = self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
self.assertIn(
|
||||||
|
'--os-compute-api-version 2.10 or greater is required', str(ex))
|
||||||
|
|
||||||
|
def test_keypair_list_conflicting_user_options(self):
|
||||||
|
|
||||||
|
# Filtering by user is support for nova api 2.10 or above
|
||||||
|
self.app.client_manager.compute.api_version = \
|
||||||
|
api_versions.APIVersion('2.10')
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
'--user', identity_fakes.user_name,
|
||||||
|
'--project', identity_fakes.project_name,
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
tests_utils.ParserException,
|
||||||
|
self.check_parser, self.cmd, arglist, None)
|
||||||
|
|
||||||
|
|
||||||
class TestKeypairShow(TestKeypair):
|
class TestKeypairShow(TestKeypair):
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
It is now possible to list the keypairs for all users in a project using
|
||||||
|
the ``--project`` parameter. This is an admin-only action by default and
|
||||||
|
requires Compute API microversion 2.10 or later.
|
Loading…
Reference in New Issue
Block a user