Merge "identity: Normalise output of application credentials commands"

This commit is contained in:
Zuul
2025-05-26 16:03:37 +00:00
committed by Gerrit Code Review
5 changed files with 142 additions and 135 deletions

@ -20,6 +20,7 @@ import json
import logging
import uuid
from cliff import columns as cliff_columns
from osc_lib.command import command
from osc_lib import exceptions
from osc_lib import utils
@ -27,10 +28,84 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common
LOG = logging.getLogger(__name__)
class RolesColumn(cliff_columns.FormattableColumn):
"""Generate a formatted string of role names."""
def human_readable(self):
return utils.format_list(r['name'] for r in self._value)
def _format_application_credential(
application_credential, *, include_secret=False
):
column_headers: tuple[str, ...] = (
'ID',
'Name',
'Description',
'Project ID',
'Roles',
'Unrestricted',
'Access Rules',
'Expires At',
)
columns: tuple[str, ...] = (
'id',
'name',
'description',
'project_id',
'roles',
'unrestricted',
'access_rules',
'expires_at',
)
if include_secret:
column_headers += ('Secret',)
columns += ('secret',)
return (
column_headers,
utils.get_item_properties(
application_credential, columns, formatters={'roles': RolesColumn}
),
)
def _format_application_credentials(application_credentials):
column_headers = (
'ID',
'Name',
'Description',
'Project ID',
'Roles',
'Unrestricted',
'Access Rules',
'Expires At',
)
columns = (
'id',
'name',
'description',
'project_id',
'roles',
'unrestricted',
'access_rules',
'expires_at',
)
return (
column_headers,
(
utils.get_item_properties(
x, columns, formatters={'roles': RolesColumn}
)
for x in application_credentials
),
)
# 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.
@ -38,9 +113,6 @@ def is_uuid_like(value) -> bool:
:param val: Value to verify
:type val: string
:returns: bool
.. versionchanged:: 1.1.1
Support non-lowercase UUIDs.
"""
try:
formatted_value = (
@ -179,31 +251,8 @@ class CreateApplicationCredential(command.ShowOne):
access_rules=access_rules,
)
# Format roles into something sensible
if application_credential['roles']:
roles = application_credential['roles']
msg = ' '.join(r['name'] for r in roles)
application_credential['roles'] = msg
columns = (
'id',
'name',
'description',
'project_id',
'roles',
'unrestricted',
'access_rules',
'expires_at',
'secret',
)
return (
columns,
(
utils.get_dict_properties(
application_credential,
columns,
)
),
return _format_application_credential(
application_credential, include_secret=True
)
@ -252,6 +301,8 @@ class DeleteApplicationCredential(command.Command):
) % {'errors': errors, 'total': total}
raise exceptions.CommandError(msg)
return None
class ListApplicationCredential(command.Lister):
_description = _("List application credentials")
@ -276,39 +327,12 @@ class ListApplicationCredential(command.Lister):
conn = self.app.client_manager.sdk_connection
user_id = conn.config.get_auth().get_user_id(conn.identity)
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,
(
utils.get_item_properties(
s,
columns,
formatters={},
)
for s in data_formatted
),
application_credentials = identity_client.application_credentials(
user=user_id
)
return _format_application_credentials(application_credentials)
class ShowApplicationCredential(command.ShowOne):
_description = _("Display application credential details")
@ -327,31 +351,8 @@ class ShowApplicationCredential(command.ShowOne):
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(
application_credential = identity_client.find_application_credential(
user_id, parsed_args.application_credential
)
# Format roles into something sensible
roles = app_cred['roles']
msg = ' '.join(r['name'] for r in roles)
app_cred['roles'] = msg
columns = (
'id',
'name',
'description',
'project_id',
'roles',
'unrestricted',
'access_rules',
'expires_at',
)
return (
columns,
(
utils.get_dict_properties(
app_cred,
columns,
)
),
)
return _format_application_credential(application_credential)

@ -62,7 +62,7 @@ class AccessRuleTests(common.IdentityTests):
items = self.parse_show_as_object(raw_output)
self.access_rule_ids = [
x['id'] for x in ast.literal_eval(items['access_rules'])
x['id'] for x in ast.literal_eval(items['Access Rules'])
]
self.addCleanup(
self.openstack,

@ -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',

@ -31,18 +31,6 @@ from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
columns = (
'id',
'name',
'description',
'project_id',
'roles',
'unrestricted',
'access_rules',
'expires_at',
'secret',
)
def setUp(self):
super().setUp()
@ -52,12 +40,25 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
roles=[],
)
self.datalist = (
self.columns = (
'ID',
'Name',
'Description',
'Project ID',
'Roles',
'Unrestricted',
'Access Rules',
'Expires At',
'Secret',
)
self.data = (
self.application_credential.id,
self.application_credential.name,
self.application_credential.description,
self.application_credential.project_id,
self.application_credential.roles,
application_credential.RolesColumn(
self.application_credential.roles
),
self.application_credential.unrestricted,
self.application_credential.access_rules,
self.application_credential.expires_at,
@ -101,7 +102,7 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.assertEqual(self.data, data)
def test_application_credential_create_with_options(self):
name = self.application_credential.name
@ -147,7 +148,7 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.assertEqual(self.data, data)
def test_application_credential_create_with_access_rules_string(self):
name = self.application_credential.name
@ -191,7 +192,7 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.assertEqual(self.data, data)
@mock.patch('openstackclient.identity.v3.application_credential.json.load')
@mock.patch('openstackclient.identity.v3.application_credential.open')
@ -231,7 +232,7 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.assertEqual(self.data, data)
class TestApplicationCredentialDelete(identity_fakes.TestIdentityv3):
@ -345,7 +346,9 @@ class TestApplicationCredentialList(identity_fakes.TestIdentityv3):
self.application_credential.name,
self.application_credential.description,
self.application_credential.project_id,
'',
application_credential.RolesColumn(
self.application_credential.roles
),
self.application_credential.unrestricted,
self.application_credential.access_rules,
self.application_credential.expires_at,
@ -408,6 +411,29 @@ class TestApplicationCredentialShow(identity_fakes.TestIdentityv3):
self.application_credential
)
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,
application_credential.RolesColumn(
self.application_credential.roles
),
self.application_credential.unrestricted,
self.application_credential.access_rules,
self.application_credential.expires_at,
)
# Get the command object to test
self.cmd = application_credential.ShowApplicationCredential(
self.app, None
@ -434,25 +460,5 @@ class TestApplicationCredentialShow(identity_fakes.TestIdentityv3):
user_id, self.application_credential.id
)
collist = (
'id',
'name',
'description',
'project_id',
'roles',
'unrestricted',
'access_rules',
'expires_at',
)
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.assertEqual(datalist, data)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)

@ -5,7 +5,7 @@
pbr!=2.1.0,>=2.0.0 # Apache-2.0
cryptography>=2.7 # BSD/Apache-2.0
cliff>=3.5.0 # Apache-2.0
cliff>=4.8.0 # Apache-2.0
iso8601>=0.1.11 # MIT
openstacksdk>=4.5.0 # Apache-2.0
osc-lib>=2.3.0 # Apache-2.0