Skip to content

Commit bef8a7a

Browse files
committed
identity: Migrate 'application credential' commands to SDK
Change-Id: Iba3fee2672d32266623c6f367beaabe84bd3d24e
1 parent dd6ac28 commit bef8a7a

4 files changed

Lines changed: 346 additions & 278 deletions

File tree

openstackclient/identity/v3/application_credential.py

Lines changed: 122 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import datetime
1919
import json
2020
import logging
21+
import uuid
2122

2223
from osc_lib.command import command
2324
from osc_lib import exceptions
@@ -30,6 +31,30 @@
3031
LOG = logging.getLogger(__name__)
3132

3233

34+
# TODO(stephenfin): Move this to osc_lib since it's useful elsewhere
35+
def is_uuid_like(value) -> bool:
36+
"""Returns validation of a value as a UUID.
37+
38+
:param val: Value to verify
39+
:type val: string
40+
:returns: bool
41+
42+
.. versionchanged:: 1.1.1
43+
Support non-lowercase UUIDs.
44+
"""
45+
try:
46+
formatted_value = (
47+
value.replace('urn:', '')
48+
.replace('uuid:', '')
49+
.strip('{}')
50+
.replace('-', '')
51+
.lower()
52+
)
53+
return str(uuid.UUID(value)).replace('-', '') == formatted_value
54+
except (TypeError, ValueError, AttributeError):
55+
return False
56+
57+
3358
class CreateApplicationCredential(command.ShowOne):
3459
_description = _("Create new application credential")
3560

@@ -105,19 +130,16 @@ def get_parser(self, prog_name):
105130
return parser
106131

107132
def take_action(self, parsed_args):
108-
identity_client = self.app.client_manager.identity
133+
identity_client = self.app.client_manager.sdk_connection.identity
134+
conn = self.app.client_manager.sdk_connection
135+
user_id = conn.config.get_auth().get_user_id(conn.identity)
109136

110137
role_ids = []
111138
for role in parsed_args.role:
112-
# A user can only create an application credential for themself,
113-
# not for another user even as an admin, and only on the project to
114-
# which they are currently scoped with a subset of the role
115-
# assignments they have on that project. Don't bother trying to
116-
# look up roles via keystone, just introspect the token.
117-
role_id = common._get_token_resource(
118-
identity_client, "roles", role
119-
)
120-
role_ids.append(role_id)
139+
if is_uuid_like(role):
140+
role_ids.append({'id': role})
141+
else:
142+
role_ids.append({'name': role})
121143

122144
expires_at = None
123145
if parsed_args.expiration:
@@ -144,10 +166,10 @@ def take_action(self, parsed_args):
144166
)
145167
raise exceptions.CommandError(msg)
146168
else:
147-
access_rules = None
169+
access_rules = []
148170

149-
app_cred_manager = identity_client.application_credentials
150-
application_credential = app_cred_manager.create(
171+
application_credential = identity_client.create_application_credential(
172+
user_id,
151173
parsed_args.name,
152174
roles=role_ids,
153175
expires_at=expires_at,
@@ -157,14 +179,32 @@ def take_action(self, parsed_args):
157179
access_rules=access_rules,
158180
)
159181

160-
application_credential._info.pop('links', None)
161-
162182
# Format roles into something sensible
163-
roles = application_credential._info.pop('roles')
164-
msg = ' '.join(r['name'] for r in roles)
165-
application_credential._info['roles'] = msg
166-
167-
return zip(*sorted(application_credential._info.items()))
183+
if application_credential['roles']:
184+
roles = application_credential['roles']
185+
msg = ' '.join(r['name'] for r in roles)
186+
application_credential['roles'] = msg
187+
188+
columns = (
189+
'ID',
190+
'Name',
191+
'Description',
192+
'Project ID',
193+
'Roles',
194+
'Unrestricted',
195+
'Access Rules',
196+
'Expires At',
197+
'Secret',
198+
)
199+
return (
200+
columns,
201+
(
202+
utils.get_dict_properties(
203+
application_credential,
204+
columns,
205+
)
206+
),
207+
)
168208

169209

170210
class DeleteApplicationCredential(command.Command):
@@ -181,15 +221,19 @@ def get_parser(self, prog_name):
181221
return parser
182222

183223
def take_action(self, parsed_args):
184-
identity_client = self.app.client_manager.identity
224+
identity_client = self.app.client_manager.sdk_connection.identity
225+
conn = self.app.client_manager.sdk_connection
226+
user_id = conn.config.get_auth().get_user_id(conn.identity)
185227

186228
errors = 0
187229
for ac in parsed_args.application_credential:
188230
try:
189-
app_cred = utils.find_resource(
190-
identity_client.application_credentials, ac
231+
app_cred = identity_client.find_application_credential(
232+
user_id, ac
233+
)
234+
identity_client.delete_application_credential(
235+
user_id, app_cred.id
191236
)
192-
identity_client.application_credentials.delete(app_cred.id)
193237
except Exception as e:
194238
errors += 1
195239
LOG.error(
@@ -223,16 +267,36 @@ def get_parser(self, prog_name):
223267
return parser
224268

225269
def take_action(self, parsed_args):
226-
identity_client = self.app.client_manager.identity
270+
identity_client = self.app.client_manager.sdk_connection.identity
227271
if parsed_args.user:
228272
user_id = common.find_user(
229273
identity_client, parsed_args.user, parsed_args.user_domain
230274
).id
231275
else:
232-
user_id = None
233-
234-
columns = ('ID', 'Name', 'Project ID', 'Description', 'Expires At')
235-
data = identity_client.application_credentials.list(user=user_id)
276+
conn = self.app.client_manager.sdk_connection
277+
user_id = conn.config.get_auth().get_user_id(conn.identity)
278+
279+
data = identity_client.application_credentials(user=user_id)
280+
281+
data_formatted = []
282+
for ac in data:
283+
# Format roles into something sensible
284+
roles = ac['roles']
285+
msg = ' '.join(r['name'] for r in roles)
286+
ac['roles'] = msg
287+
288+
data_formatted.append(ac)
289+
290+
columns = (
291+
'ID',
292+
'Name',
293+
'Description',
294+
'Project ID',
295+
'Roles',
296+
'Unrestricted',
297+
'Access Rules',
298+
'Expires At',
299+
)
236300
return (
237301
columns,
238302
(
@@ -241,7 +305,7 @@ def take_action(self, parsed_args):
241305
columns,
242306
formatters={},
243307
)
244-
for s in data
308+
for s in data_formatted
245309
),
246310
)
247311

@@ -259,17 +323,35 @@ def get_parser(self, prog_name):
259323
return parser
260324

261325
def take_action(self, parsed_args):
262-
identity_client = self.app.client_manager.identity
263-
app_cred = utils.find_resource(
264-
identity_client.application_credentials,
265-
parsed_args.application_credential,
266-
)
326+
identity_client = self.app.client_manager.sdk_connection.identity
327+
conn = self.app.client_manager.sdk_connection
328+
user_id = conn.config.get_auth().get_user_id(conn.identity)
267329

268-
app_cred._info.pop('links', None)
330+
app_cred = identity_client.find_application_credential(
331+
user_id, parsed_args.application_credential
332+
)
269333

270334
# Format roles into something sensible
271-
roles = app_cred._info.pop('roles')
335+
roles = app_cred['roles']
272336
msg = ' '.join(r['name'] for r in roles)
273-
app_cred._info['roles'] = msg
274-
275-
return zip(*sorted(app_cred._info.items()))
337+
app_cred['roles'] = msg
338+
339+
columns = (
340+
'ID',
341+
'Name',
342+
'Description',
343+
'Project ID',
344+
'Roles',
345+
'Unrestricted',
346+
'Access Rules',
347+
'Expires At',
348+
)
349+
return (
350+
columns,
351+
(
352+
utils.get_dict_properties(
353+
app_cred,
354+
columns,
355+
)
356+
),
357+
)

openstackclient/tests/functional/identity/v3/test_application_credential.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121

2222
class ApplicationCredentialTests(common.IdentityTests):
2323
APPLICATION_CREDENTIAL_FIELDS = [
24-
'id',
25-
'name',
26-
'project_id',
27-
'description',
28-
'roles',
29-
'expires_at',
30-
'unrestricted',
24+
'ID',
25+
'Name',
26+
'Project ID',
27+
'Description',
28+
'Roles',
29+
'Expires At',
30+
'Unrestricted',
3131
]
3232
APPLICATION_CREDENTIAL_LIST_HEADERS = [
3333
'ID',

0 commit comments

Comments
 (0)