From 94d17b876226c9380dd2b0cf9295e737cfc6401c Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 15 May 2025 15:19:12 +0100 Subject: [PATCH] identity: Fix listing of applications credentials by user Change-Id: I71f1c4f338694e2b50e71b6907c415bbb6a768fa Signed-off-by: Stephen Finucane Closes-bug: #2107354 --- openstackclient/identity/common.py | 52 ++++++++++++++ .../identity/v3/application_credential.py | 4 +- .../v3/test_application_credential.py | 72 ++++++++++++------- 3 files changed, 101 insertions(+), 27 deletions(-) diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py index 65ff8852ff..412fd71597 100644 --- a/openstackclient/identity/common.py +++ b/openstackclient/identity/common.py @@ -189,6 +189,16 @@ def find_domain(identity_client, name_or_id): ) +def find_domain_id_sdk( + identity_client, name_or_id, *, validate_actor_existence=True +): + return _find_sdk_id( + identity_client.find_domain, + name_or_id=name_or_id, + validate_actor_existence=validate_actor_existence, + ) + + def find_group(identity_client, name_or_id, domain_name_or_id=None): if domain_name_or_id is None: return _find_identity_resource( @@ -229,6 +239,32 @@ def find_user(identity_client, name_or_id, domain_name_or_id=None): ) +def find_user_id_sdk( + identity_client, + name_or_id, + domain_name_or_id=None, + *, + validate_actor_existence=True, +): + if domain_name_or_id is None: + return _find_sdk_id( + identity_client.find_user, + name_or_id=name_or_id, + validate_actor_existence=validate_actor_existence, + ) + domain_id = find_domain_id_sdk( + identity_client, + name_or_id=domain_name_or_id, + validate_actor_existence=validate_actor_existence, + ) + return _find_sdk_id( + identity_client.find_user, + name_or_id=name_or_id, + validate_actor_existence=validate_actor_existence, + domain_id=domain_id, + ) + + def _find_identity_resource( identity_client_manager, name_or_id, resource_type, **kwargs ): @@ -269,6 +305,22 @@ def _find_identity_resource( return resource_type(None, {'id': name_or_id, 'name': name_or_id}) +def _find_sdk_id( + find_command, name_or_id, *, validate_actor_existence=True, **kwargs +): + try: + resource = find_command( + name_or_id=name_or_id, ignore_missing=False, **kwargs + ) + except sdk_exceptions.ForbiddenException: + return name_or_id + except sdk_exceptions.ResourceNotFound as exc: + if not validate_actor_existence: + return name_or_id + raise exceptions.CommandError from exc + return resource.id + + def get_immutable_options(parsed_args): options = {} if parsed_args.immutable: diff --git a/openstackclient/identity/v3/application_credential.py b/openstackclient/identity/v3/application_credential.py index 7bc2b8a192..f0dd5a58fd 100644 --- a/openstackclient/identity/v3/application_credential.py +++ b/openstackclient/identity/v3/application_credential.py @@ -269,9 +269,9 @@ class ListApplicationCredential(command.Lister): def take_action(self, parsed_args): identity_client = self.app.client_manager.sdk_connection.identity if parsed_args.user: - user_id = common.find_user( + user_id = common.find_user_id_sdk( identity_client, parsed_args.user, parsed_args.user_domain - ).id + ) else: conn = self.app.client_manager.sdk_connection user_id = conn.config.get_auth().get_user_id(conn.identity) diff --git a/openstackclient/tests/unit/identity/v3/test_application_credential.py b/openstackclient/tests/unit/identity/v3/test_application_credential.py index b53042ed1c..a4ecec5dc4 100644 --- a/openstackclient/tests/unit/identity/v3/test_application_credential.py +++ b/openstackclient/tests/unit/identity/v3/test_application_credential.py @@ -24,6 +24,7 @@ from openstack.identity.v3 import ( application_credential as _application_credential, ) from openstack.identity.v3 import role as _role +from openstack.identity.v3 import user as _user from openstack.test import fakes as sdk_fakes from openstackclient.identity.v3 import application_credential from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes @@ -325,6 +326,31 @@ class TestApplicationCredentialList(identity_fakes.TestIdentityv3): self.identity_sdk_client.application_credentials.return_value = [ self.application_credential ] + self.user = sdk_fakes.generate_fake_resource(resource_type=_user.User) + self.identity_sdk_client.find_user.return_value = self.user + + self.columns = ( + 'ID', + 'Name', + 'Description', + 'Project ID', + 'Roles', + 'Unrestricted', + 'Access Rules', + 'Expires At', + ) + self.data = ( + ( + self.application_credential.id, + self.application_credential.name, + self.application_credential.description, + self.application_credential.project_id, + '', + self.application_credential.unrestricted, + self.application_credential.access_rules, + self.application_credential.expires_at, + ), + ) # Get the command object to test self.cmd = application_credential.ListApplicationCredential( @@ -339,39 +365,35 @@ class TestApplicationCredentialList(identity_fakes.TestIdentityv3): conn = self.app.client_manager.sdk_connection user_id = conn.config.get_auth().get_user_id(conn.identity) - # In base command class Lister in cliff, abstract method take_action() - # returns a tuple containing the column names and an iterable - # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, tuple(data)) + + self.identity_sdk_client.find_user.assert_not_called() self.identity_sdk_client.application_credentials.assert_called_with( user=user_id ) - collist = ( - 'ID', - 'Name', - 'Description', - 'Project ID', - 'Roles', - 'Unrestricted', - 'Access Rules', - 'Expires At', + def test_application_credential_list_user(self): + arglist = ['--user', self.user.name] + verifylist = [] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + conn = self.app.client_manager.sdk_connection + conn.config.get_auth().get_user_id(conn.identity) + + columns, data = self.cmd.take_action(parsed_args) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, tuple(data)) + + self.identity_sdk_client.find_user.assert_called_once_with( + name_or_id=self.user.name, ignore_missing=False ) - self.assertEqual(collist, columns) - datalist = ( - ( - self.application_credential.id, - self.application_credential.name, - self.application_credential.description, - self.application_credential.project_id, - self.application_credential.roles, - self.application_credential.unrestricted, - self.application_credential.access_rules, - self.application_credential.expires_at, - ), + self.identity_sdk_client.application_credentials.assert_called_with( + user=self.user.id ) - self.assertEqual(datalist, tuple(data)) class TestApplicationCredentialShow(identity_fakes.TestIdentityv3):