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
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
"""Volume v2 snapshot action implementations"""
|
|
16
16
|
|
|
17
|
-
import copy
|
|
18
17
|
import functools
|
|
19
18
|
import logging
|
|
19
|
+
import typing as ty
|
|
20
20
|
|
|
21
21
|
from cliff import columns as cliff_columns
|
|
22
|
+
from openstack.block_storage.v2 import snapshot as _snapshot
|
|
22
23
|
from osc_lib.cli import format_columns
|
|
23
24
|
from osc_lib.cli import parseractions
|
|
24
25
|
from osc_lib.command import command
|
|
@@ -60,6 +61,42 @@ class VolumeIdColumn(cliff_columns.FormattableColumn):
|
|
|
60
61
|
return volume
|
|
61
62
|
|
|
62
63
|
|
|
64
|
+
def _format_snapshot(snapshot: _snapshot.Snapshot) -> dict[str, ty.Any]:
|
|
65
|
+
# Some columns returned by openstacksdk should not be shown because they're
|
|
66
|
+
# either irrelevant or duplicates
|
|
67
|
+
ignored_columns = {
|
|
68
|
+
# computed columns
|
|
69
|
+
'location',
|
|
70
|
+
# create-only columns
|
|
71
|
+
'consumes_quota',
|
|
72
|
+
'force',
|
|
73
|
+
'group_snapshot_id',
|
|
74
|
+
# ignored columns
|
|
75
|
+
'os-extended-snapshot-attributes:progress',
|
|
76
|
+
'os-extended-snapshot-attributes:project_id',
|
|
77
|
+
'updated_at',
|
|
78
|
+
'user_id',
|
|
79
|
+
# unnecessary columns
|
|
80
|
+
'links',
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
info = snapshot.to_dict(original_names=True)
|
|
84
|
+
data = {}
|
|
85
|
+
for key, value in info.items():
|
|
86
|
+
if key in ignored_columns:
|
|
87
|
+
continue
|
|
88
|
+
|
|
89
|
+
data[key] = value
|
|
90
|
+
|
|
91
|
+
data.update(
|
|
92
|
+
{
|
|
93
|
+
'properties': format_columns.DictColumn(data.pop('metadata')),
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return data
|
|
98
|
+
|
|
99
|
+
|
|
63
100
|
class CreateVolumeSnapshot(command.ShowOne):
|
|
64
101
|
_description = _("Create new volume snapshot")
|
|
65
102
|
|
|
@@ -94,6 +131,7 @@ class CreateVolumeSnapshot(command.ShowOne):
|
|
|
94
131
|
"--property",
|
|
95
132
|
metavar="<key=value>",
|
|
96
133
|
action=parseractions.KeyValueAction,
|
|
134
|
+
dest="properties",
|
|
97
135
|
help=_(
|
|
98
136
|
"Set a property to this snapshot "
|
|
99
137
|
"(repeat option to set multiple properties)"
|
|
@@ -113,11 +151,13 @@ class CreateVolumeSnapshot(command.ShowOne):
|
|
|
113
151
|
return parser
|
|
114
152
|
|
|
115
153
|
def take_action(self, parsed_args):
|
|
116
|
-
volume_client = self.app.client_manager.volume
|
|
154
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
155
|
+
|
|
117
156
|
volume = parsed_args.volume
|
|
118
157
|
if not parsed_args.volume:
|
|
119
158
|
volume = parsed_args.snapshot_name
|
|
120
|
-
volume_id =
|
|
159
|
+
volume_id = volume_client.find_volume(volume, ignore_missing=False).id
|
|
160
|
+
|
|
121
161
|
if parsed_args.remote_source:
|
|
122
162
|
# Create a new snapshot from an existing remote snapshot source
|
|
123
163
|
if parsed_args.force:
|
|
@@ -127,30 +167,26 @@ class CreateVolumeSnapshot(command.ShowOne):
|
|
|
127
167
|
"volume snapshot"
|
|
128
168
|
)
|
|
129
169
|
LOG.warning(msg)
|
|
130
|
-
|
|
170
|
+
|
|
171
|
+
snapshot = volume_client.manage_snapshot(
|
|
131
172
|
volume_id=volume_id,
|
|
132
173
|
ref=parsed_args.remote_source,
|
|
133
174
|
name=parsed_args.snapshot_name,
|
|
134
175
|
description=parsed_args.description,
|
|
135
|
-
metadata=parsed_args.
|
|
176
|
+
metadata=parsed_args.properties,
|
|
136
177
|
)
|
|
137
178
|
else:
|
|
138
179
|
# create a new snapshot from scratch
|
|
139
|
-
snapshot = volume_client.
|
|
140
|
-
volume_id,
|
|
180
|
+
snapshot = volume_client.create_snapshot(
|
|
181
|
+
volume_id=volume_id,
|
|
141
182
|
force=parsed_args.force,
|
|
142
183
|
name=parsed_args.snapshot_name,
|
|
143
184
|
description=parsed_args.description,
|
|
144
|
-
metadata=parsed_args.
|
|
185
|
+
metadata=parsed_args.properties,
|
|
145
186
|
)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
snapshot._info.pop('metadata')
|
|
150
|
-
)
|
|
151
|
-
}
|
|
152
|
-
)
|
|
153
|
-
return zip(*sorted(snapshot._info.items()))
|
|
187
|
+
|
|
188
|
+
data = _format_snapshot(snapshot)
|
|
189
|
+
return zip(*sorted(data.items()))
|
|
154
190
|
|
|
155
191
|
|
|
156
192
|
class DeleteVolumeSnapshot(command.Command):
|
|
@@ -175,16 +211,16 @@ class DeleteVolumeSnapshot(command.Command):
|
|
|
175
211
|
return parser
|
|
176
212
|
|
|
177
213
|
def take_action(self, parsed_args):
|
|
178
|
-
volume_client = self.app.client_manager.volume
|
|
214
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
179
215
|
result = 0
|
|
180
216
|
|
|
181
|
-
for
|
|
217
|
+
for snapshot in parsed_args.snapshots:
|
|
182
218
|
try:
|
|
183
|
-
snapshot_id =
|
|
184
|
-
|
|
219
|
+
snapshot_id = volume_client.find_snapshot(
|
|
220
|
+
snapshot, ignore_missing=False
|
|
185
221
|
).id
|
|
186
|
-
volume_client.
|
|
187
|
-
snapshot_id, parsed_args.force
|
|
222
|
+
volume_client.delete_snapshot(
|
|
223
|
+
snapshot_id, force=parsed_args.force
|
|
188
224
|
)
|
|
189
225
|
except Exception as e:
|
|
190
226
|
result += 1
|
|
@@ -193,7 +229,7 @@ class DeleteVolumeSnapshot(command.Command):
|
|
|
193
229
|
"Failed to delete snapshot with "
|
|
194
230
|
"name or ID '%(snapshot)s': %(e)s"
|
|
195
231
|
)
|
|
196
|
-
% {'snapshot':
|
|
232
|
+
% {'snapshot': snapshot, 'e': e}
|
|
197
233
|
)
|
|
198
234
|
|
|
199
235
|
if result > 0:
|
|
@@ -260,31 +296,39 @@ class ListVolumeSnapshot(command.Lister):
|
|
|
260
296
|
return parser
|
|
261
297
|
|
|
262
298
|
def take_action(self, parsed_args):
|
|
263
|
-
volume_client = self.app.client_manager.volume
|
|
299
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
264
300
|
identity_client = self.app.client_manager.identity
|
|
265
301
|
|
|
302
|
+
columns: tuple[str, ...] = (
|
|
303
|
+
'id',
|
|
304
|
+
'name',
|
|
305
|
+
'description',
|
|
306
|
+
'status',
|
|
307
|
+
'size',
|
|
308
|
+
)
|
|
309
|
+
column_headers: tuple[str, ...] = (
|
|
310
|
+
'ID',
|
|
311
|
+
'Name',
|
|
312
|
+
'Description',
|
|
313
|
+
'Status',
|
|
314
|
+
'Size',
|
|
315
|
+
)
|
|
266
316
|
if parsed_args.long:
|
|
267
|
-
columns
|
|
268
|
-
'
|
|
269
|
-
'
|
|
270
|
-
'
|
|
271
|
-
|
|
272
|
-
|
|
317
|
+
columns += (
|
|
318
|
+
'created_at',
|
|
319
|
+
'volume_id',
|
|
320
|
+
'metadata',
|
|
321
|
+
)
|
|
322
|
+
column_headers += (
|
|
273
323
|
'Created At',
|
|
274
|
-
'Volume
|
|
275
|
-
'
|
|
276
|
-
|
|
277
|
-
column_headers = copy.deepcopy(columns)
|
|
278
|
-
column_headers[6] = 'Volume'
|
|
279
|
-
column_headers[7] = 'Properties'
|
|
280
|
-
else:
|
|
281
|
-
columns = ['ID', 'Name', 'Description', 'Status', 'Size']
|
|
282
|
-
column_headers = copy.deepcopy(columns)
|
|
324
|
+
'Volume',
|
|
325
|
+
'Properties',
|
|
326
|
+
)
|
|
283
327
|
|
|
284
328
|
# Cache the volume list
|
|
285
329
|
volume_cache = {}
|
|
286
330
|
try:
|
|
287
|
-
for s in volume_client.volumes
|
|
331
|
+
for s in volume_client.volumes():
|
|
288
332
|
volume_cache[s.id] = s
|
|
289
333
|
except Exception: # noqa: S110
|
|
290
334
|
# Just forget it if there's any trouble
|
|
@@ -295,8 +339,8 @@ class ListVolumeSnapshot(command.Lister):
|
|
|
295
339
|
|
|
296
340
|
volume_id = None
|
|
297
341
|
if parsed_args.volume:
|
|
298
|
-
volume_id =
|
|
299
|
-
|
|
342
|
+
volume_id = volume_client.find_volume(
|
|
343
|
+
parsed_args.volume, ignore_missing=False
|
|
300
344
|
).id
|
|
301
345
|
|
|
302
346
|
project_id = None
|
|
@@ -312,18 +356,14 @@ class ListVolumeSnapshot(command.Lister):
|
|
|
312
356
|
True if parsed_args.project else parsed_args.all_projects
|
|
313
357
|
)
|
|
314
358
|
|
|
315
|
-
|
|
316
|
-
'all_tenants': all_projects,
|
|
317
|
-
'project_id': project_id,
|
|
318
|
-
'name': parsed_args.name,
|
|
319
|
-
'status': parsed_args.status,
|
|
320
|
-
'volume_id': volume_id,
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
data = volume_client.volume_snapshots.list(
|
|
324
|
-
search_opts=search_opts,
|
|
359
|
+
data = volume_client.snapshots(
|
|
325
360
|
marker=parsed_args.marker,
|
|
326
361
|
limit=parsed_args.limit,
|
|
362
|
+
all_projects=all_projects,
|
|
363
|
+
project_id=project_id,
|
|
364
|
+
name=parsed_args.name,
|
|
365
|
+
status=parsed_args.status,
|
|
366
|
+
volume_id=volume_id,
|
|
327
367
|
)
|
|
328
368
|
return (
|
|
329
369
|
column_headers,
|
|
@@ -332,8 +372,8 @@ class ListVolumeSnapshot(command.Lister):
|
|
|
332
372
|
s,
|
|
333
373
|
columns,
|
|
334
374
|
formatters={
|
|
335
|
-
'
|
|
336
|
-
'
|
|
375
|
+
'metadata': format_columns.DictColumn,
|
|
376
|
+
'volume_id': _VolumeIdColumn,
|
|
337
377
|
},
|
|
338
378
|
)
|
|
339
379
|
for s in data
|
|
@@ -374,6 +414,7 @@ class SetVolumeSnapshot(command.Command):
|
|
|
374
414
|
'--property',
|
|
375
415
|
metavar='<key=value>',
|
|
376
416
|
action=parseractions.KeyValueAction,
|
|
417
|
+
dest='properties',
|
|
377
418
|
help=_(
|
|
378
419
|
'Property to add/change for this snapshot '
|
|
379
420
|
'(repeat option to set multiple properties)'
|
|
@@ -400,27 +441,26 @@ class SetVolumeSnapshot(command.Command):
|
|
|
400
441
|
return parser
|
|
401
442
|
|
|
402
443
|
def take_action(self, parsed_args):
|
|
403
|
-
volume_client = self.app.client_manager.volume
|
|
404
|
-
|
|
405
|
-
|
|
444
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
445
|
+
|
|
446
|
+
snapshot = volume_client.find_snapshot(
|
|
447
|
+
parsed_args.snapshot, ignore_missing=False
|
|
406
448
|
)
|
|
407
449
|
|
|
408
450
|
result = 0
|
|
409
451
|
if parsed_args.no_property:
|
|
410
452
|
try:
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
snapshot.id,
|
|
414
|
-
list(key_list),
|
|
453
|
+
volume_client.delete_snapshot_metadata(
|
|
454
|
+
snapshot.id, keys=list(snapshot.metadata)
|
|
415
455
|
)
|
|
416
456
|
except Exception as e:
|
|
417
457
|
LOG.error(_("Failed to clean snapshot properties: %s"), e)
|
|
418
458
|
result += 1
|
|
419
459
|
|
|
420
|
-
if parsed_args.
|
|
460
|
+
if parsed_args.properties:
|
|
421
461
|
try:
|
|
422
|
-
volume_client.
|
|
423
|
-
snapshot.id, parsed_args.
|
|
462
|
+
volume_client.set_snapshot_metadata(
|
|
463
|
+
snapshot.id, **parsed_args.properties
|
|
424
464
|
)
|
|
425
465
|
except Exception as e:
|
|
426
466
|
LOG.error(_("Failed to set snapshot property: %s"), e)
|
|
@@ -428,7 +468,7 @@ class SetVolumeSnapshot(command.Command):
|
|
|
428
468
|
|
|
429
469
|
if parsed_args.state:
|
|
430
470
|
try:
|
|
431
|
-
volume_client.
|
|
471
|
+
volume_client.reset_snapshot_status(
|
|
432
472
|
snapshot.id, parsed_args.state
|
|
433
473
|
)
|
|
434
474
|
except Exception as e:
|
|
@@ -442,7 +482,7 @@ class SetVolumeSnapshot(command.Command):
|
|
|
442
482
|
kwargs['description'] = parsed_args.description
|
|
443
483
|
if kwargs:
|
|
444
484
|
try:
|
|
445
|
-
volume_client.
|
|
485
|
+
volume_client.update_snapshot(snapshot.id, **kwargs)
|
|
446
486
|
except Exception as e:
|
|
447
487
|
LOG.error(
|
|
448
488
|
_("Failed to update snapshot name or description: %s"),
|
|
@@ -469,18 +509,14 @@ class ShowVolumeSnapshot(command.ShowOne):
|
|
|
469
509
|
return parser
|
|
470
510
|
|
|
471
511
|
def take_action(self, parsed_args):
|
|
472
|
-
volume_client = self.app.client_manager.volume
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
snapshot._info.update(
|
|
477
|
-
{
|
|
478
|
-
'properties': format_columns.DictColumn(
|
|
479
|
-
snapshot._info.pop('metadata')
|
|
480
|
-
)
|
|
481
|
-
}
|
|
512
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
513
|
+
|
|
514
|
+
snapshot = volume_client.find_snapshot(
|
|
515
|
+
parsed_args.snapshot, ignore_missing=False
|
|
482
516
|
)
|
|
483
|
-
|
|
517
|
+
|
|
518
|
+
data = _format_snapshot(snapshot)
|
|
519
|
+
return zip(*sorted(data.items()))
|
|
484
520
|
|
|
485
521
|
|
|
486
522
|
class UnsetVolumeSnapshot(command.Command):
|
|
@@ -498,6 +534,7 @@ class UnsetVolumeSnapshot(command.Command):
|
|
|
498
534
|
metavar='<key>',
|
|
499
535
|
action='append',
|
|
500
536
|
default=[],
|
|
537
|
+
dest='properties',
|
|
501
538
|
help=_(
|
|
502
539
|
'Property to remove from snapshot '
|
|
503
540
|
'(repeat option to remove multiple properties)'
|
|
@@ -506,13 +543,13 @@ class UnsetVolumeSnapshot(command.Command):
|
|
|
506
543
|
return parser
|
|
507
544
|
|
|
508
545
|
def take_action(self, parsed_args):
|
|
509
|
-
volume_client = self.app.client_manager.volume
|
|
510
|
-
|
|
511
|
-
|
|
546
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
547
|
+
|
|
548
|
+
snapshot = volume_client.find_snapshot(
|
|
549
|
+
parsed_args.snapshot, ignore_missing=False
|
|
512
550
|
)
|
|
513
551
|
|
|
514
|
-
if parsed_args.
|
|
515
|
-
volume_client.
|
|
516
|
-
snapshot.id,
|
|
517
|
-
parsed_args.property,
|
|
552
|
+
if parsed_args.properties:
|
|
553
|
+
volume_client.delete_snapshot_metadata(
|
|
554
|
+
snapshot.id, keys=parsed_args.properties
|
|
518
555
|
)
|
|
@@ -14,10 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""Block Storage Service action implementations"""
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from openstack import utils as sdk_utils
|
|
18
18
|
from osc_lib.command import command
|
|
19
19
|
from osc_lib import exceptions
|
|
20
|
-
from osc_lib import utils
|
|
21
20
|
|
|
22
21
|
from openstackclient.i18n import _
|
|
23
22
|
|
|
@@ -33,7 +32,7 @@ class BlockStorageLogLevelList(command.Lister):
|
|
|
33
32
|
parser.add_argument(
|
|
34
33
|
"--host",
|
|
35
34
|
metavar="<host>",
|
|
36
|
-
default=
|
|
35
|
+
default=None,
|
|
37
36
|
help=_(
|
|
38
37
|
"List block storage service log level of specified host "
|
|
39
38
|
"(name only)"
|
|
@@ -42,9 +41,9 @@ class BlockStorageLogLevelList(command.Lister):
|
|
|
42
41
|
parser.add_argument(
|
|
43
42
|
"--service",
|
|
44
43
|
metavar="<service>",
|
|
45
|
-
default=
|
|
44
|
+
default=None,
|
|
46
45
|
choices=(
|
|
47
|
-
|
|
46
|
+
None,
|
|
48
47
|
'*',
|
|
49
48
|
'cinder-api',
|
|
50
49
|
'cinder-volume',
|
|
@@ -59,13 +58,13 @@ class BlockStorageLogLevelList(command.Lister):
|
|
|
59
58
|
parser.add_argument(
|
|
60
59
|
"--log-prefix",
|
|
61
60
|
metavar="<log-prefix>",
|
|
62
|
-
default=
|
|
61
|
+
default=None,
|
|
63
62
|
help="Prefix for the log, e.g. 'sqlalchemy'",
|
|
64
63
|
)
|
|
65
64
|
return parser
|
|
66
65
|
|
|
67
66
|
def take_action(self, parsed_args):
|
|
68
|
-
|
|
67
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
69
68
|
columns = [
|
|
70
69
|
"Binary",
|
|
71
70
|
"Host",
|
|
@@ -73,29 +72,24 @@ class BlockStorageLogLevelList(command.Lister):
|
|
|
73
72
|
"Level",
|
|
74
73
|
]
|
|
75
74
|
|
|
76
|
-
if
|
|
75
|
+
if not sdk_utils.supports_microversion(volume_client, '3.32'):
|
|
77
76
|
msg = _(
|
|
78
77
|
"--os-volume-api-version 3.32 or greater is required to "
|
|
79
78
|
"support the 'block storage log level list' command"
|
|
80
79
|
)
|
|
81
80
|
raise exceptions.CommandError(msg)
|
|
82
81
|
|
|
83
|
-
data =
|
|
82
|
+
data = []
|
|
83
|
+
for entry in volume_client.get_service_log_levels(
|
|
84
84
|
binary=parsed_args.service,
|
|
85
85
|
server=parsed_args.host,
|
|
86
86
|
prefix=parsed_args.log_prefix,
|
|
87
|
-
)
|
|
87
|
+
):
|
|
88
|
+
entry_levels = sorted(entry.levels.items(), key=lambda x: x[0])
|
|
89
|
+
for prefix, level in entry_levels:
|
|
90
|
+
data.append((entry.binary, entry.host, prefix, level))
|
|
88
91
|
|
|
89
|
-
return (
|
|
90
|
-
columns,
|
|
91
|
-
(
|
|
92
|
-
utils.get_item_properties(
|
|
93
|
-
s,
|
|
94
|
-
columns,
|
|
95
|
-
)
|
|
96
|
-
for s in data
|
|
97
|
-
),
|
|
98
|
-
)
|
|
92
|
+
return (columns, data)
|
|
99
93
|
|
|
100
94
|
|
|
101
95
|
class BlockStorageLogLevelSet(command.Command):
|
|
@@ -111,12 +105,12 @@ class BlockStorageLogLevelSet(command.Command):
|
|
|
111
105
|
metavar="<log-level>",
|
|
112
106
|
choices=('INFO', 'WARNING', 'ERROR', 'DEBUG'),
|
|
113
107
|
type=str.upper,
|
|
114
|
-
help=_("Desired log level
|
|
108
|
+
help=_("Desired log level"),
|
|
115
109
|
)
|
|
116
110
|
parser.add_argument(
|
|
117
111
|
"--host",
|
|
118
112
|
metavar="<host>",
|
|
119
|
-
default=
|
|
113
|
+
default=None,
|
|
120
114
|
help=_(
|
|
121
115
|
"Set block storage service log level of specified host "
|
|
122
116
|
"(name only)"
|
|
@@ -125,9 +119,9 @@ class BlockStorageLogLevelSet(command.Command):
|
|
|
125
119
|
parser.add_argument(
|
|
126
120
|
"--service",
|
|
127
121
|
metavar="<service>",
|
|
128
|
-
default=
|
|
122
|
+
default=None,
|
|
129
123
|
choices=(
|
|
130
|
-
|
|
124
|
+
None,
|
|
131
125
|
'*',
|
|
132
126
|
'cinder-api',
|
|
133
127
|
'cinder-volume',
|
|
@@ -142,22 +136,22 @@ class BlockStorageLogLevelSet(command.Command):
|
|
|
142
136
|
parser.add_argument(
|
|
143
137
|
"--log-prefix",
|
|
144
138
|
metavar="<log-prefix>",
|
|
145
|
-
default=
|
|
139
|
+
default=None,
|
|
146
140
|
help="Prefix for the log, e.g. 'sqlalchemy'",
|
|
147
141
|
)
|
|
148
142
|
return parser
|
|
149
143
|
|
|
150
144
|
def take_action(self, parsed_args):
|
|
151
|
-
|
|
145
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
152
146
|
|
|
153
|
-
if
|
|
147
|
+
if not sdk_utils.supports_microversion(volume_client, '3.32'):
|
|
154
148
|
msg = _(
|
|
155
149
|
"--os-volume-api-version 3.32 or greater is required to "
|
|
156
150
|
"support the 'block storage log level set' command"
|
|
157
151
|
)
|
|
158
152
|
raise exceptions.CommandError(msg)
|
|
159
153
|
|
|
160
|
-
|
|
154
|
+
volume_client.set_service_log_levels(
|
|
161
155
|
level=parsed_args.level,
|
|
162
156
|
binary=parsed_args.service,
|
|
163
157
|
server=parsed_args.host,
|
|
@@ -14,37 +14,72 @@
|
|
|
14
14
|
|
|
15
15
|
"""Service action implementations"""
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from openstack import utils as sdk_utils
|
|
18
|
+
from osc_lib.command import command
|
|
19
|
+
from osc_lib import exceptions
|
|
18
20
|
from osc_lib import utils
|
|
19
21
|
|
|
20
|
-
from openstackclient.
|
|
22
|
+
from openstackclient.i18n import _
|
|
21
23
|
|
|
22
24
|
|
|
23
|
-
class ListService(
|
|
25
|
+
class ListService(command.Lister):
|
|
26
|
+
_description = _("List service command")
|
|
27
|
+
|
|
28
|
+
def get_parser(self, prog_name):
|
|
29
|
+
parser = super().get_parser(prog_name)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--host",
|
|
32
|
+
metavar="<host>",
|
|
33
|
+
help=_("List services on specified host (name only)"),
|
|
34
|
+
)
|
|
35
|
+
parser.add_argument(
|
|
36
|
+
"--service",
|
|
37
|
+
metavar="<service>",
|
|
38
|
+
help=_("List only specified service (name only)"),
|
|
39
|
+
)
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--long",
|
|
42
|
+
action="store_true",
|
|
43
|
+
default=False,
|
|
44
|
+
help=_("List additional fields in output"),
|
|
45
|
+
)
|
|
46
|
+
return parser
|
|
47
|
+
|
|
24
48
|
def take_action(self, parsed_args):
|
|
25
|
-
|
|
49
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
26
50
|
|
|
27
|
-
columns =
|
|
51
|
+
columns: tuple[str, ...] = (
|
|
52
|
+
"binary",
|
|
53
|
+
"host",
|
|
54
|
+
"availability_zone",
|
|
55
|
+
"status",
|
|
56
|
+
"state",
|
|
57
|
+
"updated_at",
|
|
58
|
+
)
|
|
59
|
+
column_names: tuple[str, ...] = (
|
|
28
60
|
"Binary",
|
|
29
61
|
"Host",
|
|
30
62
|
"Zone",
|
|
31
63
|
"Status",
|
|
32
64
|
"State",
|
|
33
65
|
"Updated At",
|
|
34
|
-
|
|
66
|
+
)
|
|
35
67
|
|
|
36
|
-
if
|
|
37
|
-
columns
|
|
38
|
-
|
|
39
|
-
|
|
68
|
+
if sdk_utils.supports_microversion(volume_client, '3.7'):
|
|
69
|
+
columns += ("cluster",)
|
|
70
|
+
column_names += ("Cluster",)
|
|
71
|
+
if sdk_utils.supports_microversion(volume_client, '3.49'):
|
|
72
|
+
columns += ("backend_state",)
|
|
73
|
+
column_names += ("Backend State",)
|
|
40
74
|
if parsed_args.long:
|
|
41
|
-
columns
|
|
75
|
+
columns += ("disabled_reason",)
|
|
76
|
+
column_names += ("Disabled Reason",)
|
|
42
77
|
|
|
43
|
-
data =
|
|
44
|
-
parsed_args.host, parsed_args.service
|
|
78
|
+
data = volume_client.services(
|
|
79
|
+
host=parsed_args.host, binary=parsed_args.service
|
|
45
80
|
)
|
|
46
81
|
return (
|
|
47
|
-
|
|
82
|
+
column_names,
|
|
48
83
|
(
|
|
49
84
|
utils.get_item_properties(
|
|
50
85
|
s,
|
|
@@ -53,3 +88,59 @@ class ListService(service_v2.ListService):
|
|
|
53
88
|
for s in data
|
|
54
89
|
),
|
|
55
90
|
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class SetService(command.Command):
|
|
94
|
+
_description = _("Set volume service properties")
|
|
95
|
+
|
|
96
|
+
def get_parser(self, prog_name):
|
|
97
|
+
parser = super().get_parser(prog_name)
|
|
98
|
+
parser.add_argument(
|
|
99
|
+
"host",
|
|
100
|
+
metavar="<host>",
|
|
101
|
+
help=_("Name of host"),
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument(
|
|
104
|
+
"service",
|
|
105
|
+
metavar="<service>",
|
|
106
|
+
help=_("Name of service (Binary name)"),
|
|
107
|
+
)
|
|
108
|
+
enabled_group = parser.add_mutually_exclusive_group()
|
|
109
|
+
enabled_group.add_argument(
|
|
110
|
+
"--enable", action="store_true", help=_("Enable volume service")
|
|
111
|
+
)
|
|
112
|
+
enabled_group.add_argument(
|
|
113
|
+
"--disable", action="store_true", help=_("Disable volume service")
|
|
114
|
+
)
|
|
115
|
+
parser.add_argument(
|
|
116
|
+
"--disable-reason",
|
|
117
|
+
metavar="<reason>",
|
|
118
|
+
help=_(
|
|
119
|
+
"Reason for disabling the service "
|
|
120
|
+
"(should be used with --disable option)"
|
|
121
|
+
),
|
|
122
|
+
)
|
|
123
|
+
return parser
|
|
124
|
+
|
|
125
|
+
def take_action(self, parsed_args):
|
|
126
|
+
if parsed_args.disable_reason and not parsed_args.disable:
|
|
127
|
+
msg = _(
|
|
128
|
+
"Cannot specify option --disable-reason without "
|
|
129
|
+
"--disable specified."
|
|
130
|
+
)
|
|
131
|
+
raise exceptions.CommandError(msg)
|
|
132
|
+
|
|
133
|
+
volume_client = self.app.client_manager.sdk_connection.volume
|
|
134
|
+
|
|
135
|
+
service = volume_client.find_service(
|
|
136
|
+
host=parsed_args.host, service=parsed_args.service
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
if parsed_args.enable:
|
|
140
|
+
service.enable(volume_client)
|
|
141
|
+
|
|
142
|
+
if parsed_args.disable:
|
|
143
|
+
service.disable(
|
|
144
|
+
volume_client,
|
|
145
|
+
reason=parsed_args.disable_reason,
|
|
146
|
+
)
|