Merge "identity: Migrate 'application credential' commands to SDK"

This commit is contained in:
Zuul 2024-07-12 13:54:38 +00:00 committed by Gerrit Code Review
commit 7de15cee16
4 changed files with 344 additions and 276 deletions

View File

@ -18,6 +18,7 @@
import datetime import datetime
import json import json
import logging import logging
import uuid
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
@ -30,6 +31,30 @@ from openstackclient.identity import common
LOG = logging.getLogger(__name__) 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): class CreateApplicationCredential(command.ShowOne):
_description = _("Create new application credential") _description = _("Create new application credential")
@ -105,19 +130,16 @@ class CreateApplicationCredential(command.ShowOne):
return parser return parser
def take_action(self, parsed_args): 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 = [] role_ids = []
for role in parsed_args.role: for role in parsed_args.role:
# A user can only create an application credential for themself, if is_uuid_like(role):
# not for another user even as an admin, and only on the project to role_ids.append({'id': role})
# which they are currently scoped with a subset of the role else:
# assignments they have on that project. Don't bother trying to role_ids.append({'name': role})
# look up roles via keystone, just introspect the token.
role_id = common._get_token_resource(
identity_client, "roles", role
)
role_ids.append(role_id)
expires_at = None expires_at = None
if parsed_args.expiration: if parsed_args.expiration:
@ -144,10 +166,10 @@ class CreateApplicationCredential(command.ShowOne):
) )
raise exceptions.CommandError(msg) raise exceptions.CommandError(msg)
else: else:
access_rules = None access_rules = []
app_cred_manager = identity_client.application_credentials application_credential = identity_client.create_application_credential(
application_credential = app_cred_manager.create( user_id,
parsed_args.name, parsed_args.name,
roles=role_ids, roles=role_ids,
expires_at=expires_at, expires_at=expires_at,
@ -157,14 +179,32 @@ class CreateApplicationCredential(command.ShowOne):
access_rules=access_rules, access_rules=access_rules,
) )
application_credential._info.pop('links', None)
# Format roles into something sensible # Format roles into something sensible
roles = application_credential._info.pop('roles') if application_credential['roles']:
msg = ' '.join(r['name'] for r in roles) roles = application_credential['roles']
application_credential._info['roles'] = msg 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): class DeleteApplicationCredential(command.Command):
@ -181,15 +221,19 @@ class DeleteApplicationCredential(command.Command):
return parser return parser
def take_action(self, parsed_args): 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 errors = 0
for ac in parsed_args.application_credential: for ac in parsed_args.application_credential:
try: try:
app_cred = utils.find_resource( app_cred = identity_client.find_application_credential(
identity_client.application_credentials, ac 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: except Exception as e:
errors += 1 errors += 1
LOG.error( LOG.error(
@ -223,16 +267,36 @@ class ListApplicationCredential(command.Lister):
return parser return parser
def take_action(self, parsed_args): 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: if parsed_args.user:
user_id = common.find_user( user_id = common.find_user(
identity_client, parsed_args.user, parsed_args.user_domain identity_client, parsed_args.user, parsed_args.user_domain
).id ).id
else: 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(user=user_id)
data = identity_client.application_credentials.list(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 ( return (
columns, columns,
( (
@ -241,7 +305,7 @@ class ListApplicationCredential(command.Lister):
columns, columns,
formatters={}, formatters={},
) )
for s in data for s in data_formatted
), ),
) )
@ -259,17 +323,35 @@ class ShowApplicationCredential(command.ShowOne):
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity identity_client = self.app.client_manager.sdk_connection.identity
app_cred = utils.find_resource( conn = self.app.client_manager.sdk_connection
identity_client.application_credentials, user_id = conn.config.get_auth().get_user_id(conn.identity)
parsed_args.application_credential,
app_cred = identity_client.find_application_credential(
user_id, parsed_args.application_credential
) )
app_cred._info.pop('links', None)
# Format roles into something sensible # Format roles into something sensible
roles = app_cred._info.pop('roles') roles = app_cred['roles']
msg = ' '.join(r['name'] for r in 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,
)
),
)

View File

@ -21,13 +21,13 @@ from openstackclient.tests.functional.identity.v3 import common
class ApplicationCredentialTests(common.IdentityTests): class ApplicationCredentialTests(common.IdentityTests):
APPLICATION_CREDENTIAL_FIELDS = [ APPLICATION_CREDENTIAL_FIELDS = [
'id', 'ID',
'name', 'Name',
'project_id', 'Project ID',
'description', 'Description',
'roles', 'Roles',
'expires_at', 'Expires At',
'unrestricted', 'Unrestricted',
] ]
APPLICATION_CREDENTIAL_LIST_HEADERS = [ APPLICATION_CREDENTIAL_LIST_HEADERS = [
'ID', 'ID',

View File

@ -13,37 +13,58 @@
# under the License. # under the License.
# #
import copy import datetime
import json
from unittest import mock from unittest import mock
from unittest.mock import call
from osc_lib import exceptions 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.identity.v3 import application_credential
from openstackclient.tests.unit import fakes
from openstackclient.tests.unit.identity.v3 import fakes as identity_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): def setUp(self):
super().setUp() super().setUp()
identity_manager = self.identity_client self.roles = sdk_fakes.generate_fake_resource(_role.Role)
self.app_creds_mock = identity_manager.application_credentials self.application_credential = sdk_fakes.generate_fake_resource(
self.app_creds_mock.reset_mock() resource_type=_application_credential.ApplicationCredential,
self.roles_mock = identity_manager.roles roles=[],
self.roles_mock.reset_mock() )
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): self.identity_sdk_client.create_application_credential.return_value = (
def setUp(self): self.application_credential
super().setUp()
self.roles_mock.get.return_value = fakes.FakeResource(
None,
copy.deepcopy(identity_fakes.ROLE),
loaded=True,
) )
# Get the command object to test # Get the command object to test
@ -52,17 +73,14 @@ class TestApplicationCredentialCreate(TestApplicationCredential):
) )
def test_application_credential_create_basic(self): def test_application_credential_create_basic(self):
self.app_creds_mock.create.return_value = fakes.FakeResource( name = self.application_credential.name
None,
copy.deepcopy(identity_fakes.APP_CRED_BASIC),
loaded=True,
)
name = identity_fakes.app_cred_name
arglist = [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) 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() # 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 # returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown. # data to be shown.
@ -70,68 +88,45 @@ class TestApplicationCredentialCreate(TestApplicationCredential):
# Set expected values # Set expected values
kwargs = { kwargs = {
'secret': None,
'roles': [], 'roles': [],
'expires_at': None, 'expires_at': None,
'description': None, 'description': None,
'secret': None,
'unrestricted': False, '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 = ( self.assertEqual(self.columns, columns)
'access_rules', self.assertEqual(self.datalist, data)
'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)
def test_application_credential_create_with_options(self): def test_application_credential_create_with_options(self):
name = identity_fakes.app_cred_name name = self.application_credential.name
self.app_creds_mock.create.return_value = fakes.FakeResource(
None,
copy.deepcopy(identity_fakes.APP_CRED_OPTIONS),
loaded=True,
)
arglist = [ arglist = [
name, name,
'--secret', '--secret',
'moresecuresecret', 'moresecuresecret',
'--role', '--role',
identity_fakes.role_id, self.roles.id,
'--expiration', '--expiration',
identity_fakes.app_cred_expires_str, '2024-01-01T00:00:00',
'--description', '--description',
'credential for testing', 'credential for testing',
] ]
verifylist = [ verifylist = [
('name', identity_fakes.app_cred_name), ('name', self.application_credential.name),
('secret', 'moresecuresecret'), ('secret', 'moresecuresecret'),
('role', [identity_fakes.role_id]), ('role', [self.roles.id]),
('expiration', identity_fakes.app_cred_expires_str), ('expiration', '2024-01-01T00:00:00'),
('description', 'credential for testing'), ('description', 'credential for testing'),
] ]
parsed_args = self.check_parser(self.cmd, arglist, 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 ShowOne in cliff, abstract method take_action() # 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 # returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown. # data to be shown.
@ -139,172 +134,119 @@ class TestApplicationCredentialCreate(TestApplicationCredential):
# Set expected values # Set expected values
kwargs = { kwargs = {
'secret': 'moresecuresecret', 'roles': [{'id': self.roles.id}],
'roles': [identity_fakes.role_id], 'expires_at': datetime.datetime(2024, 1, 1, 0, 0),
'expires_at': identity_fakes.app_cred_expires,
'description': 'credential for testing', 'description': 'credential for testing',
'secret': 'moresecuresecret',
'unrestricted': False, '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 = ( self.assertEqual(self.columns, columns)
'access_rules', self.assertEqual(self.datalist, data)
'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)
def test_application_credential_create_with_access_rules_string(self): def test_application_credential_create_with_access_rules_string(self):
name = identity_fakes.app_cred_name name = self.application_credential.name
self.app_creds_mock.create.return_value = fakes.FakeResource(
None,
copy.deepcopy(identity_fakes.APP_CRED_ACCESS_RULES),
loaded=True,
)
arglist = [ arglist = [
name, name,
'--access-rules', '--access-rules',
identity_fakes.app_cred_access_rules, '[{"path": "/v2.1/servers", "method": "GET", "service": "compute"}]',
] ]
verifylist = [ verifylist = [
('name', identity_fakes.app_cred_name), ('name', self.application_credential.name),
('access_rules', identity_fakes.app_cred_access_rules), (
'access_rules',
'[{"path": "/v2.1/servers", "method": "GET", "service": "compute"}]',
),
] ]
parsed_args = self.check_parser(self.cmd, arglist, 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)
columns, data = self.cmd.take_action(parsed_args) columns, data = self.cmd.take_action(parsed_args)
# Set expected values # Set expected values
kwargs = { kwargs = {
'secret': None,
'roles': [], 'roles': [],
'expires_at': None, 'expires_at': None,
'description': None, 'description': None,
'secret': None,
'unrestricted': False, '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 = ( self.assertEqual(self.columns, columns)
'access_rules', self.assertEqual(self.datalist, data)
'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)
@mock.patch('openstackclient.identity.v3.application_credential.json.load') @mock.patch('openstackclient.identity.v3.application_credential.json.load')
@mock.patch('openstackclient.identity.v3.application_credential.open') @mock.patch('openstackclient.identity.v3.application_credential.open')
def test_application_credential_create_with_access_rules_file( def test_application_credential_create_with_access_rules_file(
self, _, mock_json_load self, _, mock_json_load
): ):
mock_json_load.return_value = identity_fakes.app_cred_access_rules mock_json_load.return_value = '/tmp/access_rules.json'
name = self.application_credential.name
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,
)
arglist = [ arglist = [
name, name,
'--access-rules', '--access-rules',
identity_fakes.app_cred_access_rules_path, '/tmp/access_rules.json',
] ]
verifylist = [ verifylist = [
('name', identity_fakes.app_cred_name), ('name', self.application_credential.name),
('access_rules', identity_fakes.app_cred_access_rules_path), ('access_rules', '/tmp/access_rules.json'),
] ]
parsed_args = self.check_parser(self.cmd, arglist, 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)
columns, data = self.cmd.take_action(parsed_args) columns, data = self.cmd.take_action(parsed_args)
# Set expected values # Set expected values
kwargs = { kwargs = {
'secret': None,
'roles': [], 'roles': [],
'expires_at': None, 'expires_at': None,
'description': None, 'description': None,
'secret': None,
'unrestricted': False, '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) 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 = ( self.assertEqual(self.columns, columns)
identity_fakes.app_cred_access_rules, self.assertEqual(self.datalist, data)
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)
class TestApplicationCredentialDelete(TestApplicationCredential): class TestApplicationCredentialDelete(identity_fakes.TestIdentityv3):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# This is the return value for utils.find_resource() self.application_credential = sdk_fakes.generate_fake_resource(
self.app_creds_mock.get.return_value = fakes.FakeResource( resource_type=_application_credential.ApplicationCredential,
None, roles=[],
copy.deepcopy(identity_fakes.APP_CRED_BASIC), )
loaded=True, 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 # Get the command object to test
self.cmd = application_credential.DeleteApplicationCredential( self.cmd = application_credential.DeleteApplicationCredential(
@ -313,26 +255,31 @@ class TestApplicationCredentialDelete(TestApplicationCredential):
def test_application_credential_delete(self): def test_application_credential_delete(self):
arglist = [ 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) 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) result = self.cmd.take_action(parsed_args)
self.app_creds_mock.delete.assert_called_with( self.identity_sdk_client.delete_application_credential.assert_called_with(
identity_fakes.app_cred_id, user_id,
self.application_credential.id,
) )
self.assertIsNone(result) self.assertIsNone(result)
@mock.patch.object(utils, 'find_resource') def test_delete_multi_app_creds_with_exception(self):
def test_delete_multi_app_creds_with_exception(self, find_mock): self.identity_sdk_client.find_application_credential.side_effect = [
find_mock.side_effect = [ self.application_credential,
self.app_creds_mock.get.return_value, sdk_exceptions.NotFoundException,
exceptions.CommandError,
] ]
arglist = [ arglist = [
identity_fakes.app_cred_id, self.application_credential.id,
'nonexistent_app_cred', 'nonexistent_app_cred',
] ]
verifylist = [ verifylist = [
@ -340,6 +287,9 @@ class TestApplicationCredentialDelete(TestApplicationCredential):
] ]
parsed_args = self.check_parser(self.cmd, arglist, 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)
try: try:
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.fail('CommandError should be raised.') self.fail('CommandError should be raised.')
@ -348,27 +298,32 @@ class TestApplicationCredentialDelete(TestApplicationCredential):
'1 of 2 application credentials failed to' ' delete.', str(e) '1 of 2 application credentials failed to' ' delete.', str(e)
) )
find_mock.assert_any_call( calls = []
self.app_creds_mock, identity_fakes.app_cred_id for a in arglist:
) calls.append(call(user_id, a))
find_mock.assert_any_call(self.app_creds_mock, 'nonexistent_app_cred')
self.assertEqual(2, find_mock.call_count) self.identity_sdk_client.find_application_credential.assert_has_calls(
self.app_creds_mock.delete.assert_called_once_with( calls
identity_fakes.app_cred_id )
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): def setUp(self):
super().setUp() super().setUp()
self.app_creds_mock.list.return_value = [ self.application_credential = sdk_fakes.generate_fake_resource(
fakes.FakeResource( resource_type=_application_credential.ApplicationCredential,
None, roles=[],
copy.deepcopy(identity_fakes.APP_CRED_BASIC), )
loaded=True, self.identity_sdk_client.application_credentials.return_value = [
), self.application_credential
] ]
# Get the command object to test # Get the command object to test
@ -381,35 +336,54 @@ class TestApplicationCredentialList(TestApplicationCredential):
verifylist = [] verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, 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() # In base command class Lister in cliff, abstract method take_action()
# returns a tuple containing the column names and an iterable # returns a tuple containing the column names and an iterable
# containing the data to be listed. # containing the data to be listed.
columns, data = self.cmd.take_action(parsed_args) 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) self.assertEqual(collist, columns)
datalist = ( datalist = (
( (
identity_fakes.app_cred_id, self.application_credential.id,
identity_fakes.app_cred_name, self.application_credential.name,
identity_fakes.project_id, self.application_credential.description,
None, self.application_credential.project_id,
None, self.application_credential.roles,
self.application_credential.unrestricted,
self.application_credential.access_rules,
self.application_credential.expires_at,
), ),
) )
self.assertEqual(datalist, tuple(data)) self.assertEqual(datalist, tuple(data))
class TestApplicationCredentialShow(TestApplicationCredential): class TestApplicationCredentialShow(identity_fakes.TestIdentityv3):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.app_creds_mock.get.return_value = fakes.FakeResource( self.application_credential = sdk_fakes.generate_fake_resource(
None, resource_type=_application_credential.ApplicationCredential,
copy.deepcopy(identity_fakes.APP_CRED_BASIC), roles=[],
loaded=True, )
self.identity_sdk_client.find_application_credential.return_value = (
self.application_credential
) )
# Get the command object to test # Get the command object to test
@ -419,41 +393,44 @@ class TestApplicationCredentialShow(TestApplicationCredential):
def test_application_credential_show(self): def test_application_credential_show(self):
arglist = [ arglist = [
identity_fakes.app_cred_id, self.application_credential.id,
] ]
verifylist = [ verifylist = [
('application_credential', identity_fakes.app_cred_id), ('application_credential', self.application_credential.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, 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 ShowOne in cliff, abstract method take_action() # 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 # returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown. # data to be shown.
columns, data = self.cmd.take_action(parsed_args) 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 = ( collist = (
'access_rules', 'ID',
'description', 'Name',
'expires_at', 'Description',
'id', 'Project ID',
'name', 'Roles',
'project_id', 'Unrestricted',
'roles', 'Access Rules',
'secret', 'Expires At',
'unrestricted',
) )
self.assertEqual(collist, columns) self.assertEqual(collist, columns)
datalist = ( datalist = (
None, self.application_credential.id,
None, self.application_credential.name,
None, self.application_credential.description,
identity_fakes.app_cred_id, self.application_credential.project_id,
identity_fakes.app_cred_name, self.application_credential.roles,
identity_fakes.project_id, self.application_credential.unrestricted,
identity_fakes.role_name, self.application_credential.access_rules,
identity_fakes.app_cred_secret, self.application_credential.expires_at,
False,
) )
self.assertEqual(datalist, data) self.assertEqual(datalist, data)

View File

@ -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``