From bef8a7a63098f903bcd2a9d42f2f37458602340f Mon Sep 17 00:00:00 2001 From: Antonia Gaete Date: Wed, 26 Jun 2024 15:54:44 +0000 Subject: [PATCH] identity: Migrate 'application credential' commands to SDK Change-Id: Iba3fee2672d32266623c6f367beaabe84bd3d24e --- .../identity/v3/application_credential.py | 156 +++++-- .../v3/test_application_credential.py | 14 +- .../v3/test_application_credential.py | 441 +++++++++--------- ...on-credential-to-sdk-c79d8dfc3c8e1d9f.yaml | 9 + 4 files changed, 344 insertions(+), 276 deletions(-) create mode 100644 releasenotes/notes/migrate-application-credential-to-sdk-c79d8dfc3c8e1d9f.yaml diff --git a/openstackclient/identity/v3/application_credential.py b/openstackclient/identity/v3/application_credential.py index cffab99274..035be2d212 100644 --- a/openstackclient/identity/v3/application_credential.py +++ b/openstackclient/identity/v3/application_credential.py @@ -18,6 +18,7 @@ import datetime import json import logging +import uuid from osc_lib.command import command from osc_lib import exceptions @@ -30,6 +31,30 @@ from openstackclient.identity import common LOG = logging.getLogger(__name__) +# TODO(stephenfin): Move this to osc_lib since it's useful elsewhere +def is_uuid_like(value) -> bool: + """Returns validation of a value as a UUID. + + :param val: Value to verify + :type val: string + :returns: bool + + .. versionchanged:: 1.1.1 + Support non-lowercase UUIDs. + """ + try: + formatted_value = ( + value.replace('urn:', '') + .replace('uuid:', '') + .strip('{}') + .replace('-', '') + .lower() + ) + return str(uuid.UUID(value)).replace('-', '') == formatted_value + except (TypeError, ValueError, AttributeError): + return False + + class CreateApplicationCredential(command.ShowOne): _description = _("Create new application credential") @@ -105,19 +130,16 @@ class CreateApplicationCredential(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) role_ids = [] for role in parsed_args.role: - # A user can only create an application credential for themself, - # not for another user even as an admin, and only on the project to - # which they are currently scoped with a subset of the role - # assignments they have on that project. Don't bother trying to - # look up roles via keystone, just introspect the token. - role_id = common._get_token_resource( - identity_client, "roles", role - ) - role_ids.append(role_id) + if is_uuid_like(role): + role_ids.append({'id': role}) + else: + role_ids.append({'name': role}) expires_at = None if parsed_args.expiration: @@ -144,10 +166,10 @@ class CreateApplicationCredential(command.ShowOne): ) raise exceptions.CommandError(msg) else: - access_rules = None + access_rules = [] - app_cred_manager = identity_client.application_credentials - application_credential = app_cred_manager.create( + application_credential = identity_client.create_application_credential( + user_id, parsed_args.name, roles=role_ids, expires_at=expires_at, @@ -157,14 +179,32 @@ class CreateApplicationCredential(command.ShowOne): access_rules=access_rules, ) - application_credential._info.pop('links', None) - # Format roles into something sensible - roles = application_credential._info.pop('roles') - msg = ' '.join(r['name'] for r in roles) - application_credential._info['roles'] = msg + if application_credential['roles']: + roles = application_credential['roles'] + msg = ' '.join(r['name'] for r in roles) + application_credential['roles'] = msg - return zip(*sorted(application_credential._info.items())) + columns = ( + 'ID', + 'Name', + 'Description', + 'Project ID', + 'Roles', + 'Unrestricted', + 'Access Rules', + 'Expires At', + 'Secret', + ) + return ( + columns, + ( + utils.get_dict_properties( + application_credential, + columns, + ) + ), + ) class DeleteApplicationCredential(command.Command): @@ -181,15 +221,19 @@ class DeleteApplicationCredential(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) errors = 0 for ac in parsed_args.application_credential: try: - app_cred = utils.find_resource( - identity_client.application_credentials, ac + app_cred = identity_client.find_application_credential( + user_id, ac + ) + identity_client.delete_application_credential( + user_id, app_cred.id ) - identity_client.application_credentials.delete(app_cred.id) except Exception as e: errors += 1 LOG.error( @@ -223,16 +267,36 @@ class ListApplicationCredential(command.Lister): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity if parsed_args.user: user_id = common.find_user( identity_client, parsed_args.user, parsed_args.user_domain ).id else: - user_id = None + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) - columns = ('ID', 'Name', 'Project ID', 'Description', 'Expires At') - data = identity_client.application_credentials.list(user=user_id) + data = identity_client.application_credentials(user=user_id) + + data_formatted = [] + for ac in data: + # Format roles into something sensible + roles = ac['roles'] + msg = ' '.join(r['name'] for r in roles) + ac['roles'] = msg + + data_formatted.append(ac) + + columns = ( + 'ID', + 'Name', + 'Description', + 'Project ID', + 'Roles', + 'Unrestricted', + 'Access Rules', + 'Expires At', + ) return ( columns, ( @@ -241,7 +305,7 @@ class ListApplicationCredential(command.Lister): columns, formatters={}, ) - for s in data + for s in data_formatted ), ) @@ -259,17 +323,35 @@ class ShowApplicationCredential(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity - app_cred = utils.find_resource( - identity_client.application_credentials, - parsed_args.application_credential, + identity_client = self.app.client_manager.sdk_connection.identity + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) + + app_cred = identity_client.find_application_credential( + user_id, parsed_args.application_credential ) - app_cred._info.pop('links', None) - # Format roles into something sensible - roles = app_cred._info.pop('roles') + roles = app_cred['roles'] msg = ' '.join(r['name'] for r in roles) - app_cred._info['roles'] = msg + app_cred['roles'] = msg - return zip(*sorted(app_cred._info.items())) + columns = ( + 'ID', + 'Name', + 'Description', + 'Project ID', + 'Roles', + 'Unrestricted', + 'Access Rules', + 'Expires At', + ) + return ( + columns, + ( + utils.get_dict_properties( + app_cred, + columns, + ) + ), + ) diff --git a/openstackclient/tests/functional/identity/v3/test_application_credential.py b/openstackclient/tests/functional/identity/v3/test_application_credential.py index 22f2b90bb4..9c8b0462ff 100644 --- a/openstackclient/tests/functional/identity/v3/test_application_credential.py +++ b/openstackclient/tests/functional/identity/v3/test_application_credential.py @@ -21,13 +21,13 @@ from openstackclient.tests.functional.identity.v3 import common class ApplicationCredentialTests(common.IdentityTests): APPLICATION_CREDENTIAL_FIELDS = [ - 'id', - 'name', - 'project_id', - 'description', - 'roles', - 'expires_at', - 'unrestricted', + 'ID', + 'Name', + 'Project ID', + 'Description', + 'Roles', + 'Expires At', + 'Unrestricted', ] APPLICATION_CREDENTIAL_LIST_HEADERS = [ 'ID', diff --git a/openstackclient/tests/unit/identity/v3/test_application_credential.py b/openstackclient/tests/unit/identity/v3/test_application_credential.py index d9c3531ddd..277204dd45 100644 --- a/openstackclient/tests/unit/identity/v3/test_application_credential.py +++ b/openstackclient/tests/unit/identity/v3/test_application_credential.py @@ -13,37 +13,58 @@ # under the License. # -import copy -import json +import datetime from unittest import mock +from unittest.mock import call from osc_lib import exceptions -from osc_lib import utils +from openstack import exceptions as sdk_exceptions +from openstack.identity.v3 import ( + application_credential as _application_credential, +) +from openstack.identity.v3 import role as _role +from openstack.test import fakes as sdk_fakes from openstackclient.identity.v3 import application_credential -from openstackclient.tests.unit import fakes from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes -class TestApplicationCredential(identity_fakes.TestIdentityv3): +class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3): + columns = ( + 'ID', + 'Name', + 'Description', + 'Project ID', + 'Roles', + 'Unrestricted', + 'Access Rules', + 'Expires At', + 'Secret', + ) + def setUp(self): super().setUp() - identity_manager = self.identity_client - self.app_creds_mock = identity_manager.application_credentials - self.app_creds_mock.reset_mock() - self.roles_mock = identity_manager.roles - self.roles_mock.reset_mock() + self.roles = sdk_fakes.generate_fake_resource(_role.Role) + self.application_credential = sdk_fakes.generate_fake_resource( + resource_type=_application_credential.ApplicationCredential, + roles=[], + ) + self.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.application_credential.secret, + ) -class TestApplicationCredentialCreate(TestApplicationCredential): - def setUp(self): - super().setUp() - - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, + self.identity_sdk_client.create_application_credential.return_value = ( + self.application_credential ) # Get the command object to test @@ -52,17 +73,14 @@ class TestApplicationCredentialCreate(TestApplicationCredential): ) def test_application_credential_create_basic(self): - self.app_creds_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.APP_CRED_BASIC), - loaded=True, - ) - - name = identity_fakes.app_cred_name + name = self.application_credential.name arglist = [name] - verifylist = [('name', identity_fakes.app_cred_name)] + verifylist = [('name', self.application_credential.name)] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) + # In base command class ShowOne in cliff, abstract method take_action() # returns a two-part tuple with a tuple of column names and a tuple of # data to be shown. @@ -70,68 +88,45 @@ class TestApplicationCredentialCreate(TestApplicationCredential): # Set expected values kwargs = { - 'secret': None, 'roles': [], 'expires_at': None, 'description': None, + 'secret': None, 'unrestricted': False, - 'access_rules': None, + 'access_rules': [], } - self.app_creds_mock.create.assert_called_with(name, **kwargs) + self.identity_sdk_client.create_application_credential.assert_called_with( + user_id, name, **kwargs + ) - collist = ( - 'access_rules', - 'description', - 'expires_at', - 'id', - 'name', - 'project_id', - 'roles', - 'secret', - 'unrestricted', - ) - self.assertEqual(collist, columns) - datalist = ( - None, - None, - None, - identity_fakes.app_cred_id, - identity_fakes.app_cred_name, - identity_fakes.project_id, - identity_fakes.role_name, - identity_fakes.app_cred_secret, - False, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_application_credential_create_with_options(self): - name = identity_fakes.app_cred_name - self.app_creds_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.APP_CRED_OPTIONS), - loaded=True, - ) - + name = self.application_credential.name arglist = [ name, '--secret', 'moresecuresecret', '--role', - identity_fakes.role_id, + self.roles.id, '--expiration', - identity_fakes.app_cred_expires_str, + '2024-01-01T00:00:00', '--description', 'credential for testing', ] verifylist = [ - ('name', identity_fakes.app_cred_name), + ('name', self.application_credential.name), ('secret', 'moresecuresecret'), - ('role', [identity_fakes.role_id]), - ('expiration', identity_fakes.app_cred_expires_str), + ('role', [self.roles.id]), + ('expiration', '2024-01-01T00:00:00'), ('description', 'credential for testing'), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) + # In base command class ShowOne in cliff, abstract method take_action() # returns a two-part tuple with a tuple of column names and a tuple of # data to be shown. @@ -139,172 +134,119 @@ class TestApplicationCredentialCreate(TestApplicationCredential): # Set expected values kwargs = { - 'secret': 'moresecuresecret', - 'roles': [identity_fakes.role_id], - 'expires_at': identity_fakes.app_cred_expires, + 'roles': [{'id': self.roles.id}], + 'expires_at': datetime.datetime(2024, 1, 1, 0, 0), 'description': 'credential for testing', + 'secret': 'moresecuresecret', 'unrestricted': False, - 'access_rules': None, + 'access_rules': [], } - self.app_creds_mock.create.assert_called_with(name, **kwargs) + self.identity_sdk_client.create_application_credential.assert_called_with( + user_id, name, **kwargs + ) - collist = ( - 'access_rules', - 'description', - 'expires_at', - 'id', - 'name', - 'project_id', - 'roles', - 'secret', - 'unrestricted', - ) - self.assertEqual(collist, columns) - datalist = ( - None, - identity_fakes.app_cred_description, - identity_fakes.app_cred_expires_str, - identity_fakes.app_cred_id, - identity_fakes.app_cred_name, - identity_fakes.project_id, - identity_fakes.role_name, - identity_fakes.app_cred_secret, - False, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_application_credential_create_with_access_rules_string(self): - name = identity_fakes.app_cred_name - self.app_creds_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.APP_CRED_ACCESS_RULES), - loaded=True, - ) + name = self.application_credential.name arglist = [ name, '--access-rules', - identity_fakes.app_cred_access_rules, + '[{"path": "/v2.1/servers", "method": "GET", "service": "compute"}]', ] verifylist = [ - ('name', identity_fakes.app_cred_name), - ('access_rules', identity_fakes.app_cred_access_rules), + ('name', self.application_credential.name), + ( + 'access_rules', + '[{"path": "/v2.1/servers", "method": "GET", "service": "compute"}]', + ), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) + columns, data = self.cmd.take_action(parsed_args) # Set expected values kwargs = { - 'secret': None, 'roles': [], 'expires_at': None, 'description': None, + 'secret': None, 'unrestricted': False, - 'access_rules': json.loads(identity_fakes.app_cred_access_rules), + 'access_rules': [ + { + "path": "/v2.1/servers", + "method": "GET", + "service": "compute", + } + ], } - self.app_creds_mock.create.assert_called_with(name, **kwargs) + self.identity_sdk_client.create_application_credential.assert_called_with( + user_id, name, **kwargs + ) - collist = ( - 'access_rules', - 'description', - 'expires_at', - 'id', - 'name', - 'project_id', - 'roles', - 'secret', - 'unrestricted', - ) - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.app_cred_access_rules, - None, - None, - identity_fakes.app_cred_id, - identity_fakes.app_cred_name, - identity_fakes.project_id, - identity_fakes.role_name, - identity_fakes.app_cred_secret, - False, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) @mock.patch('openstackclient.identity.v3.application_credential.json.load') @mock.patch('openstackclient.identity.v3.application_credential.open') def test_application_credential_create_with_access_rules_file( self, _, mock_json_load ): - mock_json_load.return_value = identity_fakes.app_cred_access_rules - - name = identity_fakes.app_cred_name - self.app_creds_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.APP_CRED_ACCESS_RULES), - loaded=True, - ) + mock_json_load.return_value = '/tmp/access_rules.json' + name = self.application_credential.name arglist = [ name, '--access-rules', - identity_fakes.app_cred_access_rules_path, + '/tmp/access_rules.json', ] verifylist = [ - ('name', identity_fakes.app_cred_name), - ('access_rules', identity_fakes.app_cred_access_rules_path), + ('name', self.application_credential.name), + ('access_rules', '/tmp/access_rules.json'), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) + columns, data = self.cmd.take_action(parsed_args) # Set expected values kwargs = { - 'secret': None, 'roles': [], 'expires_at': None, 'description': None, + 'secret': None, 'unrestricted': False, - 'access_rules': identity_fakes.app_cred_access_rules, + 'access_rules': '/tmp/access_rules.json', } - self.app_creds_mock.create.assert_called_with(name, **kwargs) - - collist = ( - 'access_rules', - 'description', - 'expires_at', - 'id', - 'name', - 'project_id', - 'roles', - 'secret', - 'unrestricted', + self.identity_sdk_client.create_application_credential.assert_called_with( + user_id, name, **kwargs ) - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.app_cred_access_rules, - None, - None, - identity_fakes.app_cred_id, - identity_fakes.app_cred_name, - identity_fakes.project_id, - identity_fakes.role_name, - identity_fakes.app_cred_secret, - False, - ) - self.assertEqual(datalist, data) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) -class TestApplicationCredentialDelete(TestApplicationCredential): +class TestApplicationCredentialDelete(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - # This is the return value for utils.find_resource() - self.app_creds_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.APP_CRED_BASIC), - loaded=True, + self.application_credential = sdk_fakes.generate_fake_resource( + resource_type=_application_credential.ApplicationCredential, + roles=[], + ) + self.identity_sdk_client.find_application_credential.return_value = ( + self.application_credential + ) + self.identity_sdk_client.delete_application_credential.return_value = ( + None ) - self.app_creds_mock.delete.return_value = None # Get the command object to test self.cmd = application_credential.DeleteApplicationCredential( @@ -313,26 +255,31 @@ class TestApplicationCredentialDelete(TestApplicationCredential): def test_application_credential_delete(self): arglist = [ - identity_fakes.app_cred_id, + self.application_credential.id, + ] + verifylist = [ + ('application_credential', [self.application_credential.id]) ] - verifylist = [('application_credential', [identity_fakes.app_cred_id])] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) + result = self.cmd.take_action(parsed_args) - self.app_creds_mock.delete.assert_called_with( - identity_fakes.app_cred_id, + self.identity_sdk_client.delete_application_credential.assert_called_with( + user_id, + self.application_credential.id, ) self.assertIsNone(result) - @mock.patch.object(utils, 'find_resource') - def test_delete_multi_app_creds_with_exception(self, find_mock): - find_mock.side_effect = [ - self.app_creds_mock.get.return_value, - exceptions.CommandError, + def test_delete_multi_app_creds_with_exception(self): + self.identity_sdk_client.find_application_credential.side_effect = [ + self.application_credential, + sdk_exceptions.NotFoundException, ] arglist = [ - identity_fakes.app_cred_id, + self.application_credential.id, 'nonexistent_app_cred', ] verifylist = [ @@ -340,6 +287,9 @@ class TestApplicationCredentialDelete(TestApplicationCredential): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) + try: self.cmd.take_action(parsed_args) self.fail('CommandError should be raised.') @@ -348,27 +298,32 @@ class TestApplicationCredentialDelete(TestApplicationCredential): '1 of 2 application credentials failed to' ' delete.', str(e) ) - find_mock.assert_any_call( - self.app_creds_mock, identity_fakes.app_cred_id - ) - find_mock.assert_any_call(self.app_creds_mock, 'nonexistent_app_cred') + calls = [] + for a in arglist: + calls.append(call(user_id, a)) - self.assertEqual(2, find_mock.call_count) - self.app_creds_mock.delete.assert_called_once_with( - identity_fakes.app_cred_id + self.identity_sdk_client.find_application_credential.assert_has_calls( + calls + ) + + self.assertEqual( + 2, self.identity_sdk_client.find_application_credential.call_count + ) + self.identity_sdk_client.delete_application_credential.assert_called_once_with( + user_id, self.application_credential.id ) -class TestApplicationCredentialList(TestApplicationCredential): +class TestApplicationCredentialList(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.app_creds_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.APP_CRED_BASIC), - loaded=True, - ), + self.application_credential = sdk_fakes.generate_fake_resource( + resource_type=_application_credential.ApplicationCredential, + roles=[], + ) + self.identity_sdk_client.application_credentials.return_value = [ + self.application_credential ] # Get the command object to test @@ -381,35 +336,54 @@ class TestApplicationCredentialList(TestApplicationCredential): verifylist = [] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + 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.app_creds_mock.list.assert_called_with(user=None) + self.identity_sdk_client.application_credentials.assert_called_with( + user=user_id + ) - collist = ('ID', 'Name', 'Project ID', 'Description', 'Expires At') + collist = ( + 'ID', + 'Name', + 'Description', + 'Project ID', + 'Roles', + 'Unrestricted', + 'Access Rules', + 'Expires At', + ) self.assertEqual(collist, columns) datalist = ( ( - identity_fakes.app_cred_id, - identity_fakes.app_cred_name, - identity_fakes.project_id, - None, - None, + 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.assertEqual(datalist, tuple(data)) -class TestApplicationCredentialShow(TestApplicationCredential): +class TestApplicationCredentialShow(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.app_creds_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.APP_CRED_BASIC), - loaded=True, + self.application_credential = sdk_fakes.generate_fake_resource( + resource_type=_application_credential.ApplicationCredential, + roles=[], + ) + self.identity_sdk_client.find_application_credential.return_value = ( + self.application_credential ) # Get the command object to test @@ -419,41 +393,44 @@ class TestApplicationCredentialShow(TestApplicationCredential): def test_application_credential_show(self): arglist = [ - identity_fakes.app_cred_id, + self.application_credential.id, ] verifylist = [ - ('application_credential', identity_fakes.app_cred_id), + ('application_credential', self.application_credential.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + conn = self.app.client_manager.sdk_connection + user_id = conn.config.get_auth().get_user_id(conn.identity) + # In base command class ShowOne in cliff, abstract method take_action() # returns a two-part tuple with a tuple of column names and a tuple of # data to be shown. columns, data = self.cmd.take_action(parsed_args) - self.app_creds_mock.get.assert_called_with(identity_fakes.app_cred_id) + self.identity_sdk_client.find_application_credential.assert_called_with( + user_id, self.application_credential.id + ) collist = ( - 'access_rules', - 'description', - 'expires_at', - 'id', - 'name', - 'project_id', - 'roles', - 'secret', - 'unrestricted', + 'ID', + 'Name', + 'Description', + 'Project ID', + 'Roles', + 'Unrestricted', + 'Access Rules', + 'Expires At', ) self.assertEqual(collist, columns) datalist = ( - None, - None, - None, - identity_fakes.app_cred_id, - identity_fakes.app_cred_name, - identity_fakes.project_id, - identity_fakes.role_name, - identity_fakes.app_cred_secret, - False, + 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.assertEqual(datalist, data) diff --git a/releasenotes/notes/migrate-application-credential-to-sdk-c79d8dfc3c8e1d9f.yaml b/releasenotes/notes/migrate-application-credential-to-sdk-c79d8dfc3c8e1d9f.yaml new file mode 100644 index 0000000000..22b7a2971f --- /dev/null +++ b/releasenotes/notes/migrate-application-credential-to-sdk-c79d8dfc3c8e1d9f.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + The following commands have been migrated to SDK: + + - ``application credential create`` + - ``application credential delete`` + - ``application credential list`` + - ``application credential show``