python-openstackclient 8.0.0__py3-none-any.whl → 8.1.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/compute/client.py +5 -0
- openstackclient/compute/v2/console.py +7 -0
- openstackclient/compute/v2/console_connection.py +48 -0
- openstackclient/compute/v2/keypair.py +10 -3
- openstackclient/compute/v2/server.py +75 -10
- openstackclient/compute/v2/server_event.py +1 -1
- openstackclient/identity/common.py +79 -0
- openstackclient/identity/v3/application_credential.py +2 -2
- openstackclient/identity/v3/domain.py +62 -43
- openstackclient/identity/v3/group.py +113 -68
- openstackclient/identity/v3/project.py +17 -0
- openstackclient/identity/v3/user.py +38 -5
- openstackclient/image/client.py +5 -0
- openstackclient/image/v2/image.py +11 -11
- 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/router.py +1 -1
- openstackclient/network/v2/security_group.py +5 -4
- openstackclient/network/v2/security_group_rule.py +1 -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/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 +1 -1
- openstackclient/tests/unit/compute/v2/test_keypair.py +12 -5
- openstackclient/tests/unit/compute/v2/test_server.py +169 -46
- 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 +47 -25
- openstackclient/tests/unit/identity/v3/test_domain.py +115 -105
- openstackclient/tests/unit/identity/v3/test_group.py +353 -202
- openstackclient/tests/unit/identity/v3/test_project.py +16 -0
- openstackclient/tests/unit/identity/v3/test_user.py +86 -6
- openstackclient/tests/unit/image/v1/test_image.py +8 -9
- openstackclient/tests/unit/image/v2/test_image.py +49 -49
- openstackclient/tests/unit/network/v2/fakes.py +405 -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 +1 -3
- 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 +17 -17
- openstackclient/tests/unit/network/v2/test_router.py +73 -57
- openstackclient/tests/unit/network/v2/test_security_group_network.py +25 -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 +33 -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 +108 -105
- 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 +130 -119
- 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 +63 -37
- 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 +200 -39
- openstackclient/volume/v3/volume_backup.py +24 -19
- openstackclient/volume/v3/volume_snapshot.py +485 -10
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/AUTHORS +8 -0
- python_openstackclient-8.1.0.dist-info/METADATA +264 -0
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/RECORD +83 -81
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/entry_points.txt +7 -6
- python_openstackclient-8.1.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.1.0.dist-info}/LICENSE +0 -0
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/WHEEL +0 -0
- {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/top_level.txt +0 -0
|
@@ -31,7 +31,6 @@ from osc_lib import utils
|
|
|
31
31
|
from openstackclient.common import pagination
|
|
32
32
|
from openstackclient.i18n import _
|
|
33
33
|
from openstackclient.identity import common as identity_common
|
|
34
|
-
from openstackclient.volume.v2 import volume as volume_v2
|
|
35
34
|
|
|
36
35
|
|
|
37
36
|
LOG = logging.getLogger(__name__)
|
|
@@ -91,7 +90,7 @@ class AttachmentsColumn(cliff_columns.FormattableColumn):
|
|
|
91
90
|
return msg
|
|
92
91
|
|
|
93
92
|
|
|
94
|
-
class CreateVolume(
|
|
93
|
+
class CreateVolume(command.ShowOne):
|
|
95
94
|
_description = _("Create new volume")
|
|
96
95
|
|
|
97
96
|
@staticmethod
|
|
@@ -117,8 +116,48 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
117
116
|
raise exceptions.CommandError(msg)
|
|
118
117
|
|
|
119
118
|
def get_parser(self, prog_name):
|
|
120
|
-
parser
|
|
121
|
-
|
|
119
|
+
parser = super().get_parser(prog_name)
|
|
120
|
+
parser.add_argument(
|
|
121
|
+
"name",
|
|
122
|
+
metavar="<name>",
|
|
123
|
+
nargs="?",
|
|
124
|
+
help=_("Volume name"),
|
|
125
|
+
)
|
|
126
|
+
parser.add_argument(
|
|
127
|
+
"--size",
|
|
128
|
+
metavar="<size>",
|
|
129
|
+
type=int,
|
|
130
|
+
help=_(
|
|
131
|
+
"Volume size in GB (required unless --snapshot or "
|
|
132
|
+
"--source specified)"
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
parser.add_argument(
|
|
136
|
+
"--type",
|
|
137
|
+
metavar="<volume-type>",
|
|
138
|
+
help=_("Set the type of volume"),
|
|
139
|
+
)
|
|
140
|
+
source_group = parser.add_mutually_exclusive_group()
|
|
141
|
+
source_group.add_argument(
|
|
142
|
+
"--image",
|
|
143
|
+
metavar="<image>",
|
|
144
|
+
help=_("Use <image> as source of volume (name or ID)"),
|
|
145
|
+
)
|
|
146
|
+
source_group.add_argument(
|
|
147
|
+
"--snapshot",
|
|
148
|
+
metavar="<snapshot>",
|
|
149
|
+
help=_("Use <snapshot> as source of volume (name or ID)"),
|
|
150
|
+
)
|
|
151
|
+
source_group.add_argument(
|
|
152
|
+
"--source",
|
|
153
|
+
metavar="<volume>",
|
|
154
|
+
help=_("Volume to clone (name or ID)"),
|
|
155
|
+
)
|
|
156
|
+
source_group.add_argument(
|
|
157
|
+
"--source-replicated",
|
|
158
|
+
metavar="<replicated-volume>",
|
|
159
|
+
help=argparse.SUPPRESS,
|
|
160
|
+
)
|
|
122
161
|
source_group.add_argument(
|
|
123
162
|
"--backup",
|
|
124
163
|
metavar="<backup>",
|
|
@@ -138,6 +177,72 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
138
177
|
"--remote-source source-id=test_id')"
|
|
139
178
|
),
|
|
140
179
|
)
|
|
180
|
+
parser.add_argument(
|
|
181
|
+
"--description",
|
|
182
|
+
metavar="<description>",
|
|
183
|
+
help=_("Volume description"),
|
|
184
|
+
)
|
|
185
|
+
parser.add_argument(
|
|
186
|
+
"--availability-zone",
|
|
187
|
+
metavar="<availability-zone>",
|
|
188
|
+
help=_("Create volume in <availability-zone>"),
|
|
189
|
+
)
|
|
190
|
+
parser.add_argument(
|
|
191
|
+
"--consistency-group",
|
|
192
|
+
metavar="consistency-group>",
|
|
193
|
+
help=_("Consistency group where the new volume belongs to"),
|
|
194
|
+
)
|
|
195
|
+
parser.add_argument(
|
|
196
|
+
"--property",
|
|
197
|
+
metavar="<key=value>",
|
|
198
|
+
action=parseractions.KeyValueAction,
|
|
199
|
+
dest="properties",
|
|
200
|
+
help=_(
|
|
201
|
+
"Set a property to this volume "
|
|
202
|
+
"(repeat option to set multiple properties)"
|
|
203
|
+
),
|
|
204
|
+
)
|
|
205
|
+
parser.add_argument(
|
|
206
|
+
"--hint",
|
|
207
|
+
metavar="<key=value>",
|
|
208
|
+
action=KeyValueHintAction,
|
|
209
|
+
help=_(
|
|
210
|
+
"Arbitrary scheduler hint key-value pairs to help creating "
|
|
211
|
+
"a volume. Repeat the option to set multiple hints. "
|
|
212
|
+
"'same_host' and 'different_host' get values appended when "
|
|
213
|
+
"repeated, all other keys take the last given value"
|
|
214
|
+
),
|
|
215
|
+
)
|
|
216
|
+
bootable_group = parser.add_mutually_exclusive_group()
|
|
217
|
+
bootable_group.add_argument(
|
|
218
|
+
"--bootable",
|
|
219
|
+
action="store_true",
|
|
220
|
+
dest="bootable",
|
|
221
|
+
default=None,
|
|
222
|
+
help=_("Mark volume as bootable"),
|
|
223
|
+
)
|
|
224
|
+
bootable_group.add_argument(
|
|
225
|
+
"--non-bootable",
|
|
226
|
+
action="store_false",
|
|
227
|
+
dest="bootable",
|
|
228
|
+
default=None,
|
|
229
|
+
help=_("Mark volume as non-bootable (default)"),
|
|
230
|
+
)
|
|
231
|
+
readonly_group = parser.add_mutually_exclusive_group()
|
|
232
|
+
readonly_group.add_argument(
|
|
233
|
+
"--read-only",
|
|
234
|
+
action="store_true",
|
|
235
|
+
dest="read_only",
|
|
236
|
+
default=None,
|
|
237
|
+
help=_("Set volume to read-only access mode"),
|
|
238
|
+
)
|
|
239
|
+
readonly_group.add_argument(
|
|
240
|
+
"--read-write",
|
|
241
|
+
action="store_false",
|
|
242
|
+
dest="read_only",
|
|
243
|
+
default=None,
|
|
244
|
+
help=_("Set volume to read-write access mode (default)"),
|
|
245
|
+
)
|
|
141
246
|
parser.add_argument(
|
|
142
247
|
"--host",
|
|
143
248
|
metavar="<host>",
|
|
@@ -160,7 +265,7 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
160
265
|
return parser
|
|
161
266
|
|
|
162
267
|
def take_action(self, parsed_args):
|
|
163
|
-
|
|
268
|
+
self._check_size_arg(parsed_args)
|
|
164
269
|
# size is validated in the above call to
|
|
165
270
|
# _check_size_arg where we check that size
|
|
166
271
|
# should be passed if we are not creating a
|
|
@@ -194,8 +299,7 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
194
299
|
parsed_args.size
|
|
195
300
|
or parsed_args.consistency_group
|
|
196
301
|
or parsed_args.hint
|
|
197
|
-
or parsed_args.read_only
|
|
198
|
-
or parsed_args.read_write
|
|
302
|
+
or parsed_args.read_only is not None
|
|
199
303
|
):
|
|
200
304
|
msg = _(
|
|
201
305
|
"The --size, --consistency-group, --hint, --read-only "
|
|
@@ -232,10 +336,24 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
232
336
|
description=parsed_args.description,
|
|
233
337
|
volume_type=parsed_args.type,
|
|
234
338
|
availability_zone=parsed_args.availability_zone,
|
|
235
|
-
metadata=parsed_args.
|
|
339
|
+
metadata=parsed_args.properties,
|
|
236
340
|
bootable=parsed_args.bootable,
|
|
237
341
|
)
|
|
238
|
-
|
|
342
|
+
data = {}
|
|
343
|
+
for key, value in volume.to_dict().items():
|
|
344
|
+
# FIXME(stephenfin): Stop ignoring these once we bump SDK
|
|
345
|
+
# https://review.opendev.org/c/openstack/openstacksdk/+/945836/
|
|
346
|
+
if key in (
|
|
347
|
+
'cluster_name',
|
|
348
|
+
'consumes_quota',
|
|
349
|
+
'encryption_key_id',
|
|
350
|
+
'service_uuid',
|
|
351
|
+
'shared_targets',
|
|
352
|
+
'volume_type_id',
|
|
353
|
+
):
|
|
354
|
+
continue
|
|
355
|
+
data[key] = value
|
|
356
|
+
return zip(*sorted(data.items()))
|
|
239
357
|
|
|
240
358
|
source_volume = None
|
|
241
359
|
if parsed_args.source:
|
|
@@ -287,7 +405,7 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
287
405
|
description=parsed_args.description,
|
|
288
406
|
volume_type=parsed_args.type,
|
|
289
407
|
availability_zone=parsed_args.availability_zone,
|
|
290
|
-
metadata=parsed_args.
|
|
408
|
+
metadata=parsed_args.properties,
|
|
291
409
|
imageRef=image,
|
|
292
410
|
source_volid=source_volume,
|
|
293
411
|
consistencygroup_id=consistency_group,
|
|
@@ -295,7 +413,7 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
295
413
|
backup_id=backup,
|
|
296
414
|
)
|
|
297
415
|
|
|
298
|
-
if parsed_args.bootable
|
|
416
|
+
if parsed_args.bootable is not None:
|
|
299
417
|
try:
|
|
300
418
|
if utils.wait_for_status(
|
|
301
419
|
volume_client.volumes.get,
|
|
@@ -314,7 +432,8 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
314
432
|
raise exceptions.CommandError(msg)
|
|
315
433
|
except Exception as e:
|
|
316
434
|
LOG.error(_("Failed to set volume bootable property: %s"), e)
|
|
317
|
-
|
|
435
|
+
|
|
436
|
+
if parsed_args.read_only is not None:
|
|
318
437
|
try:
|
|
319
438
|
if utils.wait_for_status(
|
|
320
439
|
volume_client.volumes.get,
|
|
@@ -351,11 +470,33 @@ class CreateVolume(volume_v2.CreateVolume):
|
|
|
351
470
|
return zip(*sorted(volume._info.items()))
|
|
352
471
|
|
|
353
472
|
|
|
354
|
-
class DeleteVolume(
|
|
473
|
+
class DeleteVolume(command.Command):
|
|
355
474
|
_description = _("Delete volume(s)")
|
|
356
475
|
|
|
357
476
|
def get_parser(self, prog_name):
|
|
358
477
|
parser = super().get_parser(prog_name)
|
|
478
|
+
parser.add_argument(
|
|
479
|
+
"volumes",
|
|
480
|
+
metavar="<volume>",
|
|
481
|
+
nargs="+",
|
|
482
|
+
help=_("Volume(s) to delete (name or ID)"),
|
|
483
|
+
)
|
|
484
|
+
group = parser.add_mutually_exclusive_group()
|
|
485
|
+
group.add_argument(
|
|
486
|
+
"--force",
|
|
487
|
+
action="store_true",
|
|
488
|
+
help=_(
|
|
489
|
+
"Attempt forced removal of volume(s), regardless of state "
|
|
490
|
+
"(defaults to False)"
|
|
491
|
+
),
|
|
492
|
+
)
|
|
493
|
+
group.add_argument(
|
|
494
|
+
"--purge",
|
|
495
|
+
action="store_true",
|
|
496
|
+
help=_(
|
|
497
|
+
"Remove any snapshots along with volume(s) (defaults to False)"
|
|
498
|
+
),
|
|
499
|
+
)
|
|
359
500
|
parser.add_argument(
|
|
360
501
|
'--remote',
|
|
361
502
|
action='store_true',
|
|
@@ -364,8 +505,7 @@ class DeleteVolume(volume_v2.DeleteVolume):
|
|
|
364
505
|
return parser
|
|
365
506
|
|
|
366
507
|
def take_action(self, parsed_args):
|
|
367
|
-
volume_client = self.app.client_manager.volume
|
|
368
|
-
volume_client_sdk = self.app.client_manager.sdk_connection.volume
|
|
508
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
369
509
|
result = 0
|
|
370
510
|
|
|
371
511
|
if parsed_args.remote and (parsed_args.force or parsed_args.purge):
|
|
@@ -375,16 +515,18 @@ class DeleteVolume(volume_v2.DeleteVolume):
|
|
|
375
515
|
)
|
|
376
516
|
raise exceptions.CommandError(msg)
|
|
377
517
|
|
|
378
|
-
for
|
|
518
|
+
for volume in parsed_args.volumes:
|
|
379
519
|
try:
|
|
380
|
-
volume_obj =
|
|
520
|
+
volume_obj = volume_client.find_volume(
|
|
521
|
+
volume, ignore_missing=False
|
|
522
|
+
)
|
|
381
523
|
if parsed_args.remote:
|
|
382
|
-
|
|
383
|
-
elif parsed_args.force:
|
|
384
|
-
volume_client.volumes.force_delete(volume_obj.id)
|
|
524
|
+
volume_client.unmanage_volume(volume_obj.id)
|
|
385
525
|
else:
|
|
386
|
-
volume_client.
|
|
387
|
-
volume_obj.id,
|
|
526
|
+
volume_client.delete_volume(
|
|
527
|
+
volume_obj.id,
|
|
528
|
+
force=parsed_args.force,
|
|
529
|
+
cascade=parsed_args.purge,
|
|
388
530
|
)
|
|
389
531
|
except Exception as e:
|
|
390
532
|
result += 1
|
|
@@ -393,7 +535,7 @@ class DeleteVolume(volume_v2.DeleteVolume):
|
|
|
393
535
|
"Failed to delete volume with "
|
|
394
536
|
"name or ID '%(volume)s': %(e)s"
|
|
395
537
|
),
|
|
396
|
-
{'volume':
|
|
538
|
+
{'volume': volume, 'e': e},
|
|
397
539
|
)
|
|
398
540
|
|
|
399
541
|
if result > 0:
|
|
@@ -638,6 +780,7 @@ class SetVolume(command.Command):
|
|
|
638
780
|
'--property',
|
|
639
781
|
metavar='<key=value>',
|
|
640
782
|
action=parseractions.KeyValueAction,
|
|
783
|
+
dest='properties',
|
|
641
784
|
help=_(
|
|
642
785
|
'Set a property on this volume '
|
|
643
786
|
'(repeat option to set multiple properties)'
|
|
@@ -647,6 +790,7 @@ class SetVolume(command.Command):
|
|
|
647
790
|
'--image-property',
|
|
648
791
|
metavar='<key=value>',
|
|
649
792
|
action=parseractions.KeyValueAction,
|
|
793
|
+
dest='image_properties',
|
|
650
794
|
help=_(
|
|
651
795
|
'Set an image property on this volume '
|
|
652
796
|
'(repeat option to set multiple image properties)'
|
|
@@ -723,22 +867,30 @@ class SetVolume(command.Command):
|
|
|
723
867
|
bootable_group.add_argument(
|
|
724
868
|
"--bootable",
|
|
725
869
|
action="store_true",
|
|
870
|
+
dest="bootable",
|
|
871
|
+
default=None,
|
|
726
872
|
help=_("Mark volume as bootable"),
|
|
727
873
|
)
|
|
728
874
|
bootable_group.add_argument(
|
|
729
875
|
"--non-bootable",
|
|
730
|
-
action="
|
|
876
|
+
action="store_false",
|
|
877
|
+
dest="bootable",
|
|
878
|
+
default=None,
|
|
731
879
|
help=_("Mark volume as non-bootable"),
|
|
732
880
|
)
|
|
733
881
|
readonly_group = parser.add_mutually_exclusive_group()
|
|
734
882
|
readonly_group.add_argument(
|
|
735
883
|
"--read-only",
|
|
736
884
|
action="store_true",
|
|
885
|
+
dest="read_only",
|
|
886
|
+
default=None,
|
|
737
887
|
help=_("Set volume to read-only access mode"),
|
|
738
888
|
)
|
|
739
889
|
readonly_group.add_argument(
|
|
740
890
|
"--read-write",
|
|
741
|
-
action="
|
|
891
|
+
action="store_false",
|
|
892
|
+
dest="read_only",
|
|
893
|
+
default=None,
|
|
742
894
|
help=_("Set volume to read-write access mode"),
|
|
743
895
|
)
|
|
744
896
|
return parser
|
|
@@ -796,28 +948,31 @@ class SetVolume(command.Command):
|
|
|
796
948
|
LOG.error(_("Failed to clean volume properties: %s"), e)
|
|
797
949
|
result += 1
|
|
798
950
|
|
|
799
|
-
if parsed_args.
|
|
951
|
+
if parsed_args.properties:
|
|
800
952
|
try:
|
|
801
953
|
volume_client.volumes.set_metadata(
|
|
802
|
-
volume.id, parsed_args.
|
|
954
|
+
volume.id, parsed_args.properties
|
|
803
955
|
)
|
|
804
956
|
except Exception as e:
|
|
805
|
-
LOG.error(_("Failed to set volume
|
|
957
|
+
LOG.error(_("Failed to set volume properties: %s"), e)
|
|
806
958
|
result += 1
|
|
807
|
-
|
|
959
|
+
|
|
960
|
+
if parsed_args.image_properties:
|
|
808
961
|
try:
|
|
809
962
|
volume_client.volumes.set_image_metadata(
|
|
810
|
-
volume.id, parsed_args.
|
|
963
|
+
volume.id, parsed_args.image_properties
|
|
811
964
|
)
|
|
812
965
|
except Exception as e:
|
|
813
|
-
LOG.error(_("Failed to set image
|
|
966
|
+
LOG.error(_("Failed to set image properties: %s"), e)
|
|
814
967
|
result += 1
|
|
968
|
+
|
|
815
969
|
if parsed_args.state:
|
|
816
970
|
try:
|
|
817
971
|
volume_client.volumes.reset_state(volume.id, parsed_args.state)
|
|
818
972
|
except Exception as e:
|
|
819
973
|
LOG.error(_("Failed to set volume state: %s"), e)
|
|
820
974
|
result += 1
|
|
975
|
+
|
|
821
976
|
if parsed_args.attached:
|
|
822
977
|
try:
|
|
823
978
|
volume_client.volumes.reset_state(
|
|
@@ -826,6 +981,7 @@ class SetVolume(command.Command):
|
|
|
826
981
|
except Exception as e:
|
|
827
982
|
LOG.error(_("Failed to set volume attach-status: %s"), e)
|
|
828
983
|
result += 1
|
|
984
|
+
|
|
829
985
|
if parsed_args.detached:
|
|
830
986
|
try:
|
|
831
987
|
volume_client.volumes.reset_state(
|
|
@@ -834,7 +990,8 @@ class SetVolume(command.Command):
|
|
|
834
990
|
except Exception as e:
|
|
835
991
|
LOG.error(_("Failed to set volume attach-status: %s"), e)
|
|
836
992
|
result += 1
|
|
837
|
-
|
|
993
|
+
|
|
994
|
+
if parsed_args.bootable is not None:
|
|
838
995
|
try:
|
|
839
996
|
volume_client.volumes.set_bootable(
|
|
840
997
|
volume.id, parsed_args.bootable
|
|
@@ -842,7 +999,8 @@ class SetVolume(command.Command):
|
|
|
842
999
|
except Exception as e:
|
|
843
1000
|
LOG.error(_("Failed to set volume bootable property: %s"), e)
|
|
844
1001
|
result += 1
|
|
845
|
-
|
|
1002
|
+
|
|
1003
|
+
if parsed_args.read_only is not None:
|
|
846
1004
|
try:
|
|
847
1005
|
volume_client.volumes.update_readonly_flag(
|
|
848
1006
|
volume.id, parsed_args.read_only
|
|
@@ -853,6 +1011,7 @@ class SetVolume(command.Command):
|
|
|
853
1011
|
e,
|
|
854
1012
|
)
|
|
855
1013
|
result += 1
|
|
1014
|
+
|
|
856
1015
|
policy = parsed_args.migration_policy or parsed_args.retype_policy
|
|
857
1016
|
if parsed_args.type:
|
|
858
1017
|
# get the migration policy
|
|
@@ -953,6 +1112,7 @@ class UnsetVolume(command.Command):
|
|
|
953
1112
|
'--property',
|
|
954
1113
|
metavar='<key>',
|
|
955
1114
|
action='append',
|
|
1115
|
+
dest='properties',
|
|
956
1116
|
help=_(
|
|
957
1117
|
'Remove a property from volume '
|
|
958
1118
|
'(repeat option to remove multiple properties)'
|
|
@@ -962,6 +1122,7 @@ class UnsetVolume(command.Command):
|
|
|
962
1122
|
'--image-property',
|
|
963
1123
|
metavar='<key>',
|
|
964
1124
|
action='append',
|
|
1125
|
+
dest='image_properties',
|
|
965
1126
|
help=_(
|
|
966
1127
|
'Remove an image property from volume '
|
|
967
1128
|
'(repeat option to remove multiple image properties)'
|
|
@@ -974,22 +1135,22 @@ class UnsetVolume(command.Command):
|
|
|
974
1135
|
volume = utils.find_resource(volume_client.volumes, parsed_args.volume)
|
|
975
1136
|
|
|
976
1137
|
result = 0
|
|
977
|
-
if parsed_args.
|
|
1138
|
+
if parsed_args.properties:
|
|
978
1139
|
try:
|
|
979
1140
|
volume_client.volumes.delete_metadata(
|
|
980
|
-
volume.id, parsed_args.
|
|
1141
|
+
volume.id, parsed_args.properties
|
|
981
1142
|
)
|
|
982
1143
|
except Exception as e:
|
|
983
|
-
LOG.error(_("Failed to unset volume
|
|
1144
|
+
LOG.error(_("Failed to unset volume properties: %s"), e)
|
|
984
1145
|
result += 1
|
|
985
1146
|
|
|
986
|
-
if parsed_args.
|
|
1147
|
+
if parsed_args.image_properties:
|
|
987
1148
|
try:
|
|
988
1149
|
volume_client.volumes.delete_image_metadata(
|
|
989
|
-
volume.id, parsed_args.
|
|
1150
|
+
volume.id, parsed_args.image_properties
|
|
990
1151
|
)
|
|
991
1152
|
except Exception as e:
|
|
992
|
-
LOG.error(_("Failed to unset image
|
|
1153
|
+
LOG.error(_("Failed to unset image properties: %s"), e)
|
|
993
1154
|
result += 1
|
|
994
1155
|
|
|
995
1156
|
if result > 0:
|
|
@@ -18,7 +18,6 @@ import copy
|
|
|
18
18
|
import functools
|
|
19
19
|
import logging
|
|
20
20
|
|
|
21
|
-
from cinderclient import api_versions
|
|
22
21
|
from cliff import columns as cliff_columns
|
|
23
22
|
from openstack import utils as sdk_utils
|
|
24
23
|
from osc_lib.cli import parseractions
|
|
@@ -512,13 +511,19 @@ class SetVolumeBackup(command.Command):
|
|
|
512
511
|
return parser
|
|
513
512
|
|
|
514
513
|
def take_action(self, parsed_args):
|
|
515
|
-
volume_client = self.app.client_manager.volume
|
|
516
|
-
|
|
514
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
515
|
+
|
|
516
|
+
backup = volume_client.find_backup(
|
|
517
|
+
parsed_args.backup,
|
|
518
|
+
ignore_missing=False,
|
|
519
|
+
)
|
|
517
520
|
|
|
518
521
|
result = 0
|
|
519
522
|
if parsed_args.state:
|
|
520
523
|
try:
|
|
521
|
-
volume_client.
|
|
524
|
+
volume_client.reset_backup_status(
|
|
525
|
+
backup, status=parsed_args.state
|
|
526
|
+
)
|
|
522
527
|
except Exception as e:
|
|
523
528
|
LOG.error(_("Failed to set backup state: %s"), e)
|
|
524
529
|
result += 1
|
|
@@ -526,7 +531,7 @@ class SetVolumeBackup(command.Command):
|
|
|
526
531
|
kwargs = {}
|
|
527
532
|
|
|
528
533
|
if parsed_args.name:
|
|
529
|
-
if
|
|
534
|
+
if not sdk_utils.supports_microversion(volume_client, '3.9'):
|
|
530
535
|
msg = _(
|
|
531
536
|
'--os-volume-api-version 3.9 or greater is required to '
|
|
532
537
|
'support the --name option'
|
|
@@ -536,7 +541,7 @@ class SetVolumeBackup(command.Command):
|
|
|
536
541
|
kwargs['name'] = parsed_args.name
|
|
537
542
|
|
|
538
543
|
if parsed_args.description:
|
|
539
|
-
if
|
|
544
|
+
if not sdk_utils.supports_microversion(volume_client, '3.9'):
|
|
540
545
|
msg = _(
|
|
541
546
|
'--os-volume-api-version 3.9 or greater is required to '
|
|
542
547
|
'support the --description option'
|
|
@@ -546,7 +551,7 @@ class SetVolumeBackup(command.Command):
|
|
|
546
551
|
kwargs['description'] = parsed_args.description
|
|
547
552
|
|
|
548
553
|
if parsed_args.no_property:
|
|
549
|
-
if
|
|
554
|
+
if not sdk_utils.supports_microversion(volume_client, '3.43'):
|
|
550
555
|
msg = _(
|
|
551
556
|
'--os-volume-api-version 3.43 or greater is required to '
|
|
552
557
|
'support the --no-property option'
|
|
@@ -554,14 +559,14 @@ class SetVolumeBackup(command.Command):
|
|
|
554
559
|
raise exceptions.CommandError(msg)
|
|
555
560
|
|
|
556
561
|
if parsed_args.properties:
|
|
557
|
-
if
|
|
562
|
+
if not sdk_utils.supports_microversion(volume_client, '3.43'):
|
|
558
563
|
msg = _(
|
|
559
564
|
'--os-volume-api-version 3.43 or greater is required to '
|
|
560
565
|
'support the --property option'
|
|
561
566
|
)
|
|
562
567
|
raise exceptions.CommandError(msg)
|
|
563
568
|
|
|
564
|
-
if volume_client
|
|
569
|
+
if sdk_utils.supports_microversion(volume_client, '3.43'):
|
|
565
570
|
metadata = copy.deepcopy(backup.metadata)
|
|
566
571
|
|
|
567
572
|
if parsed_args.no_property:
|
|
@@ -572,7 +577,7 @@ class SetVolumeBackup(command.Command):
|
|
|
572
577
|
|
|
573
578
|
if kwargs:
|
|
574
579
|
try:
|
|
575
|
-
volume_client.
|
|
580
|
+
volume_client.update_backup(backup, **kwargs)
|
|
576
581
|
except Exception as e:
|
|
577
582
|
LOG.error("Failed to update backup: %s", e)
|
|
578
583
|
result += 1
|
|
@@ -608,16 +613,18 @@ class UnsetVolumeBackup(command.Command):
|
|
|
608
613
|
return parser
|
|
609
614
|
|
|
610
615
|
def take_action(self, parsed_args):
|
|
611
|
-
volume_client = self.app.client_manager.volume
|
|
616
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
612
617
|
|
|
613
|
-
if
|
|
618
|
+
if not sdk_utils.supports_microversion(volume_client, '3.43'):
|
|
614
619
|
msg = _(
|
|
615
620
|
'--os-volume-api-version 3.43 or greater is required to '
|
|
616
621
|
'support the --property option'
|
|
617
622
|
)
|
|
618
623
|
raise exceptions.CommandError(msg)
|
|
619
624
|
|
|
620
|
-
backup =
|
|
625
|
+
backup = volume_client.find_backup(
|
|
626
|
+
parsed_args.backup, ignore_missing=False
|
|
627
|
+
)
|
|
621
628
|
metadata = copy.deepcopy(backup.metadata)
|
|
622
629
|
|
|
623
630
|
for key in parsed_args.properties:
|
|
@@ -632,11 +639,7 @@ class UnsetVolumeBackup(command.Command):
|
|
|
632
639
|
|
|
633
640
|
del metadata[key]
|
|
634
641
|
|
|
635
|
-
|
|
636
|
-
'metadata': metadata,
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
volume_client.backups.update(backup.id, **kwargs)
|
|
642
|
+
volume_client.delete_backup_metadata(backup, keys=list(metadata))
|
|
640
643
|
|
|
641
644
|
|
|
642
645
|
class ShowVolumeBackup(command.ShowOne):
|
|
@@ -653,7 +656,9 @@ class ShowVolumeBackup(command.ShowOne):
|
|
|
653
656
|
|
|
654
657
|
def take_action(self, parsed_args):
|
|
655
658
|
volume_client = self.app.client_manager.sdk_connection.volume
|
|
656
|
-
backup = volume_client.find_backup(
|
|
659
|
+
backup = volume_client.find_backup(
|
|
660
|
+
parsed_args.backup, ignore_missing=False
|
|
661
|
+
)
|
|
657
662
|
columns: tuple[str, ...] = (
|
|
658
663
|
"availability_zone",
|
|
659
664
|
"container",
|