Skip to content

Commit ace4bfb

Browse files
committed
compute: Add 'server create --block-device' option
One of the last big gaps with novaclient. As noted in the release note, the current '--block-device-mapping' format is based on the old BDM v1 format, even though it actually results in BDM v2-style requests to the server. It's time to replace that. Change-Id: If4eba38ccfb208ee186b90a0eec95e5fe6cf8415 Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
1 parent f2deabb commit ace4bfb

3 files changed

Lines changed: 383 additions & 1 deletion

File tree

openstackclient/compute/v2/server.py

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,7 @@ def get_parser(self, prog_name):
801801
'options.'
802802
)
803803
)
804+
# TODO(stephenfin): Remove this in the v7.0
804805
parser.add_argument(
805806
'--block-device-mapping',
806807
metavar='<dev-name=mapping>',
@@ -809,7 +810,7 @@ def get_parser(self, prog_name):
809810
# NOTE(RuiChen): Add '\n' to the end of line to improve formatting;
810811
# see cliff's _SmartHelpFormatter for more details.
811812
help=_(
812-
'Create a block device on the server.\n'
813+
'**Deprecated** Create a block device on the server.\n'
813814
'Block device mapping in the format\n'
814815
'<dev-name>=<id>:<type>:<size(GB)>:<delete-on-terminate>\n'
815816
'<dev-name>: block device name, like: vdb, xvdc '
@@ -822,6 +823,49 @@ def get_parser(self, prog_name):
822823
'(optional)\n'
823824
'<delete-on-terminate>: true or false; default: false '
824825
'(optional)\n'
826+
'Replaced by --block-device'
827+
),
828+
)
829+
parser.add_argument(
830+
'--block-device',
831+
metavar='',
832+
action=parseractions.MultiKeyValueAction,
833+
dest='block_devices',
834+
default=[],
835+
required_keys=[
836+
'boot_index',
837+
],
838+
optional_keys=[
839+
'uuid', 'source_type', 'destination_type',
840+
'disk_bus', 'device_type', 'device_name', 'guest_format',
841+
'volume_size', 'volume_type', 'delete_on_termination', 'tag',
842+
],
843+
help=_(
844+
'Create a block device on the server.\n'
845+
'Block device in the format:\n'
846+
'uuid=<uuid>: UUID of the volume, snapshot or ID '
847+
'(required if using source image, snapshot or volume),\n'
848+
'source_type=<source_type>: source type '
849+
'(one of: image, snapshot, volume, blank),\n'
850+
'destination_typ=<destination_type>: destination type '
851+
'(one of: volume, local) (optional),\n'
852+
'disk_bus=<disk_bus>: device bus '
853+
'(one of: uml, lxc, virtio, ...) (optional),\n'
854+
'device_type=<device_type>: device type '
855+
'(one of: disk, cdrom, etc. (optional),\n'
856+
'device_name=<device_name>: name of the device (optional),\n'
857+
'volume_size=<volume_size>: size of the block device in MiB '
858+
'(for swap) or GiB (for everything else) (optional),\n'
859+
'guest_format=<guest_format>: format of device (optional),\n'
860+
'boot_index=<boot_index>: index of disk used to order boot '
861+
'disk '
862+
'(required for volume-backed instances),\n'
863+
'delete_on_termination=<true|false>: whether to delete the '
864+
'volume upon deletion of server (optional),\n'
865+
'tag=<tag>: device metadata tag (optional),\n'
866+
'volume_type=<volume_type>: type of volume to create (name or '
867+
'ID) when source if blank, image or snapshot and dest is '
868+
'volume (optional)'
825869
),
826870
)
827871
parser.add_argument(
@@ -1250,6 +1294,8 @@ def _match_image(image_api, wanted_properties):
12501294

12511295
# Handle block device by device name order, like: vdb -> vdc -> vdd
12521296
for mapping in parsed_args.block_device_mapping:
1297+
# The 'uuid' field isn't necessarily a UUID yet; let's validate it
1298+
# just in case
12531299
if mapping['source_type'] == 'volume':
12541300
volume_id = utils.find_resource(
12551301
volume_client.volumes, mapping['uuid'],
@@ -1279,6 +1325,77 @@ def _match_image(image_api, wanted_properties):
12791325

12801326
block_device_mapping_v2.append(mapping)
12811327

1328+
for mapping in parsed_args.block_devices:
1329+
try:
1330+
mapping['boot_index'] = int(mapping['boot_index'])
1331+
except ValueError:
1332+
msg = _(
1333+
'The boot_index key of --block-device should be an '
1334+
'integer'
1335+
)
1336+
raise exceptions.CommandError(msg)
1337+
1338+
if 'tag' in mapping and (
1339+
compute_client.api_version < api_versions.APIVersion('2.42')
1340+
):
1341+
msg = _(
1342+
'--os-compute-api-version 2.42 or greater is '
1343+
'required to support the tag key of --block-device'
1344+
)
1345+
raise exceptions.CommandError(msg)
1346+
1347+
if 'volume_type' in mapping and (
1348+
compute_client.api_version < api_versions.APIVersion('2.67')
1349+
):
1350+
msg = _(
1351+
'--os-compute-api-version 2.67 or greater is '
1352+
'required to support the volume_type key of --block-device'
1353+
)
1354+
raise exceptions.CommandError(msg)
1355+
1356+
if 'source_type' in mapping:
1357+
if mapping['source_type'] not in (
1358+
'volume', 'image', 'snapshot', 'blank',
1359+
):
1360+
msg = _(
1361+
'The source_type key of --block-device should be one '
1362+
'of: volume, image, snapshot, blank'
1363+
)
1364+
raise exceptions.CommandError(msg)
1365+
else:
1366+
mapping['source_type'] = 'blank'
1367+
1368+
if 'destination_type' in mapping:
1369+
if mapping['destination_type'] not in ('local', 'volume'):
1370+
msg = _(
1371+
'The destination_type key of --block-device should be '
1372+
'one of: local, volume'
1373+
)
1374+
raise exceptions.CommandError(msg)
1375+
else:
1376+
if mapping['source_type'] in ('image', 'blank'):
1377+
mapping['destination_type'] = 'local'
1378+
else: # volume, snapshot
1379+
mapping['destination_type'] = 'volume'
1380+
1381+
if 'delete_on_termination' in mapping:
1382+
try:
1383+
value = strutils.bool_from_string(
1384+
mapping['delete_on_termination'], strict=True)
1385+
except ValueError:
1386+
msg = _(
1387+
'The delete_on_termination key of --block-device '
1388+
'should be a boolean-like value'
1389+
)
1390+
raise exceptions.CommandError(msg)
1391+
1392+
mapping['delete_on_termination'] = value
1393+
else:
1394+
if mapping['destination_type'] == 'local':
1395+
mapping['delete_on_termination'] = True
1396+
1397+
block_device_mapping_v2.append(mapping)
1398+
12821399
nics = parsed_args.nics
12831400

12841401
if 'auto' in nics or 'none' in nics:

0 commit comments

Comments
 (0)