Skip to content

Commit 91277e7

Browse files
committed
compute: Allow users to manually specify bootable volumes
When creating a server with an attached volume, you can specify a block device with a 'boot_index' of '0' and this will become the bootable device. OSC allows users to do this by using either the '--volume' option or a combination of the '--image' and '--boot-from-volume' options, but we should also allow them to do it the "hard way" via the '--block-device' option. For example: openstack server create \ --block-device uuid=0a89ecd8-1fe2-45f0-94da-7789067911c9,boot_index=0 \ --block-device uuid=589266ef-fd88-46e9-b7b2-94503ce8f88f,boot_index=1 \ ... \ my-server Make this possible. Change-Id: Ia48449fecbc590346630807b1c7da40102d53b33 Signed-off-by: Stephen Finucane <sfinucan@redhat.com> Story: 2010376 Task: 46617
1 parent e7bc687 commit 91277e7

3 files changed

Lines changed: 58 additions & 12 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -891,9 +891,7 @@ def get_parser(self, prog_name):
891891
required=True,
892892
help=_('Create server with this flavor (name or ID)'),
893893
)
894-
disk_group = parser.add_mutually_exclusive_group(
895-
required=True,
896-
)
894+
disk_group = parser.add_mutually_exclusive_group()
897895
disk_group.add_argument(
898896
'--image',
899897
metavar='<image>',
@@ -1451,14 +1449,14 @@ def _match_image(image_api, wanted_properties):
14511449
if volume:
14521450
block_device_mapping_v2 = [{
14531451
'uuid': volume,
1454-
'boot_index': '0',
1452+
'boot_index': 0,
14551453
'source_type': 'volume',
14561454
'destination_type': 'volume'
14571455
}]
14581456
elif snapshot:
14591457
block_device_mapping_v2 = [{
14601458
'uuid': snapshot,
1461-
'boot_index': '0',
1459+
'boot_index': 0,
14621460
'source_type': 'snapshot',
14631461
'destination_type': 'volume',
14641462
'delete_on_termination': False
@@ -1467,7 +1465,7 @@ def _match_image(image_api, wanted_properties):
14671465
# Tell nova to create a root volume from the image provided.
14681466
block_device_mapping_v2 = [{
14691467
'uuid': image.id,
1470-
'boot_index': '0',
1468+
'boot_index': 0,
14711469
'source_type': 'image',
14721470
'destination_type': 'volume',
14731471
'volume_size': parsed_args.boot_from_volume
@@ -1604,6 +1602,15 @@ def _match_image(image_api, wanted_properties):
16041602

16051603
block_device_mapping_v2.append(mapping)
16061604

1605+
if not image and not any(
1606+
[bdm.get('boot_index') == 0 for bdm in block_device_mapping_v2]
1607+
):
1608+
msg = _(
1609+
'An image (--image, --image-property) or bootable volume '
1610+
'(--volume, --snapshot, --block-device) is required'
1611+
)
1612+
raise exceptions.CommandError(msg)
1613+
16071614
nics = parsed_args.nics
16081615

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

openstackclient/tests/unit/compute/v2/test_server.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2455,7 +2455,7 @@ def test_server_create_with_volume(self):
24552455
'admin_pass': None,
24562456
'block_device_mapping_v2': [{
24572457
'uuid': self.volume.id,
2458-
'boot_index': '0',
2458+
'boot_index': 0,
24592459
'source_type': 'volume',
24602460
'destination_type': 'volume',
24612461
}],
@@ -2506,7 +2506,7 @@ def test_server_create_with_snapshot(self):
25062506
'admin_pass': None,
25072507
'block_device_mapping_v2': [{
25082508
'uuid': self.snapshot.id,
2509-
'boot_index': '0',
2509+
'boot_index': 0,
25102510
'source_type': 'snapshot',
25112511
'destination_type': 'volume',
25122512
'delete_on_termination': False,
@@ -2529,20 +2529,20 @@ def test_server_create_with_snapshot(self):
25292529
self.assertEqual(self.datalist(), data)
25302530

25312531
def test_server_create_with_block_device(self):
2532-
block_device = f'uuid={self.volume.id},source_type=volume'
2532+
block_device = f'uuid={self.volume.id},source_type=volume,boot_index=0'
25332533
arglist = [
2534-
'--image', 'image1',
25352534
'--flavor', self.flavor.id,
25362535
'--block-device', block_device,
25372536
self.new_server.name,
25382537
]
25392538
verifylist = [
2540-
('image', 'image1'),
2539+
('image', None),
25412540
('flavor', self.flavor.id),
25422541
('block_devices', [
25432542
{
25442543
'uuid': self.volume.id,
25452544
'source_type': 'volume',
2545+
'boot_index': '0',
25462546
},
25472547
]),
25482548
('server_name', self.new_server.name),
@@ -2569,6 +2569,7 @@ def test_server_create_with_block_device(self):
25692569
'uuid': self.volume.id,
25702570
'source_type': 'volume',
25712571
'destination_type': 'volume',
2572+
'boot_index': 0,
25722573
},
25732574
],
25742575
'nics': [],
@@ -2578,7 +2579,7 @@ def test_server_create_with_block_device(self):
25782579
# ServerManager.create(name, image, flavor, **kwargs)
25792580
self.servers_mock.create.assert_called_with(
25802581
self.new_server.name,
2581-
self.image,
2582+
None,
25822583
self.flavor,
25832584
**kwargs
25842585
)
@@ -3506,6 +3507,37 @@ def test_server_create_image_property_with_image_list(self):
35063507
self.assertEqual(self.columns, columns)
35073508
self.assertEqual(self.datalist(), data)
35083509

3510+
def test_server_create_no_boot_device(self):
3511+
block_device = f'uuid={self.volume.id},source_type=volume,boot_index=1'
3512+
arglist = [
3513+
'--block-device', block_device,
3514+
'--flavor', self.flavor.id,
3515+
self.new_server.name,
3516+
]
3517+
verifylist = [
3518+
('image', None),
3519+
('flavor', self.flavor.id),
3520+
('block_devices', [
3521+
{
3522+
'uuid': self.volume.id,
3523+
'source_type': 'volume',
3524+
'boot_index': '1',
3525+
},
3526+
]),
3527+
('server_name', self.new_server.name),
3528+
]
3529+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
3530+
exc = self.assertRaises(
3531+
exceptions.CommandError,
3532+
self.cmd.take_action,
3533+
parsed_args,
3534+
)
3535+
self.assertIn(
3536+
'An image (--image, --image-property) or bootable volume '
3537+
'(--volume, --snapshot, --block-device) is required',
3538+
str(exc),
3539+
)
3540+
35093541
def test_server_create_with_swap(self):
35103542
arglist = [
35113543
'--image', 'image1',
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
fixes:
3+
- |
4+
The ``server create`` command will no longer insist on an ``--image``,
5+
``--image-property``, ``--volume`` or ``--snapshot`` argument when a
6+
volume is provided with a boot index of ``0`` via the ``--block-device``
7+
option.

0 commit comments

Comments
 (0)