Skip to content

Commit d123be0

Browse files
committed
Fix 'openstack keypair list --project <project>'
The --project option of 'openstack keypair list' is supposed to filter keypairs by a project but has not been working and instead returns keypairs from all projects. The reason appears to be because it uses a request for a user list filtered by project but tenant_id/project_id is not a valid filter for GET /users. This fixes the issue by requesting role assignments for the specified project and then requesting keypairs for users with a role in the project. This change depends on a recent openstacksdk bug fix change Ic552dee83d56278d2b866de0cb365a0c394fe26a which fixed the user_id query parameter for the compute /os-keypairs APIs. The bug fix was released in openstacksdk 4.4.0. Closes-Bug: #2096947 Change-Id: Ibb5757766e3040e58d64388b95678fab9b2b6f23
1 parent 616d6f3 commit d123be0

5 files changed

Lines changed: 66 additions & 16 deletions

File tree

openstackclient/compute/v2/keypair.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ def get_parser(self, prog_name):
300300
def take_action(self, parsed_args):
301301
compute_client = self.app.client_manager.compute
302302
identity_client = self.app.client_manager.identity
303+
identity_sdk_client = self.app.client_manager.sdk_connection.identity
303304

304305
kwargs = {}
305306

@@ -345,11 +346,17 @@ def take_action(self, parsed_args):
345346
parsed_args.project,
346347
parsed_args.project_domain,
347348
).id
348-
users = identity_client.users.list(tenant_id=project)
349+
assignments = identity_sdk_client.role_assignments(
350+
scope_project_id=project
351+
)
352+
user_ids = set()
353+
for assignment in assignments:
354+
if assignment.user:
355+
user_ids.add(assignment.user['id'])
349356

350357
data = []
351-
for user in users:
352-
kwargs['user_id'] = user.id
358+
for user_id in user_ids:
359+
kwargs['user_id'] = user_id
353360
data.extend(compute_client.keypairs(**kwargs))
354361
elif parsed_args.user:
355362
if not sdk_utils.supports_microversion(compute_client, '2.10'):

openstackclient/tests/functional/compute/v2/test_keypair.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,32 @@
2121
class KeypairBase(base.TestCase):
2222
"""Methods for functional tests."""
2323

24-
def keypair_create(self, name=data_utils.rand_uuid()):
24+
def keypair_create(self, name=data_utils.rand_uuid(), user=None):
2525
"""Create keypair and add cleanup."""
26-
raw_output = self.openstack('keypair create ' + name)
27-
self.addCleanup(self.keypair_delete, name, True)
26+
cmd = 'keypair create ' + name
27+
if user is not None:
28+
cmd += ' --user ' + user
29+
raw_output = self.openstack(cmd)
30+
self.addCleanup(
31+
self.keypair_delete, name, ignore_exceptions=True, user=user
32+
)
2833
if not raw_output:
2934
self.fail('Keypair has not been created!')
35+
return name
3036

3137
def keypair_list(self, params=''):
3238
"""Return dictionary with list of keypairs."""
3339
raw_output = self.openstack('keypair list')
3440
keypairs = self.parse_show_as_object(raw_output)
3541
return keypairs
3642

37-
def keypair_delete(self, name, ignore_exceptions=False):
43+
def keypair_delete(self, name, ignore_exceptions=False, user=None):
3844
"""Try to delete keypair by name."""
3945
try:
40-
self.openstack('keypair delete ' + name)
46+
cmd = 'keypair delete ' + name
47+
if user is not None:
48+
cmd += ' --user ' + user
49+
self.openstack(cmd)
4150
except exceptions.CommandFailed:
4251
if not ignore_exceptions:
4352
raise
@@ -200,3 +209,30 @@ def test_keypair_show(self):
200209
items = self.parse_listing(raw_output)
201210
self.assert_table_structure(items, HEADERS)
202211
self.assertInOutput(self.KPName, raw_output)
212+
213+
def test_keypair_list_by_project(self):
214+
"""Test keypair list by project.
215+
216+
Test steps:
217+
1) Create keypair for admin project in setUp
218+
2) Create a new project
219+
3) Create a new user
220+
4) Associate the new user with the new project
221+
5) Create keypair for the new user
222+
6) List keypairs by the new project
223+
7) Check that only the keypair from step 5 is returned
224+
"""
225+
project_name = data_utils.rand_name('TestProject')
226+
self.openstack(f'project create {project_name}')
227+
self.addCleanup(self.openstack, f'project delete {project_name}')
228+
user_name = data_utils.rand_name('TestUser')
229+
self.openstack(f'user create {user_name}')
230+
self.addCleanup(self.openstack, f'user delete {user_name}')
231+
self.openstack(
232+
f'role add --user {user_name} --project {project_name} member'
233+
)
234+
keypair_name = self.keypair_create(user=user_name)
235+
raw_output = self.openstack(f'keypair list --project {project_name}')
236+
items = self.parse_listing(raw_output)
237+
self.assertEqual(1, len(items))
238+
self.assertEqual(keypair_name, items[0]['Name'])

openstackclient/tests/unit/compute/v2/fakes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from openstack.compute.v2 import volume_attachment as _volume_attachment
3434

3535
from openstackclient.tests.unit import fakes
36-
from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
36+
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
3737
from openstackclient.tests.unit.image.v2 import fakes as image_fakes
3838
from openstackclient.tests.unit.network.v2 import fakes as network_fakes
3939
from openstackclient.tests.unit import utils
@@ -121,10 +121,10 @@ def set_compute_api_version(self, version: str = '2.1'):
121121

122122

123123
class TestComputev2(
124+
identity_fakes.FakeClientMixin,
124125
network_fakes.FakeClientMixin,
125126
image_fakes.FakeClientMixin,
126127
volume_fakes.FakeClientMixin,
127-
identity_fakes.FakeClientMixin,
128128
FakeClientMixin,
129129
utils.TestCommand,
130130
): ...

openstackclient/tests/unit/compute/v2/test_keypair.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from openstack.compute.v2 import keypair as _keypair
2020
from openstack.identity.v3 import project as _project
21+
from openstack.identity.v3 import role_assignment as _role_assignment
2122
from openstack.identity.v3 import user as _user
2223
from openstack.test import fakes as sdk_fakes
2324
from osc_lib import exceptions
@@ -529,13 +530,17 @@ def test_keypair_list_with_user_pre_v210(self):
529530
def test_keypair_list_with_project(self):
530531
self.set_compute_api_version('2.35')
531532

532-
projects_mock = self.identity_client.tenants
533+
projects_mock = self.identity_client.projects
533534
projects_mock.reset_mock()
534535
projects_mock.get.return_value = self._project
535536

536-
users_mock = self.identity_client.users
537-
users_mock.reset_mock()
538-
users_mock.list.return_value = [self._user]
537+
role_assignments_mock = self.identity_sdk_client.role_assignments
538+
role_assignments_mock.reset_mock()
539+
assignment = sdk_fakes.generate_fake_resource(
540+
_role_assignment.RoleAssignment
541+
)
542+
assignment.user = self._user
543+
role_assignments_mock.return_value = [assignment]
539544

540545
arglist = ['--project', self._project.name]
541546
verifylist = [('project', self._project.name)]
@@ -544,7 +549,9 @@ def test_keypair_list_with_project(self):
544549
columns, data = self.cmd.take_action(parsed_args)
545550

546551
projects_mock.get.assert_called_with(self._project.name)
547-
users_mock.list.assert_called_with(tenant_id=self._project.id)
552+
role_assignments_mock.assert_called_with(
553+
scope_project_id=self._project.id
554+
)
548555
self.compute_client.keypairs.assert_called_with(
549556
user_id=self._user.id,
550557
)

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pbr!=2.1.0,>=2.0.0 # Apache-2.0
77
cryptography>=2.7 # BSD/Apache-2.0
88
cliff>=3.5.0 # Apache-2.0
99
iso8601>=0.1.11 # MIT
10-
openstacksdk>=3.3.0 # Apache-2.0
10+
openstacksdk>=4.4.0 # Apache-2.0
1111
osc-lib>=2.3.0 # Apache-2.0
1212
oslo.i18n>=3.15.3 # Apache-2.0
1313
python-keystoneclient>=3.22.0 # Apache-2.0

0 commit comments

Comments
 (0)