python-openstackclient 8.0.0__py3-none-any.whl → 8.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openstackclient/api/compute_v2.py +2 -2
- openstackclient/api/volume_v2.py +60 -0
- openstackclient/api/volume_v3.py +60 -0
- openstackclient/compute/client.py +5 -0
- openstackclient/compute/v2/console.py +7 -0
- openstackclient/compute/v2/console_connection.py +48 -0
- openstackclient/compute/v2/flavor.py +14 -1
- openstackclient/compute/v2/keypair.py +10 -3
- openstackclient/compute/v2/server.py +76 -13
- openstackclient/compute/v2/server_event.py +1 -1
- openstackclient/identity/common.py +85 -11
- openstackclient/identity/v3/application_credential.py +88 -87
- openstackclient/identity/v3/domain.py +67 -49
- openstackclient/identity/v3/group.py +113 -68
- openstackclient/identity/v3/project.py +42 -20
- openstackclient/identity/v3/role.py +7 -2
- openstackclient/identity/v3/user.py +38 -5
- openstackclient/image/client.py +5 -0
- openstackclient/image/v1/image.py +16 -1
- openstackclient/image/v2/cache.py +10 -6
- openstackclient/image/v2/image.py +59 -12
- openstackclient/image/v2/metadef_objects.py +8 -2
- openstackclient/image/v2/metadef_properties.py +9 -2
- openstackclient/network/client.py +0 -6
- openstackclient/network/v2/floating_ip.py +58 -29
- openstackclient/network/v2/network_qos_rule.py +3 -11
- openstackclient/network/v2/port.py +16 -0
- openstackclient/network/v2/router.py +1 -1
- openstackclient/network/v2/security_group.py +49 -7
- openstackclient/network/v2/security_group_rule.py +18 -1
- openstackclient/shell.py +1 -1
- openstackclient/tests/functional/base.py +5 -1
- openstackclient/tests/functional/compute/v2/test_keypair.py +41 -5
- openstackclient/tests/functional/identity/v3/test_access_rule.py +1 -1
- openstackclient/tests/functional/identity/v3/test_application_credential.py +7 -7
- openstackclient/tests/functional/image/v2/test_image.py +36 -14
- openstackclient/tests/functional/volume/v2/test_volume.py +1 -1
- openstackclient/tests/functional/volume/v3/test_volume.py +2 -2
- openstackclient/tests/unit/api/test_volume_v2.py +124 -0
- openstackclient/tests/unit/api/test_volume_v3.py +124 -0
- openstackclient/tests/unit/compute/v2/fakes.py +81 -305
- openstackclient/tests/unit/compute/v2/test_console.py +18 -1
- openstackclient/tests/unit/compute/v2/test_console_connection.py +72 -0
- openstackclient/tests/unit/compute/v2/test_flavor.py +160 -175
- openstackclient/tests/unit/compute/v2/test_keypair.py +12 -5
- openstackclient/tests/unit/compute/v2/test_server.py +211 -97
- openstackclient/tests/unit/compute/v2/test_server_backup.py +32 -71
- openstackclient/tests/unit/compute/v2/test_server_event.py +2 -2
- openstackclient/tests/unit/compute/v2/test_server_image.py +33 -72
- openstackclient/tests/unit/compute/v2/test_server_migration.py +4 -4
- openstackclient/tests/unit/identity/v3/test_application_credential.py +93 -65
- openstackclient/tests/unit/identity/v3/test_domain.py +117 -107
- openstackclient/tests/unit/identity/v3/test_group.py +353 -202
- openstackclient/tests/unit/identity/v3/test_project.py +46 -53
- openstackclient/tests/unit/identity/v3/test_role.py +2 -8
- openstackclient/tests/unit/identity/v3/test_user.py +86 -6
- openstackclient/tests/unit/image/v1/test_image.py +55 -9
- openstackclient/tests/unit/image/v2/test_image.py +128 -58
- openstackclient/tests/unit/image/v2/test_metadef_objects.py +22 -0
- openstackclient/tests/unit/image/v2/test_metadef_properties.py +24 -10
- openstackclient/tests/unit/network/v2/fakes.py +406 -485
- openstackclient/tests/unit/network/v2/test_floating_ip_network.py +13 -19
- openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +2 -2
- openstackclient/tests/unit/network/v2/test_ndp_proxy.py +3 -5
- openstackclient/tests/unit/network/v2/test_network.py +4 -4
- openstackclient/tests/unit/network/v2/test_network_agent.py +15 -29
- openstackclient/tests/unit/network/v2/test_network_qos_policy.py +16 -19
- openstackclient/tests/unit/network/v2/test_network_qos_rule.py +79 -152
- openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +4 -6
- openstackclient/tests/unit/network/v2/test_network_rbac.py +2 -2
- openstackclient/tests/unit/network/v2/test_port.py +57 -17
- openstackclient/tests/unit/network/v2/test_router.py +73 -57
- openstackclient/tests/unit/network/v2/test_security_group_network.py +31 -27
- openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +1 -3
- openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +82 -39
- openstackclient/tests/unit/volume/v2/fakes.py +1 -2
- openstackclient/tests/unit/volume/v2/test_service.py +57 -91
- openstackclient/tests/unit/volume/v2/test_volume.py +466 -410
- openstackclient/tests/unit/volume/v2/test_volume_backup.py +141 -148
- openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +293 -283
- openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +61 -71
- openstackclient/tests/unit/volume/v3/test_service.py +221 -141
- openstackclient/tests/unit/volume/v3/test_volume.py +569 -534
- openstackclient/tests/unit/volume/v3/test_volume_attachment.py +1 -1
- openstackclient/tests/unit/volume/v3/test_volume_backup.py +198 -203
- openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +682 -47
- openstackclient/volume/v2/service.py +41 -38
- openstackclient/volume/v2/volume.py +140 -88
- openstackclient/volume/v2/volume_backup.py +9 -3
- openstackclient/volume/v2/volume_snapshot.py +121 -84
- openstackclient/volume/v3/block_storage_log_level.py +22 -28
- openstackclient/volume/v3/service.py +105 -14
- openstackclient/volume/v3/volume.py +287 -99
- openstackclient/volume/v3/volume_backup.py +24 -19
- openstackclient/volume/v3/volume_group.py +1 -1
- openstackclient/volume/v3/volume_snapshot.py +485 -10
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/AUTHORS +13 -0
- python_openstackclient-8.2.0.dist-info/METADATA +264 -0
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/RECORD +104 -98
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/entry_points.txt +7 -6
- python_openstackclient-8.2.0.dist-info/pbr.json +1 -0
- python_openstackclient-8.0.0.dist-info/METADATA +0 -166
- python_openstackclient-8.0.0.dist-info/pbr.json +0 -1
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/LICENSE +0 -0
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/WHEEL +0 -0
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import logging
|
|
19
19
|
|
|
20
|
-
from
|
|
20
|
+
from openstack import exceptions as sdk_exc
|
|
21
21
|
from osc_lib.command import command
|
|
22
22
|
from osc_lib import exceptions
|
|
23
23
|
from osc_lib import utils
|
|
@@ -29,6 +29,25 @@ from openstackclient.identity import common
|
|
|
29
29
|
LOG = logging.getLogger(__name__)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
def _format_group(group):
|
|
33
|
+
columns = (
|
|
34
|
+
'description',
|
|
35
|
+
'domain_id',
|
|
36
|
+
'id',
|
|
37
|
+
'name',
|
|
38
|
+
)
|
|
39
|
+
column_headers = (
|
|
40
|
+
'description',
|
|
41
|
+
'domain_id',
|
|
42
|
+
'id',
|
|
43
|
+
'name',
|
|
44
|
+
)
|
|
45
|
+
return (
|
|
46
|
+
column_headers,
|
|
47
|
+
utils.get_item_properties(group, columns),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
32
51
|
class AddUserToGroup(command.Command):
|
|
33
52
|
_description = _("Add user to group")
|
|
34
53
|
|
|
@@ -53,19 +72,19 @@ class AddUserToGroup(command.Command):
|
|
|
53
72
|
return parser
|
|
54
73
|
|
|
55
74
|
def take_action(self, parsed_args):
|
|
56
|
-
identity_client = self.app.client_manager.identity
|
|
75
|
+
identity_client = self.app.client_manager.sdk_connection.identity
|
|
57
76
|
|
|
58
|
-
group_id = common.
|
|
77
|
+
group_id = common.find_group_id_sdk(
|
|
59
78
|
identity_client, parsed_args.group, parsed_args.group_domain
|
|
60
|
-
)
|
|
79
|
+
)
|
|
61
80
|
|
|
62
81
|
result = 0
|
|
63
82
|
for i in parsed_args.user:
|
|
64
83
|
try:
|
|
65
|
-
user_id = common.
|
|
84
|
+
user_id = common.find_user_id_sdk(
|
|
66
85
|
identity_client, i, parsed_args.user_domain
|
|
67
|
-
)
|
|
68
|
-
identity_client.
|
|
86
|
+
)
|
|
87
|
+
identity_client.add_user_to_group(user_id, group_id)
|
|
69
88
|
except Exception as e:
|
|
70
89
|
result += 1
|
|
71
90
|
msg = _("%(user)s not added to group %(group)s: %(e)s") % {
|
|
@@ -109,32 +128,41 @@ class CheckUserInGroup(command.Command):
|
|
|
109
128
|
return parser
|
|
110
129
|
|
|
111
130
|
def take_action(self, parsed_args):
|
|
112
|
-
identity_client = self.app.client_manager.identity
|
|
131
|
+
identity_client = self.app.client_manager.sdk_connection.identity
|
|
113
132
|
|
|
114
|
-
user_id = common.
|
|
115
|
-
identity_client,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
133
|
+
user_id = common.find_user_id_sdk(
|
|
134
|
+
identity_client,
|
|
135
|
+
parsed_args.user,
|
|
136
|
+
parsed_args.user_domain,
|
|
137
|
+
validate_actor_existence=False,
|
|
138
|
+
)
|
|
139
|
+
group_id = common.find_group_id_sdk(
|
|
140
|
+
identity_client,
|
|
141
|
+
parsed_args.group,
|
|
142
|
+
parsed_args.group_domain,
|
|
143
|
+
validate_actor_existence=False,
|
|
144
|
+
)
|
|
120
145
|
|
|
146
|
+
user_in_group = False
|
|
121
147
|
try:
|
|
122
|
-
identity_client.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
self.app.stderr.write(msg)
|
|
130
|
-
else:
|
|
131
|
-
raise e
|
|
132
|
-
else:
|
|
148
|
+
user_in_group = identity_client.check_user_in_group(
|
|
149
|
+
user_id, group_id
|
|
150
|
+
)
|
|
151
|
+
except sdk_exc.ForbiddenException:
|
|
152
|
+
# Assume False if forbidden
|
|
153
|
+
pass
|
|
154
|
+
if user_in_group:
|
|
133
155
|
msg = _("%(user)s in group %(group)s\n") % {
|
|
134
156
|
'user': parsed_args.user,
|
|
135
157
|
'group': parsed_args.group,
|
|
136
158
|
}
|
|
137
159
|
self.app.stdout.write(msg)
|
|
160
|
+
else:
|
|
161
|
+
msg = _("%(user)s not in group %(group)s\n") % {
|
|
162
|
+
'user': parsed_args.user,
|
|
163
|
+
'group': parsed_args.group,
|
|
164
|
+
}
|
|
165
|
+
self.app.stderr.write(msg)
|
|
138
166
|
|
|
139
167
|
|
|
140
168
|
class CreateGroup(command.ShowOne):
|
|
@@ -165,29 +193,33 @@ class CreateGroup(command.ShowOne):
|
|
|
165
193
|
return parser
|
|
166
194
|
|
|
167
195
|
def take_action(self, parsed_args):
|
|
168
|
-
identity_client = self.app.client_manager.identity
|
|
196
|
+
identity_client = self.app.client_manager.sdk_connection.identity
|
|
169
197
|
|
|
170
|
-
|
|
198
|
+
kwargs = {}
|
|
199
|
+
if parsed_args.name:
|
|
200
|
+
kwargs['name'] = parsed_args.name
|
|
201
|
+
if parsed_args.description:
|
|
202
|
+
kwargs['description'] = parsed_args.description
|
|
171
203
|
if parsed_args.domain:
|
|
172
|
-
|
|
204
|
+
kwargs['domain_id'] = common.find_domain_id_sdk(
|
|
205
|
+
identity_client, parsed_args.domain
|
|
206
|
+
)
|
|
173
207
|
|
|
174
208
|
try:
|
|
175
|
-
group = identity_client.
|
|
176
|
-
|
|
177
|
-
domain=domain,
|
|
178
|
-
description=parsed_args.description,
|
|
179
|
-
)
|
|
180
|
-
except ks_exc.Conflict:
|
|
209
|
+
group = identity_client.create_group(**kwargs)
|
|
210
|
+
except sdk_exc.ConflictException:
|
|
181
211
|
if parsed_args.or_show:
|
|
182
|
-
|
|
183
|
-
identity_client.
|
|
184
|
-
|
|
212
|
+
if parsed_args.domain:
|
|
213
|
+
group = identity_client.find_group(
|
|
214
|
+
parsed_args.name, domain_id=parsed_args.domain
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
group = identity_client.find_group(parsed_args.name)
|
|
185
218
|
LOG.info(_('Returning existing group %s'), group.name)
|
|
186
219
|
else:
|
|
187
220
|
raise
|
|
188
221
|
|
|
189
|
-
group
|
|
190
|
-
return zip(*sorted(group._info.items()))
|
|
222
|
+
return _format_group(group)
|
|
191
223
|
|
|
192
224
|
|
|
193
225
|
class DeleteGroup(command.Command):
|
|
@@ -209,15 +241,15 @@ class DeleteGroup(command.Command):
|
|
|
209
241
|
return parser
|
|
210
242
|
|
|
211
243
|
def take_action(self, parsed_args):
|
|
212
|
-
identity_client = self.app.client_manager.identity
|
|
244
|
+
identity_client = self.app.client_manager.sdk_connection.identity
|
|
213
245
|
|
|
214
246
|
errors = 0
|
|
215
247
|
for group in parsed_args.groups:
|
|
216
248
|
try:
|
|
217
|
-
|
|
249
|
+
group_id = common.find_group_id_sdk(
|
|
218
250
|
identity_client, group, parsed_args.domain
|
|
219
251
|
)
|
|
220
|
-
identity_client.
|
|
252
|
+
identity_client.delete_group(group_id)
|
|
221
253
|
except Exception as e:
|
|
222
254
|
errors += 1
|
|
223
255
|
LOG.error(
|
|
@@ -262,29 +294,37 @@ class ListGroup(command.Lister):
|
|
|
262
294
|
return parser
|
|
263
295
|
|
|
264
296
|
def take_action(self, parsed_args):
|
|
265
|
-
identity_client = self.app.client_manager.identity
|
|
297
|
+
identity_client = self.app.client_manager.sdk_connection.identity
|
|
266
298
|
|
|
267
299
|
domain = None
|
|
268
300
|
if parsed_args.domain:
|
|
269
|
-
domain = common.
|
|
301
|
+
domain = common.find_domain_id_sdk(
|
|
302
|
+
identity_client, parsed_args.domain
|
|
303
|
+
)
|
|
270
304
|
|
|
305
|
+
data = []
|
|
271
306
|
if parsed_args.user:
|
|
272
|
-
user = common.
|
|
307
|
+
user = common.find_user_id_sdk(
|
|
273
308
|
identity_client,
|
|
274
309
|
parsed_args.user,
|
|
275
310
|
parsed_args.user_domain,
|
|
276
|
-
)
|
|
311
|
+
)
|
|
312
|
+
if domain:
|
|
313
|
+
# NOTE(0weng): The API doesn't actually support filtering additionally by domain_id,
|
|
314
|
+
# so this doesn't really do anything.
|
|
315
|
+
data = identity_client.user_groups(user, domain_id=domain)
|
|
316
|
+
else:
|
|
317
|
+
data = identity_client.user_groups(user)
|
|
277
318
|
else:
|
|
278
|
-
|
|
319
|
+
if domain:
|
|
320
|
+
data = identity_client.groups(domain_id=domain)
|
|
321
|
+
else:
|
|
322
|
+
data = identity_client.groups()
|
|
279
323
|
|
|
280
324
|
# List groups
|
|
281
325
|
columns: tuple[str, ...] = ('ID', 'Name')
|
|
282
326
|
if parsed_args.long:
|
|
283
327
|
columns += ('Domain ID', 'Description')
|
|
284
|
-
data = identity_client.groups.list(
|
|
285
|
-
domain=domain,
|
|
286
|
-
user=user,
|
|
287
|
-
)
|
|
288
328
|
|
|
289
329
|
return (
|
|
290
330
|
columns,
|
|
@@ -323,19 +363,19 @@ class RemoveUserFromGroup(command.Command):
|
|
|
323
363
|
return parser
|
|
324
364
|
|
|
325
365
|
def take_action(self, parsed_args):
|
|
326
|
-
identity_client = self.app.client_manager.identity
|
|
366
|
+
identity_client = self.app.client_manager.sdk_connection.identity
|
|
327
367
|
|
|
328
|
-
group_id = common.
|
|
368
|
+
group_id = common.find_group_id_sdk(
|
|
329
369
|
identity_client, parsed_args.group, parsed_args.group_domain
|
|
330
|
-
)
|
|
370
|
+
)
|
|
331
371
|
|
|
332
372
|
result = 0
|
|
333
373
|
for i in parsed_args.user:
|
|
334
374
|
try:
|
|
335
|
-
user_id = common.
|
|
375
|
+
user_id = common.find_user_id_sdk(
|
|
336
376
|
identity_client, i, parsed_args.user_domain
|
|
337
|
-
)
|
|
338
|
-
identity_client.
|
|
377
|
+
)
|
|
378
|
+
identity_client.remove_user_from_group(user_id, group_id)
|
|
339
379
|
except Exception as e:
|
|
340
380
|
result += 1
|
|
341
381
|
msg = _("%(user)s not removed from group %(group)s: %(e)s") % {
|
|
@@ -387,8 +427,8 @@ class SetGroup(command.Command):
|
|
|
387
427
|
return parser
|
|
388
428
|
|
|
389
429
|
def take_action(self, parsed_args):
|
|
390
|
-
identity_client = self.app.client_manager.identity
|
|
391
|
-
group = common.
|
|
430
|
+
identity_client = self.app.client_manager.sdk_connection.identity
|
|
431
|
+
group = common.find_group_id_sdk(
|
|
392
432
|
identity_client, parsed_args.group, parsed_args.domain
|
|
393
433
|
)
|
|
394
434
|
kwargs = {}
|
|
@@ -397,7 +437,7 @@ class SetGroup(command.Command):
|
|
|
397
437
|
if parsed_args.description:
|
|
398
438
|
kwargs['description'] = parsed_args.description
|
|
399
439
|
|
|
400
|
-
identity_client.
|
|
440
|
+
identity_client.update_group(group, **kwargs)
|
|
401
441
|
|
|
402
442
|
|
|
403
443
|
class ShowGroup(command.ShowOne):
|
|
@@ -418,13 +458,18 @@ class ShowGroup(command.ShowOne):
|
|
|
418
458
|
return parser
|
|
419
459
|
|
|
420
460
|
def take_action(self, parsed_args):
|
|
421
|
-
identity_client = self.app.client_manager.identity
|
|
461
|
+
identity_client = self.app.client_manager.sdk_connection.identity
|
|
422
462
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
463
|
+
if parsed_args.domain:
|
|
464
|
+
domain = common.find_domain_id_sdk(
|
|
465
|
+
identity_client, parsed_args.domain
|
|
466
|
+
)
|
|
467
|
+
group = identity_client.find_group(
|
|
468
|
+
parsed_args.group, domain_id=domain, ignore_missing=False
|
|
469
|
+
)
|
|
470
|
+
else:
|
|
471
|
+
group = identity_client.find_group(
|
|
472
|
+
parsed_args.group, ignore_missing=False
|
|
473
|
+
)
|
|
428
474
|
|
|
429
|
-
group
|
|
430
|
-
return zip(*sorted(group._info.items()))
|
|
475
|
+
return _format_group(group)
|
|
@@ -59,17 +59,22 @@ class CreateProject(command.ShowOne):
|
|
|
59
59
|
enable_group.add_argument(
|
|
60
60
|
'--enable',
|
|
61
61
|
action='store_true',
|
|
62
|
+
dest='enabled',
|
|
63
|
+
default=True,
|
|
62
64
|
help=_('Enable project'),
|
|
63
65
|
)
|
|
64
66
|
enable_group.add_argument(
|
|
65
67
|
'--disable',
|
|
66
|
-
action='
|
|
68
|
+
action='store_false',
|
|
69
|
+
dest='enabled',
|
|
70
|
+
default=True,
|
|
67
71
|
help=_('Disable project'),
|
|
68
72
|
)
|
|
69
73
|
parser.add_argument(
|
|
70
74
|
'--property',
|
|
71
75
|
metavar='<key=value>',
|
|
72
76
|
action=parseractions.KeyValueAction,
|
|
77
|
+
dest='properties',
|
|
73
78
|
help=_(
|
|
74
79
|
'Add a property to <name> '
|
|
75
80
|
'(repeat option to set multiple properties)'
|
|
@@ -98,15 +103,9 @@ class CreateProject(command.ShowOne):
|
|
|
98
103
|
parsed_args.parent,
|
|
99
104
|
).id
|
|
100
105
|
|
|
101
|
-
enabled = True
|
|
102
|
-
if parsed_args.disable:
|
|
103
|
-
enabled = False
|
|
104
|
-
|
|
105
|
-
options = common.get_immutable_options(parsed_args)
|
|
106
|
-
|
|
107
106
|
kwargs = {}
|
|
108
|
-
if parsed_args.
|
|
109
|
-
kwargs = parsed_args.
|
|
107
|
+
if parsed_args.properties:
|
|
108
|
+
kwargs = parsed_args.properties.copy()
|
|
110
109
|
if 'is_domain' in kwargs.keys():
|
|
111
110
|
if kwargs['is_domain'].lower() == "true":
|
|
112
111
|
kwargs['is_domain'] = True
|
|
@@ -117,13 +116,17 @@ class CreateProject(command.ShowOne):
|
|
|
117
116
|
|
|
118
117
|
kwargs['tags'] = list(set(parsed_args.tags))
|
|
119
118
|
|
|
119
|
+
options = {}
|
|
120
|
+
if parsed_args.immutable is not None:
|
|
121
|
+
options['immutable'] = parsed_args.immutable
|
|
122
|
+
|
|
120
123
|
try:
|
|
121
124
|
project = identity_client.projects.create(
|
|
122
125
|
name=parsed_args.name,
|
|
123
126
|
domain=domain,
|
|
124
127
|
parent=parent,
|
|
125
128
|
description=parsed_args.description,
|
|
126
|
-
enabled=enabled,
|
|
129
|
+
enabled=parsed_args.enabled,
|
|
127
130
|
options=options,
|
|
128
131
|
**kwargs,
|
|
129
132
|
)
|
|
@@ -240,6 +243,20 @@ class ListProject(command.Lister):
|
|
|
240
243
|
'keys and directions.'
|
|
241
244
|
),
|
|
242
245
|
)
|
|
246
|
+
parser.add_argument(
|
|
247
|
+
'--enabled',
|
|
248
|
+
action='store_true',
|
|
249
|
+
dest='is_enabled',
|
|
250
|
+
default=None,
|
|
251
|
+
help=_('List only enabled projects'),
|
|
252
|
+
)
|
|
253
|
+
parser.add_argument(
|
|
254
|
+
'--disabled',
|
|
255
|
+
action='store_false',
|
|
256
|
+
dest='is_enabled',
|
|
257
|
+
default=None,
|
|
258
|
+
help=_('List only disabled projects'),
|
|
259
|
+
)
|
|
243
260
|
tag.add_tag_filtering_option_to_parser(parser, _('projects'))
|
|
244
261
|
return parser
|
|
245
262
|
|
|
@@ -277,6 +294,9 @@ class ListProject(command.Lister):
|
|
|
277
294
|
|
|
278
295
|
kwargs['user'] = user_id
|
|
279
296
|
|
|
297
|
+
if parsed_args.is_enabled is not None:
|
|
298
|
+
kwargs['is_enabled'] = parsed_args.is_enabled
|
|
299
|
+
|
|
280
300
|
tag.get_tag_filtering_args(parsed_args, kwargs)
|
|
281
301
|
|
|
282
302
|
if parsed_args.my_projects:
|
|
@@ -339,16 +359,21 @@ class SetProject(command.Command):
|
|
|
339
359
|
enable_group.add_argument(
|
|
340
360
|
'--enable',
|
|
341
361
|
action='store_true',
|
|
362
|
+
dest='enabled',
|
|
363
|
+
default=None,
|
|
342
364
|
help=_('Enable project'),
|
|
343
365
|
)
|
|
344
366
|
enable_group.add_argument(
|
|
345
367
|
'--disable',
|
|
346
|
-
action='
|
|
368
|
+
action='store_false',
|
|
369
|
+
dest='enabled',
|
|
370
|
+
default=None,
|
|
347
371
|
help=_('Disable project'),
|
|
348
372
|
)
|
|
349
373
|
parser.add_argument(
|
|
350
374
|
'--property',
|
|
351
375
|
metavar='<key=value>',
|
|
376
|
+
dest='properties',
|
|
352
377
|
action=parseractions.KeyValueAction,
|
|
353
378
|
help=_(
|
|
354
379
|
'Set a property on <project> '
|
|
@@ -371,15 +396,12 @@ class SetProject(command.Command):
|
|
|
371
396
|
kwargs['name'] = parsed_args.name
|
|
372
397
|
if parsed_args.description:
|
|
373
398
|
kwargs['description'] = parsed_args.description
|
|
374
|
-
if parsed_args.
|
|
375
|
-
kwargs['enabled'] =
|
|
376
|
-
if parsed_args.
|
|
377
|
-
kwargs['
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
kwargs['options'] = options
|
|
381
|
-
if parsed_args.property:
|
|
382
|
-
kwargs.update(parsed_args.property)
|
|
399
|
+
if parsed_args.enabled is not None:
|
|
400
|
+
kwargs['enabled'] = parsed_args.enabled
|
|
401
|
+
if parsed_args.immutable is not None:
|
|
402
|
+
kwargs['options'] = {'immutable': parsed_args.immutable}
|
|
403
|
+
if parsed_args.properties:
|
|
404
|
+
kwargs.update(parsed_args.properties)
|
|
383
405
|
tag.update_tags_in_args(parsed_args, project, kwargs)
|
|
384
406
|
|
|
385
407
|
identity_client.projects.update(project.id, **kwargs)
|
|
@@ -334,9 +334,12 @@ class CreateRole(command.ShowOne):
|
|
|
334
334
|
|
|
335
335
|
if parsed_args.name:
|
|
336
336
|
create_kwargs['name'] = parsed_args.name
|
|
337
|
+
|
|
337
338
|
if parsed_args.description:
|
|
338
339
|
create_kwargs['description'] = parsed_args.description
|
|
339
|
-
|
|
340
|
+
|
|
341
|
+
if parsed_args.immutable is not None:
|
|
342
|
+
create_kwargs['options'] = {"immutable": parsed_args.immutable}
|
|
340
343
|
|
|
341
344
|
try:
|
|
342
345
|
role = identity_client.create_role(**create_kwargs)
|
|
@@ -585,7 +588,9 @@ class SetRole(command.Command):
|
|
|
585
588
|
)
|
|
586
589
|
update_kwargs["domain_id"] = domain_id
|
|
587
590
|
|
|
588
|
-
|
|
591
|
+
if parsed_args.immutable is not None:
|
|
592
|
+
update_kwargs["options"] = {"immutable": parsed_args.immutable}
|
|
593
|
+
|
|
589
594
|
role = _find_sdk_id(
|
|
590
595
|
identity_client.find_role,
|
|
591
596
|
name_or_id=parsed_args.role,
|
|
@@ -41,6 +41,7 @@ def _format_user(user):
|
|
|
41
41
|
'name',
|
|
42
42
|
'description',
|
|
43
43
|
'password_expires_at',
|
|
44
|
+
'options',
|
|
44
45
|
)
|
|
45
46
|
column_headers = (
|
|
46
47
|
'default_project_id',
|
|
@@ -51,6 +52,7 @@ def _format_user(user):
|
|
|
51
52
|
'name',
|
|
52
53
|
'description',
|
|
53
54
|
'password_expires_at',
|
|
55
|
+
'options',
|
|
54
56
|
)
|
|
55
57
|
return (
|
|
56
58
|
column_headers,
|
|
@@ -289,7 +291,7 @@ class CreateUser(command.ShowOne):
|
|
|
289
291
|
elif parsed_args.password_prompt:
|
|
290
292
|
password = utils.get_password(self.app.stdin)
|
|
291
293
|
|
|
292
|
-
if not
|
|
294
|
+
if not password:
|
|
293
295
|
LOG.warning(
|
|
294
296
|
_(
|
|
295
297
|
"No password was supplied, authentication will fail "
|
|
@@ -412,6 +414,24 @@ class ListUser(command.Lister):
|
|
|
412
414
|
default=False,
|
|
413
415
|
help=_('List additional fields in output'),
|
|
414
416
|
)
|
|
417
|
+
parser.add_argument(
|
|
418
|
+
'--enabled',
|
|
419
|
+
action='store_true',
|
|
420
|
+
dest='is_enabled',
|
|
421
|
+
default=None,
|
|
422
|
+
help=_(
|
|
423
|
+
'List only enabled users, does nothing with --project and --group'
|
|
424
|
+
),
|
|
425
|
+
)
|
|
426
|
+
parser.add_argument(
|
|
427
|
+
'--disabled',
|
|
428
|
+
action='store_false',
|
|
429
|
+
dest='is_enabled',
|
|
430
|
+
default=None,
|
|
431
|
+
help=_(
|
|
432
|
+
'List only disabled users, does nothing with --project and --group'
|
|
433
|
+
),
|
|
434
|
+
)
|
|
415
435
|
return parser
|
|
416
436
|
|
|
417
437
|
def take_action(self, parsed_args):
|
|
@@ -431,6 +451,9 @@ class ListUser(command.Lister):
|
|
|
431
451
|
ignore_missing=False,
|
|
432
452
|
).id
|
|
433
453
|
|
|
454
|
+
if parsed_args.is_enabled is not None:
|
|
455
|
+
enabled = parsed_args.is_enabled
|
|
456
|
+
|
|
434
457
|
if parsed_args.project:
|
|
435
458
|
if domain is not None:
|
|
436
459
|
project = identity_client.find_project(
|
|
@@ -469,9 +492,15 @@ class ListUser(command.Lister):
|
|
|
469
492
|
group=group,
|
|
470
493
|
)
|
|
471
494
|
else:
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
495
|
+
if parsed_args.is_enabled is not None:
|
|
496
|
+
data = identity_client.users(
|
|
497
|
+
domain_id=domain,
|
|
498
|
+
is_enabled=enabled,
|
|
499
|
+
)
|
|
500
|
+
else:
|
|
501
|
+
data = identity_client.users(
|
|
502
|
+
domain_id=domain,
|
|
503
|
+
)
|
|
475
504
|
|
|
476
505
|
# Column handling
|
|
477
506
|
if parsed_args.long:
|
|
@@ -659,6 +688,8 @@ class SetPasswordUser(command.Command):
|
|
|
659
688
|
|
|
660
689
|
def take_action(self, parsed_args):
|
|
661
690
|
identity_client = self.app.client_manager.sdk_connection.identity
|
|
691
|
+
conn = self.app.client_manager.sdk_connection
|
|
692
|
+
user_id = conn.config.get_auth().get_user_id(conn.identity)
|
|
662
693
|
|
|
663
694
|
# FIXME(gyee): there are two scenarios:
|
|
664
695
|
#
|
|
@@ -701,7 +732,9 @@ class SetPasswordUser(command.Command):
|
|
|
701
732
|
)
|
|
702
733
|
|
|
703
734
|
identity_client.update_user(
|
|
704
|
-
|
|
735
|
+
user=user_id,
|
|
736
|
+
current_password=current_password,
|
|
737
|
+
password=password,
|
|
705
738
|
)
|
|
706
739
|
|
|
707
740
|
|
openstackclient/image/client.py
CHANGED
|
@@ -528,6 +528,16 @@ class SaveImage(command.Command):
|
|
|
528
528
|
|
|
529
529
|
def get_parser(self, prog_name):
|
|
530
530
|
parser = super().get_parser(prog_name)
|
|
531
|
+
parser.add_argument(
|
|
532
|
+
"--chunk-size",
|
|
533
|
+
type=int,
|
|
534
|
+
default=1024,
|
|
535
|
+
metavar="<chunk-size>",
|
|
536
|
+
help=_(
|
|
537
|
+
"Size in bytes to read from the wire and buffer at one "
|
|
538
|
+
"time (default: 1024)"
|
|
539
|
+
),
|
|
540
|
+
)
|
|
531
541
|
parser.add_argument(
|
|
532
542
|
"--file",
|
|
533
543
|
metavar="<filename>",
|
|
@@ -550,7 +560,12 @@ class SaveImage(command.Command):
|
|
|
550
560
|
if output_file is None:
|
|
551
561
|
output_file = getattr(sys.stdout, "buffer", sys.stdout)
|
|
552
562
|
|
|
553
|
-
image_client.download_image(
|
|
563
|
+
image_client.download_image(
|
|
564
|
+
image.id,
|
|
565
|
+
stream=True,
|
|
566
|
+
output=output_file,
|
|
567
|
+
chunk_size=parsed_args.chunk_size,
|
|
568
|
+
)
|
|
554
569
|
|
|
555
570
|
|
|
556
571
|
class SetImage(command.Command):
|
|
@@ -37,14 +37,18 @@ def _format_image_cache(cached_images):
|
|
|
37
37
|
image_obj = copy.deepcopy(image)
|
|
38
38
|
image_obj['state'] = 'cached'
|
|
39
39
|
image_obj['last_accessed'] = (
|
|
40
|
-
datetime.datetime.
|
|
41
|
-
image['last_accessed']
|
|
42
|
-
)
|
|
40
|
+
datetime.datetime.fromtimestamp(
|
|
41
|
+
image['last_accessed'], tz=datetime.timezone.utc
|
|
42
|
+
)
|
|
43
|
+
.replace(tzinfo=None)
|
|
44
|
+
.isoformat()
|
|
43
45
|
)
|
|
44
46
|
image_obj['last_modified'] = (
|
|
45
|
-
datetime.datetime.
|
|
46
|
-
image['last_modified']
|
|
47
|
-
)
|
|
47
|
+
datetime.datetime.fromtimestamp(
|
|
48
|
+
image['last_modified'], tz=datetime.timezone.utc
|
|
49
|
+
)
|
|
50
|
+
.replace(tzinfo=None)
|
|
51
|
+
.isoformat()
|
|
48
52
|
)
|
|
49
53
|
image_list.append(image_obj)
|
|
50
54
|
elif item == "queued_images":
|