identity: Normalise output of application credentials commands
cliff is now smarter (I9155763eee15e19eab23b48989dfcc19ea2c5d34), so we can effectively revert change I6b4f1b793dc383856bfdf9a01514381be3cd2bf1. We bump the dependencies to ensure this. Change-Id: I2af19043fd66b5be0826a774baeabeac7110a4aa Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from cliff import columns as cliff_columns
|
||||||
from osc_lib.command import command
|
from osc_lib.command import command
|
||||||
from osc_lib import exceptions
|
from osc_lib import exceptions
|
||||||
from osc_lib import utils
|
from osc_lib import utils
|
||||||
@@ -27,10 +28,84 @@ from osc_lib import utils
|
|||||||
from openstackclient.i18n import _
|
from openstackclient.i18n import _
|
||||||
from openstackclient.identity import common
|
from openstackclient.identity import common
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
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
|
# TODO(stephenfin): Move this to osc_lib since it's useful elsewhere
|
||||||
def is_uuid_like(value) -> bool:
|
def is_uuid_like(value) -> bool:
|
||||||
"""Returns validation of a value as a UUID.
|
"""Returns validation of a value as a UUID.
|
||||||
@@ -38,9 +113,6 @@ def is_uuid_like(value) -> bool:
|
|||||||
:param val: Value to verify
|
:param val: Value to verify
|
||||||
:type val: string
|
:type val: string
|
||||||
:returns: bool
|
:returns: bool
|
||||||
|
|
||||||
.. versionchanged:: 1.1.1
|
|
||||||
Support non-lowercase UUIDs.
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
formatted_value = (
|
formatted_value = (
|
||||||
@@ -179,31 +251,8 @@ class CreateApplicationCredential(command.ShowOne):
|
|||||||
access_rules=access_rules,
|
access_rules=access_rules,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Format roles into something sensible
|
return _format_application_credential(
|
||||||
if application_credential['roles']:
|
application_credential, include_secret=True
|
||||||
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,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -252,6 +301,8 @@ class DeleteApplicationCredential(command.Command):
|
|||||||
) % {'errors': errors, 'total': total}
|
) % {'errors': errors, 'total': total}
|
||||||
raise exceptions.CommandError(msg)
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ListApplicationCredential(command.Lister):
|
class ListApplicationCredential(command.Lister):
|
||||||
_description = _("List application credentials")
|
_description = _("List application credentials")
|
||||||
@@ -276,39 +327,12 @@ class ListApplicationCredential(command.Lister):
|
|||||||
conn = self.app.client_manager.sdk_connection
|
conn = self.app.client_manager.sdk_connection
|
||||||
user_id = conn.config.get_auth().get_user_id(conn.identity)
|
user_id = conn.config.get_auth().get_user_id(conn.identity)
|
||||||
|
|
||||||
data = identity_client.application_credentials(user=user_id)
|
application_credentials = 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
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return _format_application_credentials(application_credentials)
|
||||||
|
|
||||||
|
|
||||||
class ShowApplicationCredential(command.ShowOne):
|
class ShowApplicationCredential(command.ShowOne):
|
||||||
_description = _("Display application credential details")
|
_description = _("Display application credential details")
|
||||||
@@ -327,31 +351,8 @@ class ShowApplicationCredential(command.ShowOne):
|
|||||||
conn = self.app.client_manager.sdk_connection
|
conn = self.app.client_manager.sdk_connection
|
||||||
user_id = conn.config.get_auth().get_user_id(conn.identity)
|
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
|
user_id, parsed_args.application_credential
|
||||||
)
|
)
|
||||||
|
|
||||||
# Format roles into something sensible
|
return _format_application_credential(application_credential)
|
||||||
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,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
@@ -62,7 +62,7 @@ class AccessRuleTests(common.IdentityTests):
|
|||||||
|
|
||||||
items = self.parse_show_as_object(raw_output)
|
items = self.parse_show_as_object(raw_output)
|
||||||
self.access_rule_ids = [
|
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.addCleanup(
|
||||||
self.openstack,
|
self.openstack,
|
||||||
|
@@ -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',
|
||||||
|
@@ -31,18 +31,6 @@ from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
|
|||||||
|
|
||||||
|
|
||||||
class TestApplicationCredentialCreate(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()
|
||||||
|
|
||||||
@@ -52,12 +40,25 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
|
|||||||
roles=[],
|
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.id,
|
||||||
self.application_credential.name,
|
self.application_credential.name,
|
||||||
self.application_credential.description,
|
self.application_credential.description,
|
||||||
self.application_credential.project_id,
|
self.application_credential.project_id,
|
||||||
self.application_credential.roles,
|
application_credential.RolesColumn(
|
||||||
|
self.application_credential.roles
|
||||||
|
),
|
||||||
self.application_credential.unrestricted,
|
self.application_credential.unrestricted,
|
||||||
self.application_credential.access_rules,
|
self.application_credential.access_rules,
|
||||||
self.application_credential.expires_at,
|
self.application_credential.expires_at,
|
||||||
@@ -101,7 +102,7 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(self.columns, columns)
|
self.assertEqual(self.columns, columns)
|
||||||
self.assertEqual(self.datalist, data)
|
self.assertEqual(self.data, data)
|
||||||
|
|
||||||
def test_application_credential_create_with_options(self):
|
def test_application_credential_create_with_options(self):
|
||||||
name = self.application_credential.name
|
name = self.application_credential.name
|
||||||
@@ -147,7 +148,7 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(self.columns, columns)
|
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):
|
def test_application_credential_create_with_access_rules_string(self):
|
||||||
name = self.application_credential.name
|
name = self.application_credential.name
|
||||||
@@ -191,7 +192,7 @@ class TestApplicationCredentialCreate(identity_fakes.TestIdentityv3):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(self.columns, columns)
|
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.json.load')
|
||||||
@mock.patch('openstackclient.identity.v3.application_credential.open')
|
@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.columns, columns)
|
||||||
self.assertEqual(self.datalist, data)
|
self.assertEqual(self.data, data)
|
||||||
|
|
||||||
|
|
||||||
class TestApplicationCredentialDelete(identity_fakes.TestIdentityv3):
|
class TestApplicationCredentialDelete(identity_fakes.TestIdentityv3):
|
||||||
@@ -345,7 +346,9 @@ class TestApplicationCredentialList(identity_fakes.TestIdentityv3):
|
|||||||
self.application_credential.name,
|
self.application_credential.name,
|
||||||
self.application_credential.description,
|
self.application_credential.description,
|
||||||
self.application_credential.project_id,
|
self.application_credential.project_id,
|
||||||
'',
|
application_credential.RolesColumn(
|
||||||
|
self.application_credential.roles
|
||||||
|
),
|
||||||
self.application_credential.unrestricted,
|
self.application_credential.unrestricted,
|
||||||
self.application_credential.access_rules,
|
self.application_credential.access_rules,
|
||||||
self.application_credential.expires_at,
|
self.application_credential.expires_at,
|
||||||
@@ -408,6 +411,29 @@ class TestApplicationCredentialShow(identity_fakes.TestIdentityv3):
|
|||||||
self.application_credential
|
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
|
# Get the command object to test
|
||||||
self.cmd = application_credential.ShowApplicationCredential(
|
self.cmd = application_credential.ShowApplicationCredential(
|
||||||
self.app, None
|
self.app, None
|
||||||
@@ -434,25 +460,5 @@ class TestApplicationCredentialShow(identity_fakes.TestIdentityv3):
|
|||||||
user_id, self.application_credential.id
|
user_id, self.application_credential.id
|
||||||
)
|
)
|
||||||
|
|
||||||
collist = (
|
self.assertEqual(self.columns, columns)
|
||||||
'id',
|
self.assertEqual(self.data, data)
|
||||||
'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)
|
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||||
|
|
||||||
cryptography>=2.7 # BSD/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
|
iso8601>=0.1.11 # MIT
|
||||||
openstacksdk>=4.5.0 # Apache-2.0
|
openstacksdk>=4.5.0 # Apache-2.0
|
||||||
osc-lib>=2.3.0 # Apache-2.0
|
osc-lib>=2.3.0 # Apache-2.0
|
||||||
|
Reference in New Issue
Block a user