python-openstackclient 6.3.0__py3-none-any.whl → 6.5.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/common/availability_zone.py +4 -4
- openstackclient/common/pagination.py +82 -0
- openstackclient/compute/v2/flavor.py +2 -16
- openstackclient/compute/v2/hypervisor.py +2 -21
- openstackclient/compute/v2/keypair.py +2 -9
- openstackclient/compute/v2/server.py +220 -131
- openstackclient/compute/v2/server_event.py +30 -19
- openstackclient/compute/v2/server_group.py +2 -23
- openstackclient/compute/v2/server_migration.py +2 -22
- openstackclient/compute/v2/usage.py +4 -6
- openstackclient/identity/v3/mapping.py +25 -3
- openstackclient/identity/v3/policy.py +3 -1
- openstackclient/image/v2/cache.py +218 -0
- openstackclient/image/v2/image.py +40 -17
- openstackclient/image/v2/metadef_namespaces.py +25 -21
- openstackclient/image/v2/metadef_objects.py +189 -0
- openstackclient/image/v2/metadef_properties.py +284 -0
- openstackclient/network/utils.py +100 -0
- openstackclient/network/v2/default_security_group_rule.py +418 -0
- openstackclient/network/v2/local_ip_association.py +1 -1
- openstackclient/network/v2/ndp_proxy.py +7 -3
- openstackclient/network/v2/network.py +2 -2
- openstackclient/network/v2/port.py +65 -19
- openstackclient/network/v2/security_group_rule.py +18 -111
- openstackclient/network/v2/subnet.py +1 -0
- openstackclient/object/v1/container.py +2 -12
- openstackclient/object/v1/object.py +2 -11
- openstackclient/tests/functional/base.py +13 -6
- openstackclient/tests/functional/identity/v3/test_role.py +11 -3
- openstackclient/tests/functional/network/v2/common.py +7 -1
- openstackclient/tests/functional/network/v2/test_address_group.py +2 -4
- openstackclient/tests/functional/network/v2/test_address_scope.py +0 -6
- openstackclient/tests/functional/network/v2/test_default_security_group_rule.py +67 -0
- openstackclient/tests/functional/network/v2/test_floating_ip.py +3 -6
- openstackclient/tests/functional/network/v2/test_ip_availability.py +3 -8
- openstackclient/tests/functional/network/v2/test_l3_conntrack_helper.py +3 -4
- openstackclient/tests/functional/network/v2/test_local_ip.py +2 -4
- openstackclient/tests/functional/network/v2/test_network.py +18 -17
- openstackclient/tests/functional/network/v2/test_network_agent.py +24 -21
- openstackclient/tests/functional/network/v2/test_network_flavor.py +0 -6
- openstackclient/tests/functional/network/v2/test_network_flavor_profile.py +0 -6
- openstackclient/tests/functional/network/v2/test_network_meter.py +6 -6
- openstackclient/tests/functional/network/v2/test_network_meter_rule.py +7 -8
- openstackclient/tests/functional/network/v2/test_network_ndp_proxy.py +1 -3
- openstackclient/tests/functional/network/v2/test_network_qos_policy.py +4 -4
- openstackclient/tests/functional/network/v2/test_network_qos_rule.py +16 -20
- openstackclient/tests/functional/network/v2/test_network_qos_rule_type.py +4 -4
- openstackclient/tests/functional/network/v2/test_network_rbac.py +1 -4
- openstackclient/tests/functional/network/v2/test_network_segment.py +7 -12
- openstackclient/tests/functional/network/v2/test_network_segment_range.py +3 -4
- openstackclient/tests/functional/network/v2/test_network_service_provider.py +2 -4
- openstackclient/tests/functional/network/v2/test_network_trunk.py +3 -3
- openstackclient/tests/functional/network/v2/test_port.py +2 -8
- openstackclient/tests/functional/network/v2/test_router.py +0 -6
- openstackclient/tests/functional/network/v2/test_security_group.py +1 -4
- openstackclient/tests/functional/network/v2/test_security_group_rule.py +1 -4
- openstackclient/tests/functional/network/v2/test_subnet.py +4 -22
- openstackclient/tests/functional/network/v2/test_subnet_pool.py +0 -6
- openstackclient/tests/unit/common/test_availability_zone.py +28 -30
- openstackclient/tests/unit/common/test_extension.py +1 -4
- openstackclient/tests/unit/common/test_limits.py +2 -4
- openstackclient/tests/unit/common/test_project_cleanup.py +3 -10
- openstackclient/tests/unit/common/test_quota.py +18 -24
- openstackclient/tests/unit/compute/v2/fakes.py +24 -11
- openstackclient/tests/unit/compute/v2/test_agent.py +1 -1
- openstackclient/tests/unit/compute/v2/test_aggregate.py +62 -72
- openstackclient/tests/unit/compute/v2/test_console.py +18 -30
- openstackclient/tests/unit/compute/v2/test_flavor.py +85 -89
- openstackclient/tests/unit/compute/v2/test_host.py +12 -19
- openstackclient/tests/unit/compute/v2/test_hypervisor.py +23 -25
- openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +2 -6
- openstackclient/tests/unit/compute/v2/test_keypair.py +25 -39
- openstackclient/tests/unit/compute/v2/test_server.py +316 -365
- openstackclient/tests/unit/compute/v2/test_server_backup.py +5 -17
- openstackclient/tests/unit/compute/v2/test_server_event.py +23 -25
- openstackclient/tests/unit/compute/v2/test_server_group.py +41 -33
- openstackclient/tests/unit/compute/v2/test_server_image.py +6 -18
- openstackclient/tests/unit/compute/v2/test_server_migration.py +45 -45
- openstackclient/tests/unit/compute/v2/test_server_volume.py +15 -31
- openstackclient/tests/unit/compute/v2/test_service.py +51 -56
- openstackclient/tests/unit/compute/v2/test_usage.py +10 -13
- openstackclient/tests/unit/fakes.py +4 -0
- openstackclient/tests/unit/identity/v3/test_mappings.py +9 -4
- openstackclient/tests/unit/identity/v3/test_trust.py +0 -2
- openstackclient/tests/unit/image/v1/fakes.py +2 -1
- openstackclient/tests/unit/image/v1/test_image.py +1 -1
- openstackclient/tests/unit/image/v2/fakes.py +82 -0
- openstackclient/tests/unit/image/v2/test_cache.py +214 -0
- openstackclient/tests/unit/image/v2/test_image.py +62 -4
- openstackclient/tests/unit/image/v2/test_metadef_namespaces.py +5 -19
- openstackclient/tests/unit/image/v2/test_metadef_objects.py +162 -0
- openstackclient/tests/unit/image/v2/test_metadef_properties.py +227 -0
- openstackclient/tests/unit/integ/cli/test_shell.py +0 -2
- openstackclient/tests/unit/network/test_common.py +3 -3
- openstackclient/tests/unit/network/v2/fakes.py +1 -0
- openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +1133 -0
- openstackclient/tests/unit/network/v2/test_floating_ip_compute.py +5 -13
- openstackclient/tests/unit/network/v2/test_floating_ip_pool_compute.py +1 -9
- openstackclient/tests/unit/network/v2/test_network.py +33 -0
- openstackclient/tests/unit/network/v2/test_network_compute.py +5 -11
- openstackclient/tests/unit/network/v2/test_network_trunk.py +6 -8
- openstackclient/tests/unit/network/v2/test_port.py +83 -38
- openstackclient/tests/unit/network/v2/test_security_group_compute.py +7 -15
- openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +19 -27
- openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +3 -6
- openstackclient/tests/unit/network/v2/test_subnet.py +92 -0
- openstackclient/tests/unit/network/v2/test_subnet_pool.py +11 -13
- openstackclient/tests/unit/test_shell.py +1 -7
- openstackclient/tests/unit/utils.py +10 -4
- openstackclient/tests/unit/volume/v1/fakes.py +7 -1
- openstackclient/tests/unit/volume/v1/test_qos_specs.py +2 -2
- openstackclient/tests/unit/volume/v1/test_service.py +1 -1
- openstackclient/tests/unit/volume/v1/test_transfer_request.py +2 -2
- openstackclient/tests/unit/volume/v1/test_type.py +2 -4
- openstackclient/tests/unit/volume/v1/test_volume.py +5 -7
- openstackclient/tests/unit/volume/v1/test_volume_backup.py +4 -4
- openstackclient/tests/unit/volume/v2/fakes.py +32 -12
- openstackclient/tests/unit/volume/v2/test_backup_record.py +1 -1
- openstackclient/tests/unit/volume/v2/test_consistency_group.py +4 -6
- openstackclient/tests/unit/volume/v2/test_consistency_group_snapshot.py +2 -4
- openstackclient/tests/unit/volume/v2/test_qos_specs.py +2 -2
- openstackclient/tests/unit/volume/v2/test_service.py +1 -1
- openstackclient/tests/unit/volume/v2/test_volume.py +78 -16
- openstackclient/tests/unit/volume/v2/test_volume_backend.py +10 -22
- openstackclient/tests/unit/volume/v2/test_volume_backup.py +76 -89
- openstackclient/tests/unit/volume/v2/test_volume_host.py +1 -1
- openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +5 -7
- openstackclient/tests/unit/volume/v2/test_volume_transfer_request.py +4 -8
- openstackclient/tests/unit/volume/v2/test_volume_type.py +164 -24
- openstackclient/tests/unit/volume/v3/fakes.py +91 -15
- openstackclient/tests/unit/volume/v3/test_block_storage_cleanup.py +3 -7
- openstackclient/tests/unit/volume/v3/test_block_storage_cluster.py +11 -31
- openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +6 -16
- openstackclient/tests/unit/volume/v3/test_block_storage_manage.py +219 -157
- openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py +32 -23
- openstackclient/tests/unit/volume/v3/test_volume.py +50 -48
- openstackclient/tests/unit/volume/v3/test_volume_attachment.py +17 -47
- openstackclient/tests/unit/volume/v3/test_volume_group.py +23 -65
- openstackclient/tests/unit/volume/v3/test_volume_group_snapshot.py +88 -77
- openstackclient/tests/unit/volume/v3/test_volume_group_type.py +14 -42
- openstackclient/tests/unit/volume/v3/test_volume_message.py +10 -28
- openstackclient/volume/v1/volume.py +2 -14
- openstackclient/volume/v2/volume.py +30 -15
- openstackclient/volume/v2/volume_backend.py +10 -18
- openstackclient/volume/v2/volume_backup.py +18 -15
- openstackclient/volume/v2/volume_snapshot.py +2 -12
- openstackclient/volume/v2/volume_type.py +211 -14
- openstackclient/volume/v3/block_storage_manage.py +72 -11
- openstackclient/volume/v3/block_storage_resource_filter.py +33 -11
- openstackclient/volume/v3/volume_attachment.py +2 -14
- openstackclient/volume/v3/volume_group_snapshot.py +27 -27
- openstackclient/volume/v3/volume_message.py +2 -13
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/AUTHORS +11 -0
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/METADATA +6 -5
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/RECORD +160 -151
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/entry_points.txt +23 -5
- python_openstackclient-6.5.0.dist-info/pbr.json +1 -0
- openstackclient/tests/unit/common/test_parseractions.py +0 -233
- python_openstackclient-6.3.0.dist-info/pbr.json +0 -1
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/LICENSE +0 -0
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/WHEEL +0 -0
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/top_level.txt +0 -0
|
@@ -32,13 +32,12 @@ from osc_lib.cli import parseractions
|
|
|
32
32
|
from osc_lib.command import command
|
|
33
33
|
from osc_lib import exceptions
|
|
34
34
|
from osc_lib import utils
|
|
35
|
-
from oslo_utils import strutils
|
|
36
35
|
|
|
36
|
+
from openstackclient.common import pagination
|
|
37
37
|
from openstackclient.i18n import _
|
|
38
38
|
from openstackclient.identity import common as identity_common
|
|
39
39
|
from openstackclient.network import common as network_common
|
|
40
40
|
|
|
41
|
-
|
|
42
41
|
LOG = logging.getLogger(__name__)
|
|
43
42
|
|
|
44
43
|
IMAGE_STRING_FOR_BFV = 'N/A (booted from volume)'
|
|
@@ -150,16 +149,13 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|
|
150
149
|
# Some commands using this routine were originally implemented with the
|
|
151
150
|
# nova python wrappers, and were later migrated to use the SDK. Map the
|
|
152
151
|
# SDK's property names to the original property names to maintain backward
|
|
153
|
-
# compatibility for existing users.
|
|
154
|
-
# and new name so users can consume the data by either name.
|
|
152
|
+
# compatibility for existing users.
|
|
155
153
|
column_map = {
|
|
156
154
|
'access_ipv4': 'accessIPv4',
|
|
157
155
|
'access_ipv6': 'accessIPv6',
|
|
158
156
|
'admin_password': 'adminPass',
|
|
159
|
-
'
|
|
160
|
-
'volumes': 'os-extended-volumes:volumes_attached',
|
|
157
|
+
'attached_volumes': 'volumes_attached',
|
|
161
158
|
'availability_zone': 'OS-EXT-AZ:availability_zone',
|
|
162
|
-
'block_device_mapping': 'block_device_mapping_v2',
|
|
163
159
|
'compute_host': 'OS-EXT-SRV-ATTR:host',
|
|
164
160
|
'created_at': 'created',
|
|
165
161
|
'disk_config': 'OS-DCF:diskConfig',
|
|
@@ -169,7 +165,6 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|
|
169
165
|
'fault': 'fault',
|
|
170
166
|
'hostname': 'OS-EXT-SRV-ATTR:hostname',
|
|
171
167
|
'hypervisor_hostname': 'OS-EXT-SRV-ATTR:hypervisor_hostname',
|
|
172
|
-
'image_id': 'imageRef',
|
|
173
168
|
'instance_name': 'OS-EXT-SRV-ATTR:instance_name',
|
|
174
169
|
'is_locked': 'locked',
|
|
175
170
|
'kernel_id': 'OS-EXT-SRV-ATTR:kernel_id',
|
|
@@ -180,21 +175,56 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|
|
180
175
|
'ramdisk_id': 'OS-EXT-SRV-ATTR:ramdisk_id',
|
|
181
176
|
'reservation_id': 'OS-EXT-SRV-ATTR:reservation_id',
|
|
182
177
|
'root_device_name': 'OS-EXT-SRV-ATTR:root_device_name',
|
|
183
|
-
'scheduler_hints': 'OS-SCH-HNT:scheduler_hints',
|
|
184
178
|
'task_state': 'OS-EXT-STS:task_state',
|
|
185
179
|
'terminated_at': 'OS-SRV-USG:terminated_at',
|
|
186
180
|
'updated_at': 'updated',
|
|
187
181
|
'user_data': 'OS-EXT-SRV-ATTR:user_data',
|
|
188
182
|
'vm_state': 'OS-EXT-STS:vm_state',
|
|
189
183
|
}
|
|
184
|
+
# Some columns returned by openstacksdk should not be shown because they're
|
|
185
|
+
# either irrelevant or duplicates
|
|
186
|
+
ignored_columns = {
|
|
187
|
+
# computed columns
|
|
188
|
+
'interface_ip',
|
|
189
|
+
'location',
|
|
190
|
+
'private_v4',
|
|
191
|
+
'private_v6',
|
|
192
|
+
'public_v4',
|
|
193
|
+
'public_v6',
|
|
194
|
+
# create-only columns
|
|
195
|
+
'block_device_mapping',
|
|
196
|
+
'image_id',
|
|
197
|
+
'max_count',
|
|
198
|
+
'min_count',
|
|
199
|
+
'scheduler_hints',
|
|
200
|
+
# aliases
|
|
201
|
+
'volumes',
|
|
202
|
+
# unnecessary
|
|
203
|
+
'links',
|
|
204
|
+
}
|
|
205
|
+
# Some columns are only present in certain responses and should not be
|
|
206
|
+
# shown otherwise.
|
|
207
|
+
optional_columns = {
|
|
208
|
+
'admin_password', # removed in 2.14
|
|
209
|
+
'fault', # only present in errored servers
|
|
210
|
+
'flavor_id', # removed in 2.47
|
|
211
|
+
'networks', # only present in create responses
|
|
212
|
+
'security_groups', # only present in create, detail responses
|
|
213
|
+
}
|
|
190
214
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
215
|
+
data = {}
|
|
216
|
+
for key, value in info.items():
|
|
217
|
+
if key in ignored_columns:
|
|
218
|
+
continue
|
|
219
|
+
|
|
220
|
+
if key in optional_columns:
|
|
221
|
+
if info[key] is None:
|
|
222
|
+
continue
|
|
223
|
+
|
|
224
|
+
alias = column_map.get(key)
|
|
225
|
+
data[alias or key] = value
|
|
226
|
+
|
|
227
|
+
info = data
|
|
198
228
|
|
|
199
229
|
# Convert the image blob to a name
|
|
200
230
|
image_info = info.get('image', {})
|
|
@@ -215,46 +245,57 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|
|
215
245
|
# Convert the flavor blob to a name
|
|
216
246
|
flavor_info = info.get('flavor', {})
|
|
217
247
|
# Microversion 2.47 puts the embedded flavor into the server response
|
|
218
|
-
# body
|
|
219
|
-
|
|
220
|
-
if 'id' in flavor_info:
|
|
248
|
+
# body. The presence of the 'original_name' attribute indicates this.
|
|
249
|
+
if flavor_info.get('original_name') is None: # microversion < 2.47
|
|
221
250
|
flavor_id = flavor_info.get('id', '')
|
|
222
251
|
try:
|
|
223
252
|
flavor = utils.find_resource(compute_client.flavors, flavor_id)
|
|
224
253
|
info['flavor'] = "%s (%s)" % (flavor.name, flavor_id)
|
|
225
254
|
except Exception:
|
|
226
255
|
info['flavor'] = flavor_id
|
|
227
|
-
else:
|
|
256
|
+
else: # microversion >= 2.47
|
|
228
257
|
info['flavor'] = format_columns.DictColumn(flavor_info)
|
|
229
258
|
|
|
230
|
-
|
|
259
|
+
# there's a lot of redundant information in BDMs - strip it
|
|
260
|
+
if 'volumes_attached' in info:
|
|
231
261
|
info.update(
|
|
232
262
|
{
|
|
233
263
|
'volumes_attached': format_columns.ListDictColumn(
|
|
234
|
-
|
|
264
|
+
[
|
|
265
|
+
{
|
|
266
|
+
k: v
|
|
267
|
+
for k, v in volume.items()
|
|
268
|
+
if v is not None and k != 'location'
|
|
269
|
+
}
|
|
270
|
+
for volume in info.pop('volumes_attached') or []
|
|
271
|
+
]
|
|
235
272
|
)
|
|
236
273
|
}
|
|
237
274
|
)
|
|
275
|
+
|
|
238
276
|
if 'security_groups' in info:
|
|
239
277
|
info.update(
|
|
240
278
|
{
|
|
241
279
|
'security_groups': format_columns.ListDictColumn(
|
|
242
|
-
info.pop('security_groups')
|
|
280
|
+
info.pop('security_groups'),
|
|
243
281
|
)
|
|
244
282
|
}
|
|
245
283
|
)
|
|
284
|
+
|
|
246
285
|
if 'tags' in info:
|
|
247
286
|
info.update({'tags': format_columns.ListColumn(info.pop('tags'))})
|
|
248
287
|
|
|
249
|
-
#
|
|
250
|
-
#
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
288
|
+
# Map 'networks' to 'addresses', if present. Note that the 'networks' key
|
|
289
|
+
# is used for create responses, otherwise it's 'addresses'. We know it'll
|
|
290
|
+
# be set because this is one of our optional columns.
|
|
291
|
+
if 'networks' in info:
|
|
292
|
+
info['addresses'] = format_columns.DictListColumn(
|
|
293
|
+
info.pop('networks', {}),
|
|
294
|
+
)
|
|
295
|
+
else:
|
|
296
|
+
info['addresses'] = AddressesColumn(info.get('addresses', {}))
|
|
256
297
|
|
|
257
|
-
# Map 'metadata' field to 'properties'
|
|
298
|
+
# Map 'metadata' field to 'properties' and format
|
|
258
299
|
info['properties'] = format_columns.DictColumn(info.pop('metadata'))
|
|
259
300
|
|
|
260
301
|
# Migrate tenant_id to project_id naming
|
|
@@ -267,12 +308,33 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|
|
267
308
|
info['OS-EXT-STS:power_state']
|
|
268
309
|
)
|
|
269
310
|
|
|
270
|
-
# Remove values that are long and not too useful
|
|
271
|
-
info.pop('links', None)
|
|
272
|
-
|
|
273
311
|
return info
|
|
274
312
|
|
|
275
313
|
|
|
314
|
+
def bool_from_str(value, strict=False):
|
|
315
|
+
true_strings = ('1', 't', 'true', 'on', 'y', 'yes')
|
|
316
|
+
false_strings = ('0', 'f', 'false', 'off', 'n', 'no')
|
|
317
|
+
|
|
318
|
+
if isinstance(value, bool):
|
|
319
|
+
return value
|
|
320
|
+
|
|
321
|
+
lowered = value.strip().lower()
|
|
322
|
+
if lowered in true_strings:
|
|
323
|
+
return True
|
|
324
|
+
elif lowered in false_strings or not strict:
|
|
325
|
+
return False
|
|
326
|
+
|
|
327
|
+
msg = _(
|
|
328
|
+
"Unrecognized value '%(value)s'; acceptable values are: %(valid)s"
|
|
329
|
+
) % {
|
|
330
|
+
'value': value,
|
|
331
|
+
'valid': ', '.join(
|
|
332
|
+
f"'{s}'" for s in sorted(true_strings + false_strings)
|
|
333
|
+
),
|
|
334
|
+
}
|
|
335
|
+
raise ValueError(msg)
|
|
336
|
+
|
|
337
|
+
|
|
276
338
|
def boolenv(*vars, default=False):
|
|
277
339
|
"""Search for the first defined of possibly many bool-like env vars.
|
|
278
340
|
|
|
@@ -287,7 +349,7 @@ def boolenv(*vars, default=False):
|
|
|
287
349
|
for v in vars:
|
|
288
350
|
value = os.environ.get(v, None)
|
|
289
351
|
if value:
|
|
290
|
-
return
|
|
352
|
+
return bool_from_str(value)
|
|
291
353
|
return default
|
|
292
354
|
|
|
293
355
|
|
|
@@ -818,7 +880,7 @@ class NICAction(argparse.Action):
|
|
|
818
880
|
"Invalid argument %s; characters ',' and '=' are not "
|
|
819
881
|
"allowed"
|
|
820
882
|
)
|
|
821
|
-
raise argparse.
|
|
883
|
+
raise argparse.ArgumentError(self, msg % values)
|
|
822
884
|
|
|
823
885
|
values = '='.join([self.key, values])
|
|
824
886
|
else:
|
|
@@ -846,7 +908,7 @@ class NICAction(argparse.Action):
|
|
|
846
908
|
"'net-id=net-uuid,port-id=port-uuid,v4-fixed-ip=ip-addr,"
|
|
847
909
|
"v6-fixed-ip=ip-addr,tag=tag'"
|
|
848
910
|
)
|
|
849
|
-
raise argparse.
|
|
911
|
+
raise argparse.ArgumentError(self, msg % values)
|
|
850
912
|
|
|
851
913
|
info[k] = v
|
|
852
914
|
|
|
@@ -855,7 +917,7 @@ class NICAction(argparse.Action):
|
|
|
855
917
|
'Invalid argument %s; either network or port should be '
|
|
856
918
|
'specified but not both'
|
|
857
919
|
)
|
|
858
|
-
raise argparse.
|
|
920
|
+
raise argparse.ArgumenteError(self, msg % values)
|
|
859
921
|
|
|
860
922
|
getattr(namespace, self.dest).append(info)
|
|
861
923
|
|
|
@@ -873,7 +935,7 @@ class BDMLegacyAction(argparse.Action):
|
|
|
873
935
|
"Invalid argument %s; argument must be of form "
|
|
874
936
|
"'dev-name=id[:type[:size[:delete-on-terminate]]]'"
|
|
875
937
|
)
|
|
876
|
-
raise argparse.
|
|
938
|
+
raise argparse.ArgumentError(self, msg % values)
|
|
877
939
|
|
|
878
940
|
mapping = {
|
|
879
941
|
'device_name': dev_name,
|
|
@@ -890,7 +952,7 @@ class BDMLegacyAction(argparse.Action):
|
|
|
890
952
|
"Invalid argument %s; 'type' must be one of: volume, "
|
|
891
953
|
"snapshot, image"
|
|
892
954
|
)
|
|
893
|
-
raise argparse.
|
|
955
|
+
raise argparse.ArgumentError(self, msg % values)
|
|
894
956
|
|
|
895
957
|
mapping['source_type'] = dev_map[1]
|
|
896
958
|
|
|
@@ -943,12 +1005,13 @@ class BDMAction(parseractions.MultiKeyValueAction):
|
|
|
943
1005
|
"Invalid keys %(invalid_keys)s specified.\n"
|
|
944
1006
|
"Valid keys are: %(valid_keys)s"
|
|
945
1007
|
)
|
|
946
|
-
raise argparse.
|
|
1008
|
+
raise argparse.ArgumentError(
|
|
1009
|
+
self,
|
|
947
1010
|
msg
|
|
948
1011
|
% {
|
|
949
1012
|
'invalid_keys': ', '.join(invalid_keys),
|
|
950
1013
|
'valid_keys': ', '.join(valid_keys),
|
|
951
|
-
}
|
|
1014
|
+
},
|
|
952
1015
|
)
|
|
953
1016
|
|
|
954
1017
|
missing_keys = [k for k in self.required_keys if k not in keys]
|
|
@@ -957,12 +1020,13 @@ class BDMAction(parseractions.MultiKeyValueAction):
|
|
|
957
1020
|
"Missing required keys %(missing_keys)s.\n"
|
|
958
1021
|
"Required keys are: %(required_keys)s"
|
|
959
1022
|
)
|
|
960
|
-
raise argparse.
|
|
1023
|
+
raise argparse.ArgumentError(
|
|
1024
|
+
self,
|
|
961
1025
|
msg
|
|
962
1026
|
% {
|
|
963
1027
|
'missing_keys': ', '.join(missing_keys),
|
|
964
1028
|
'required_keys': ', '.join(self.required_keys),
|
|
965
|
-
}
|
|
1029
|
+
},
|
|
966
1030
|
)
|
|
967
1031
|
|
|
968
1032
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
@@ -1313,10 +1377,19 @@ class CreateServer(command.ShowOne):
|
|
|
1313
1377
|
'(supported by --os-compute-api-version 2.74 or above)'
|
|
1314
1378
|
),
|
|
1315
1379
|
)
|
|
1380
|
+
parser.add_argument(
|
|
1381
|
+
'--server-group',
|
|
1382
|
+
metavar='<server-group>',
|
|
1383
|
+
help=_(
|
|
1384
|
+
"Server group to create the server within "
|
|
1385
|
+
"(this is an alias for '--hint group=<server-group-id>')"
|
|
1386
|
+
),
|
|
1387
|
+
)
|
|
1316
1388
|
parser.add_argument(
|
|
1317
1389
|
'--hint',
|
|
1318
1390
|
metavar='<key=value>',
|
|
1319
1391
|
action=parseractions.KeyValueAppendAction,
|
|
1392
|
+
dest='hints',
|
|
1320
1393
|
default={},
|
|
1321
1394
|
help=_('Hints for the scheduler'),
|
|
1322
1395
|
)
|
|
@@ -1553,8 +1626,8 @@ class CreateServer(command.ShowOne):
|
|
|
1553
1626
|
if parsed_args.description:
|
|
1554
1627
|
if compute_client.api_version < api_versions.APIVersion("2.19"):
|
|
1555
1628
|
msg = _(
|
|
1556
|
-
|
|
1557
|
-
|
|
1629
|
+
'--os-compute-api-version 2.19 or greater is '
|
|
1630
|
+
'required to support the --description option'
|
|
1558
1631
|
)
|
|
1559
1632
|
raise exceptions.CommandError(msg)
|
|
1560
1633
|
|
|
@@ -1580,6 +1653,12 @@ class CreateServer(command.ShowOne):
|
|
|
1580
1653
|
]
|
|
1581
1654
|
elif parsed_args.boot_from_volume:
|
|
1582
1655
|
# Tell nova to create a root volume from the image provided.
|
|
1656
|
+
if not image:
|
|
1657
|
+
msg = _(
|
|
1658
|
+
"An image (--image or --image-property) is required "
|
|
1659
|
+
"to support --boot-from-volume option"
|
|
1660
|
+
)
|
|
1661
|
+
raise exceptions.CommandError(msg)
|
|
1583
1662
|
block_device_mapping_v2 = [
|
|
1584
1663
|
{
|
|
1585
1664
|
'uuid': image.id,
|
|
@@ -1713,8 +1792,9 @@ class CreateServer(command.ShowOne):
|
|
|
1713
1792
|
|
|
1714
1793
|
if 'delete_on_termination' in mapping:
|
|
1715
1794
|
try:
|
|
1716
|
-
value =
|
|
1717
|
-
mapping['delete_on_termination'],
|
|
1795
|
+
value = bool_from_str(
|
|
1796
|
+
mapping['delete_on_termination'],
|
|
1797
|
+
strict=True,
|
|
1718
1798
|
)
|
|
1719
1799
|
except ValueError:
|
|
1720
1800
|
msg = _(
|
|
@@ -1828,13 +1908,20 @@ class CreateServer(command.ShowOne):
|
|
|
1828
1908
|
security_group_names.append(sg['name'])
|
|
1829
1909
|
|
|
1830
1910
|
hints = {}
|
|
1831
|
-
for key, values in parsed_args.
|
|
1911
|
+
for key, values in parsed_args.hints.items():
|
|
1832
1912
|
# only items with multiple values will result in a list
|
|
1833
1913
|
if len(values) == 1:
|
|
1834
1914
|
hints[key] = values[0]
|
|
1835
1915
|
else:
|
|
1836
1916
|
hints[key] = values
|
|
1837
1917
|
|
|
1918
|
+
if parsed_args.server_group:
|
|
1919
|
+
server_group_obj = utils.find_resource(
|
|
1920
|
+
compute_client.server_groups,
|
|
1921
|
+
parsed_args.server_group,
|
|
1922
|
+
)
|
|
1923
|
+
hints['group'] = server_group_obj.id
|
|
1924
|
+
|
|
1838
1925
|
if isinstance(parsed_args.config_drive, bool):
|
|
1839
1926
|
# NOTE(stephenfin): The API doesn't accept False as a value :'(
|
|
1840
1927
|
config_drive = parsed_args.config_drive or None
|
|
@@ -1957,9 +2044,8 @@ class CreateServer(command.ShowOne):
|
|
|
1957
2044
|
):
|
|
1958
2045
|
self.app.stdout.write('\n')
|
|
1959
2046
|
else:
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
raise SystemExit
|
|
2047
|
+
msg = _('Error creating server: %s') % parsed_args.server_name
|
|
2048
|
+
raise exceptions.CommandError(msg)
|
|
1963
2049
|
|
|
1964
2050
|
details = _prep_server_detail(compute_client, image_client, server)
|
|
1965
2051
|
return zip(*sorted(details.items()))
|
|
@@ -2051,17 +2137,52 @@ class DeleteServer(command.Command):
|
|
|
2051
2137
|
server_obj.id,
|
|
2052
2138
|
callback=_show_progress,
|
|
2053
2139
|
):
|
|
2054
|
-
msg = _('Error deleting server: %s')
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2140
|
+
msg = _('Error deleting server: %s') % server_obj.id
|
|
2141
|
+
raise exceptions.CommandError(msg)
|
|
2142
|
+
|
|
2143
|
+
|
|
2144
|
+
class PercentAction(argparse.Action):
|
|
2145
|
+
def __init__(
|
|
2146
|
+
self,
|
|
2147
|
+
option_strings,
|
|
2148
|
+
dest,
|
|
2149
|
+
nargs=None,
|
|
2150
|
+
const=None,
|
|
2151
|
+
default=None,
|
|
2152
|
+
type=None,
|
|
2153
|
+
choices=None,
|
|
2154
|
+
required=False,
|
|
2155
|
+
help=None,
|
|
2156
|
+
metavar=None,
|
|
2157
|
+
):
|
|
2158
|
+
if nargs == 0:
|
|
2159
|
+
raise ValueError(
|
|
2160
|
+
'nargs for store actions must be != 0; if you '
|
|
2161
|
+
'have nothing to store, actions such as store '
|
|
2162
|
+
'true or store const may be more appropriate'
|
|
2163
|
+
)
|
|
2164
|
+
|
|
2165
|
+
if const is not None:
|
|
2166
|
+
raise ValueError('const does not make sense for PercentAction')
|
|
2058
2167
|
|
|
2168
|
+
super().__init__(
|
|
2169
|
+
option_strings=option_strings,
|
|
2170
|
+
dest=dest,
|
|
2171
|
+
nargs=nargs,
|
|
2172
|
+
const=const,
|
|
2173
|
+
default=default,
|
|
2174
|
+
type=type,
|
|
2175
|
+
choices=choices,
|
|
2176
|
+
required=required,
|
|
2177
|
+
help=help,
|
|
2178
|
+
metavar=metavar,
|
|
2179
|
+
)
|
|
2059
2180
|
|
|
2060
|
-
def
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2181
|
+
def __call__(self, parser, namespace, values, option_string=None):
|
|
2182
|
+
x = int(values)
|
|
2183
|
+
if not 0 < x <= 100:
|
|
2184
|
+
raise argparse.ArgumentError(self, "Must be between 0 and 100")
|
|
2185
|
+
setattr(namespace, self.dest, x)
|
|
2065
2186
|
|
|
2066
2187
|
|
|
2067
2188
|
class ListServer(command.Lister):
|
|
@@ -2214,7 +2335,7 @@ class ListServer(command.Lister):
|
|
|
2214
2335
|
)
|
|
2215
2336
|
parser.add_argument(
|
|
2216
2337
|
'--progress',
|
|
2217
|
-
|
|
2338
|
+
action=PercentAction,
|
|
2218
2339
|
default=None,
|
|
2219
2340
|
help=_(
|
|
2220
2341
|
'Search by progress value (%%) '
|
|
@@ -2341,29 +2462,7 @@ class ListServer(command.Lister):
|
|
|
2341
2462
|
'Mutually exclusive with "--no-name-lookup|-n" option.'
|
|
2342
2463
|
),
|
|
2343
2464
|
)
|
|
2344
|
-
|
|
2345
|
-
'--marker',
|
|
2346
|
-
metavar='<server>',
|
|
2347
|
-
default=None,
|
|
2348
|
-
help=_(
|
|
2349
|
-
'The last server of the previous page. Display '
|
|
2350
|
-
'list of servers after marker. Display all servers if not '
|
|
2351
|
-
'specified. When used with ``--deleted``, the marker must '
|
|
2352
|
-
'be an ID, otherwise a name or ID can be used.'
|
|
2353
|
-
),
|
|
2354
|
-
)
|
|
2355
|
-
parser.add_argument(
|
|
2356
|
-
'--limit',
|
|
2357
|
-
metavar='<num-servers>',
|
|
2358
|
-
type=int,
|
|
2359
|
-
default=None,
|
|
2360
|
-
help=_(
|
|
2361
|
-
"Maximum number of servers to display. If limit equals -1, "
|
|
2362
|
-
"all servers will be displayed. If limit is greater than "
|
|
2363
|
-
"'osapi_max_limit' option of Nova API, "
|
|
2364
|
-
"'osapi_max_limit' will be used instead."
|
|
2365
|
-
),
|
|
2366
|
-
)
|
|
2465
|
+
pagination.add_marker_pagination_option_to_parser(parser)
|
|
2367
2466
|
parser.add_argument(
|
|
2368
2467
|
'--changes-before',
|
|
2369
2468
|
metavar='<changes-before>',
|
|
@@ -2743,7 +2842,7 @@ class ListServer(command.Lister):
|
|
|
2743
2842
|
try:
|
|
2744
2843
|
# some deployments can have *loads* of images so we only
|
|
2745
2844
|
# want to list the ones we care about. It would be better
|
|
2746
|
-
# to only
|
|
2845
|
+
# to only return the *fields* we care about (name) but
|
|
2747
2846
|
# glance doesn't support that
|
|
2748
2847
|
# NOTE(stephenfin): This could result in super long URLs
|
|
2749
2848
|
# but it seems unlikely to cause issues. Apache supports
|
|
@@ -3102,9 +3201,8 @@ revert to release the new server and restart the old one."""
|
|
|
3102
3201
|
):
|
|
3103
3202
|
self.app.stdout.write(_('Complete\n'))
|
|
3104
3203
|
else:
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
raise SystemExit
|
|
3204
|
+
msg = _('Error migrating server: %s') % server.id
|
|
3205
|
+
raise exceptions.CommandError(msg)
|
|
3108
3206
|
|
|
3109
3207
|
|
|
3110
3208
|
class PauseServer(command.Command):
|
|
@@ -3186,9 +3284,8 @@ class RebootServer(command.Command):
|
|
|
3186
3284
|
):
|
|
3187
3285
|
self.app.stdout.write(_('Complete\n'))
|
|
3188
3286
|
else:
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
raise SystemExit
|
|
3287
|
+
msg = _('Error rebooting server: %s') % server_id
|
|
3288
|
+
raise exceptions.CommandError(msg)
|
|
3192
3289
|
|
|
3193
3290
|
|
|
3194
3291
|
class RebuildServer(command.ShowOne):
|
|
@@ -3558,9 +3655,8 @@ class RebuildServer(command.ShowOne):
|
|
|
3558
3655
|
):
|
|
3559
3656
|
self.app.stdout.write(_('Complete\n'))
|
|
3560
3657
|
else:
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
raise SystemExit
|
|
3658
|
+
msg = _('Error rebuilding server: %s') % server.id
|
|
3659
|
+
raise exceptions.CommandError(msg)
|
|
3564
3660
|
|
|
3565
3661
|
details = _prep_server_detail(
|
|
3566
3662
|
compute_client, image_client, server, refresh=False
|
|
@@ -3681,9 +3777,8 @@ host."""
|
|
|
3681
3777
|
):
|
|
3682
3778
|
self.app.stdout.write(_('Complete\n'))
|
|
3683
3779
|
else:
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
raise SystemExit
|
|
3780
|
+
msg = _('Error evacuating server: %s') % server.id
|
|
3781
|
+
raise exceptions.CommandError(msg)
|
|
3687
3782
|
|
|
3688
3783
|
details = _prep_server_detail(
|
|
3689
3784
|
compute_client, image_client, server, refresh=True
|
|
@@ -4017,6 +4112,13 @@ release the new server and restart the old one."""
|
|
|
4017
4112
|
compute_client.flavors,
|
|
4018
4113
|
parsed_args.flavor,
|
|
4019
4114
|
)
|
|
4115
|
+
if not server.image:
|
|
4116
|
+
self.log.warning(
|
|
4117
|
+
_(
|
|
4118
|
+
"The root disk size in flavor will not be applied "
|
|
4119
|
+
"while booting from a persistent volume."
|
|
4120
|
+
)
|
|
4121
|
+
)
|
|
4020
4122
|
compute_client.servers.resize(server, flavor)
|
|
4021
4123
|
if parsed_args.wait:
|
|
4022
4124
|
if utils.wait_for_status(
|
|
@@ -4027,9 +4129,8 @@ release the new server and restart the old one."""
|
|
|
4027
4129
|
):
|
|
4028
4130
|
self.app.stdout.write(_('Complete\n'))
|
|
4029
4131
|
else:
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
raise SystemExit
|
|
4132
|
+
msg = _('Error resizing server: %s') % server.id
|
|
4133
|
+
raise exceptions.CommandError(msg)
|
|
4033
4134
|
elif parsed_args.confirm:
|
|
4034
4135
|
self.log.warning(
|
|
4035
4136
|
_(
|
|
@@ -4401,6 +4502,7 @@ class ShelveServer(command.Command):
|
|
|
4401
4502
|
self.app.stdout.flush()
|
|
4402
4503
|
|
|
4403
4504
|
compute_client = self.app.client_manager.sdk_connection.compute
|
|
4505
|
+
server_ids = []
|
|
4404
4506
|
|
|
4405
4507
|
for server in parsed_args.servers:
|
|
4406
4508
|
server_obj = compute_client.find_server(
|
|
@@ -4410,6 +4512,8 @@ class ShelveServer(command.Command):
|
|
|
4410
4512
|
if server_obj.status.lower() in ('shelved', 'shelved_offloaded'):
|
|
4411
4513
|
continue
|
|
4412
4514
|
|
|
4515
|
+
server_ids.append(server_obj.id)
|
|
4516
|
+
|
|
4413
4517
|
compute_client.shelve_server(server_obj.id)
|
|
4414
4518
|
|
|
4415
4519
|
# if we don't have to wait, either because it was requested explicitly
|
|
@@ -4417,56 +4521,44 @@ class ShelveServer(command.Command):
|
|
|
4417
4521
|
if not parsed_args.wait and not parsed_args.offload:
|
|
4418
4522
|
return
|
|
4419
4523
|
|
|
4420
|
-
for
|
|
4524
|
+
for server_id in server_ids:
|
|
4421
4525
|
# We use osc-lib's wait_for_status since that allows for a callback
|
|
4422
4526
|
# TODO(stephenfin): We should wait for these in parallel using e.g.
|
|
4423
4527
|
# https://review.opendev.org/c/openstack/osc-lib/+/762503/
|
|
4424
4528
|
if not utils.wait_for_status(
|
|
4425
4529
|
compute_client.get_server,
|
|
4426
|
-
|
|
4530
|
+
server_id,
|
|
4427
4531
|
success_status=('shelved', 'shelved_offloaded'),
|
|
4428
4532
|
callback=_show_progress,
|
|
4429
4533
|
):
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
_('Error shelving server: %s\n') % server_obj.id
|
|
4433
|
-
)
|
|
4434
|
-
raise SystemExit
|
|
4534
|
+
msg = _('Error shelving server: %s') % server_id
|
|
4535
|
+
raise exceptions.CommandError(msg)
|
|
4435
4536
|
|
|
4436
4537
|
if not parsed_args.offload:
|
|
4437
4538
|
return
|
|
4438
4539
|
|
|
4439
|
-
for
|
|
4440
|
-
server_obj = compute_client.
|
|
4441
|
-
server,
|
|
4442
|
-
ignore_missing=False,
|
|
4443
|
-
)
|
|
4540
|
+
for server_id in server_ids:
|
|
4541
|
+
server_obj = compute_client.get_server(server_id)
|
|
4444
4542
|
if server_obj.status.lower() == 'shelved_offloaded':
|
|
4445
4543
|
continue
|
|
4446
4544
|
|
|
4447
|
-
compute_client.shelve_offload_server(
|
|
4545
|
+
compute_client.shelve_offload_server(server_id)
|
|
4448
4546
|
|
|
4449
4547
|
if not parsed_args.wait:
|
|
4450
4548
|
return
|
|
4451
4549
|
|
|
4452
|
-
for
|
|
4550
|
+
for server_id in server_ids:
|
|
4453
4551
|
# We use osc-lib's wait_for_status since that allows for a callback
|
|
4454
4552
|
# TODO(stephenfin): We should wait for these in parallel using e.g.
|
|
4455
4553
|
# https://review.opendev.org/c/openstack/osc-lib/+/762503/
|
|
4456
4554
|
if not utils.wait_for_status(
|
|
4457
4555
|
compute_client.get_server,
|
|
4458
|
-
|
|
4556
|
+
server_id,
|
|
4459
4557
|
success_status=('shelved_offloaded',),
|
|
4460
4558
|
callback=_show_progress,
|
|
4461
4559
|
):
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
server_obj.id,
|
|
4465
|
-
)
|
|
4466
|
-
self.app.stdout.write(
|
|
4467
|
-
_('Error offloading shelved server: %s\n') % server_obj.id
|
|
4468
|
-
)
|
|
4469
|
-
raise SystemExit
|
|
4560
|
+
msg = _('Error offloading shelved server: %s') % server_id
|
|
4561
|
+
raise exceptions.CommandError(msg)
|
|
4470
4562
|
|
|
4471
4563
|
|
|
4472
4564
|
class ShowServer(command.ShowOne):
|
|
@@ -4928,8 +5020,8 @@ class UnsetServer(command.Command):
|
|
|
4928
5020
|
if parsed_args.description:
|
|
4929
5021
|
if compute_client.api_version < api_versions.APIVersion("2.19"):
|
|
4930
5022
|
msg = _(
|
|
4931
|
-
|
|
4932
|
-
|
|
5023
|
+
'--os-compute-api-version 2.19 or greater is '
|
|
5024
|
+
'required to support the --description option'
|
|
4933
5025
|
)
|
|
4934
5026
|
raise exceptions.CommandError(msg)
|
|
4935
5027
|
compute_client.servers.update(
|
|
@@ -5058,8 +5150,5 @@ class UnshelveServer(command.Command):
|
|
|
5058
5150
|
success_status=('active', 'shutoff'),
|
|
5059
5151
|
callback=_show_progress,
|
|
5060
5152
|
):
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
_('Error unshelving server: %s\n') % server_obj.id
|
|
5064
|
-
)
|
|
5065
|
-
raise SystemExit
|
|
5153
|
+
msg = _('Error unshelving server: %s') % server_obj.id
|
|
5154
|
+
raise exceptions.CommandError(msg)
|