Add support for BIOS local boot for GPT label
Ironic doesn't support local booting of images in BIOS boot mode when the disk_label is GPT. The current changes creates BIOS Boot partition when the disk_label is chosen as gpt. The partition size is a configurable parameter. Change-Id: Iade60da0316b8f1c0bf8ce4c79931c1105d19cec Closes-bug: #1563291
This commit is contained in:
parent
9eaad70080
commit
c6d4f0f463
ironic_lib
releasenotes/notes
@ -80,7 +80,7 @@ class DiskPartitioner(object):
|
||||
use_standard_locale=True, run_as_root=True)
|
||||
|
||||
def add_partition(self, size, part_type='primary', fs_type='',
|
||||
bootable=False):
|
||||
boot_flag=None):
|
||||
"""Add a partition.
|
||||
|
||||
:param size: The size of the partition in MiB.
|
||||
@ -90,15 +90,16 @@ class DiskPartitioner(object):
|
||||
fat16, HFS, linux-swap, NTFS, reiserfs, ufs.
|
||||
If blank (''), it will create a Linux native
|
||||
partition (83).
|
||||
:param bootable: Boolean value; whether the partition is bootable
|
||||
or not.
|
||||
:param boot_flag: Boot flag that needs to be configured on the
|
||||
partition. Ignored if None. It can take values
|
||||
'bios_grub', 'boot'.
|
||||
:returns: The partition number.
|
||||
|
||||
"""
|
||||
self._partitions.append({'size': size,
|
||||
'type': part_type,
|
||||
'fs_type': fs_type,
|
||||
'bootable': bootable})
|
||||
'boot_flag': boot_flag})
|
||||
return len(self._partitions)
|
||||
|
||||
def get_partitions(self):
|
||||
@ -145,8 +146,8 @@ class DiskPartitioner(object):
|
||||
end = start + part['size']
|
||||
cmd_args.extend(['mkpart', part['type'], part['fs_type'],
|
||||
str(start), str(end)])
|
||||
if part['bootable']:
|
||||
cmd_args.extend(['set', str(num), 'boot', 'on'])
|
||||
if part['boot_flag']:
|
||||
cmd_args.extend(['set', str(num), part['boot_flag'], 'on'])
|
||||
start = end
|
||||
|
||||
self._exec(*cmd_args)
|
||||
|
@ -47,6 +47,10 @@ opts = [
|
||||
help='Size of EFI system partition in MiB when configuring '
|
||||
'UEFI systems for local boot.',
|
||||
deprecated_group='deploy'),
|
||||
cfg.IntOpt('bios_boot_partition_size',
|
||||
default=1,
|
||||
help='Size of BIOS Boot partition in MiB when configuring '
|
||||
'GPT partitioned systems for local boot in BIOS.'),
|
||||
cfg.StrOpt('dd_block_size',
|
||||
default='1M',
|
||||
help='Block size to use when writing to the nodes disk.',
|
||||
@ -180,9 +184,14 @@ def make_partitions(dev, root_mb, swap_mb, ephemeral_mb,
|
||||
if boot_mode == "uefi" and boot_option == "local":
|
||||
part_num = dp.add_partition(CONF.disk_utils.efi_system_partition_size,
|
||||
fs_type='fat32',
|
||||
bootable=True)
|
||||
boot_flag='boot')
|
||||
part_dict['efi system partition'] = part_template % part_num
|
||||
|
||||
if boot_mode == "bios" and boot_option == "local" and disk_label == "gpt":
|
||||
part_num = dp.add_partition(CONF.disk_utils.bios_boot_partition_size,
|
||||
boot_flag='bios_grub')
|
||||
part_dict['BIOS Boot partition'] = part_template % part_num
|
||||
|
||||
if ephemeral_mb:
|
||||
LOG.debug("Add ephemeral partition (%(size)d MB) to device: %(dev)s "
|
||||
"for node %(node)s",
|
||||
@ -208,8 +217,14 @@ def make_partitions(dev, root_mb, swap_mb, ephemeral_mb,
|
||||
LOG.debug("Add root partition (%(size)d MB) to device: %(dev)s "
|
||||
"for node %(node)s",
|
||||
{'dev': dev, 'size': root_mb, 'node': node_uuid})
|
||||
part_num = dp.add_partition(root_mb, bootable=(boot_option == "local" and
|
||||
boot_mode == "bios"))
|
||||
|
||||
boot_val = None
|
||||
if (boot_mode == "bios" and boot_option == "local" and
|
||||
disk_label == "msdos"):
|
||||
boot_val = 'boot'
|
||||
|
||||
part_num = dp.add_partition(root_mb, boot_flag=boot_val)
|
||||
|
||||
part_dict['root'] = part_template % part_num
|
||||
|
||||
if commit:
|
||||
|
@ -30,21 +30,26 @@ class DiskPartitionerTestCase(test_base.BaseTestCase):
|
||||
dp = disk_partitioner.DiskPartitioner('/dev/fake')
|
||||
dp.add_partition(1024)
|
||||
dp.add_partition(512, fs_type='linux-swap')
|
||||
dp.add_partition(2048, bootable=True)
|
||||
expected = [(1, {'bootable': False,
|
||||
dp.add_partition(2048, boot_flag='boot')
|
||||
dp.add_partition(2048, boot_flag='bios_grub')
|
||||
expected = [(1, {'boot_flag': None,
|
||||
'fs_type': '',
|
||||
'type': 'primary',
|
||||
'size': 1024}),
|
||||
(2, {'bootable': False,
|
||||
(2, {'boot_flag': None,
|
||||
'fs_type': 'linux-swap',
|
||||
'type': 'primary',
|
||||
'size': 512}),
|
||||
(3, {'bootable': True,
|
||||
(3, {'boot_flag': 'boot',
|
||||
'fs_type': '',
|
||||
'type': 'primary',
|
||||
'size': 2048}),
|
||||
(4, {'boot_flag': 'bios_grub',
|
||||
'fs_type': '',
|
||||
'type': 'primary',
|
||||
'size': 2048})]
|
||||
partitions = [(n, p) for n, p in dp.get_partitions()]
|
||||
self.assertThat(partitions, HasLength(3))
|
||||
self.assertThat(partitions, HasLength(4))
|
||||
self.assertEqual(expected, partitions)
|
||||
|
||||
@mock.patch.object(disk_partitioner.DiskPartitioner, '_exec',
|
||||
@ -52,11 +57,15 @@ class DiskPartitionerTestCase(test_base.BaseTestCase):
|
||||
@mock.patch.object(utils, 'execute', autospec=True)
|
||||
def test_commit(self, mock_utils_exc, mock_disk_partitioner_exec):
|
||||
dp = disk_partitioner.DiskPartitioner('/dev/fake')
|
||||
fake_parts = [(1, {'bootable': False,
|
||||
fake_parts = [(1, {'boot_flag': None,
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1}),
|
||||
(2, {'bootable': True,
|
||||
(2, {'boot_flag': 'boot',
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1}),
|
||||
(3, {'boot_flag': 'bios_grub',
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1})]
|
||||
@ -69,7 +78,9 @@ class DiskPartitionerTestCase(test_base.BaseTestCase):
|
||||
mock.ANY, 'mklabel', 'msdos',
|
||||
'mkpart', 'fake-type', 'fake-fs-type', '1', '2',
|
||||
'mkpart', 'fake-type', 'fake-fs-type', '2', '3',
|
||||
'set', '2', 'boot', 'on')
|
||||
'set', '2', 'boot', 'on',
|
||||
'mkpart', 'fake-type', 'fake-fs-type', '3', '4',
|
||||
'set', '3', 'bios_grub', 'on')
|
||||
mock_utils_exc.assert_called_once_with(
|
||||
'fuser', '/dev/fake', run_as_root=True, check_exit_code=[0, 1])
|
||||
|
||||
@ -80,11 +91,11 @@ class DiskPartitionerTestCase(test_base.BaseTestCase):
|
||||
def test_commit_with_device_is_busy_once(self, mock_utils_exc,
|
||||
mock_disk_partitioner_exec):
|
||||
dp = disk_partitioner.DiskPartitioner('/dev/fake')
|
||||
fake_parts = [(1, {'bootable': False,
|
||||
fake_parts = [(1, {'boot_flag': None,
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1}),
|
||||
(2, {'bootable': True,
|
||||
(2, {'boot_flag': 'boot',
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1})]
|
||||
@ -111,11 +122,11 @@ class DiskPartitionerTestCase(test_base.BaseTestCase):
|
||||
def test_commit_with_device_is_always_busy(self, mock_utils_exc,
|
||||
mock_disk_partitioner_exec):
|
||||
dp = disk_partitioner.DiskPartitioner('/dev/fake')
|
||||
fake_parts = [(1, {'bootable': False,
|
||||
fake_parts = [(1, {'boot_flag': None,
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1}),
|
||||
(2, {'bootable': True,
|
||||
(2, {'boot_flag': 'boot',
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1})]
|
||||
@ -142,11 +153,11 @@ class DiskPartitionerTestCase(test_base.BaseTestCase):
|
||||
def test_commit_with_device_disconnected(self, mock_utils_exc,
|
||||
mock_disk_partitioner_exec):
|
||||
dp = disk_partitioner.DiskPartitioner('/dev/fake')
|
||||
fake_parts = [(1, {'bootable': False,
|
||||
fake_parts = [(1, {'boot_flag': None,
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1}),
|
||||
(2, {'bootable': True,
|
||||
(2, {'boot_flag': 'boot',
|
||||
'fs_type': 'fake-fs-type',
|
||||
'type': 'fake-type',
|
||||
'size': 1})]
|
||||
|
@ -240,6 +240,8 @@ class MakePartitionsTestCase(test_base.BaseTestCase):
|
||||
self.ephemeral_mb = 0
|
||||
self.configdrive_mb = 0
|
||||
self.node_uuid = "12345678-1234-1234-1234-1234567890abcxyz"
|
||||
self.efi_size = CONF.disk_utils.efi_system_partition_size
|
||||
self.bios_size = CONF.disk_utils.bios_boot_partition_size
|
||||
|
||||
def _get_parted_cmd(self, dev, label=None):
|
||||
if label is None:
|
||||
@ -248,17 +250,44 @@ class MakePartitionsTestCase(test_base.BaseTestCase):
|
||||
return ['parted', '-a', 'optimal', '-s', dev,
|
||||
'--', 'unit', 'MiB', 'mklabel', label]
|
||||
|
||||
def _test_make_partitions(self, mock_exc, boot_option, disk_label=None):
|
||||
def _test_make_partitions(self, mock_exc, boot_option, boot_mode='bios',
|
||||
disk_label=None):
|
||||
mock_exc.return_value = (None, None)
|
||||
disk_utils.make_partitions(self.dev, self.root_mb, self.swap_mb,
|
||||
self.ephemeral_mb, self.configdrive_mb,
|
||||
self.node_uuid, boot_option=boot_option,
|
||||
disk_label=disk_label)
|
||||
boot_mode=boot_mode, disk_label=disk_label)
|
||||
|
||||
expected_mkpart = ['mkpart', 'primary', 'linux-swap', '1', '513',
|
||||
'mkpart', 'primary', '', '513', '1537']
|
||||
if boot_option == "local":
|
||||
expected_mkpart.extend(['set', '2', 'boot', 'on'])
|
||||
_s = lambda x, sz: x + sz
|
||||
|
||||
if boot_option == "local" and boot_mode == "uefi":
|
||||
add_efi_sz = lambda x: str(_s(x, self.efi_size))
|
||||
expected_mkpart = ['mkpart', 'primary', 'fat32', '1',
|
||||
add_efi_sz(1),
|
||||
'set', '1', 'boot', 'on',
|
||||
'mkpart', 'primary', 'linux-swap',
|
||||
add_efi_sz(1), add_efi_sz(513), 'mkpart',
|
||||
'primary', '', add_efi_sz(513),
|
||||
add_efi_sz(1537)]
|
||||
else:
|
||||
if boot_option == "local":
|
||||
if disk_label == "gpt":
|
||||
add_bios_sz = lambda x: str(_s(x, self.bios_size))
|
||||
expected_mkpart = ['mkpart', 'primary', '', '1',
|
||||
add_bios_sz(1),
|
||||
'set', '1', 'bios_grub', 'on',
|
||||
'mkpart', 'primary', 'linux-swap',
|
||||
add_bios_sz(1), add_bios_sz(513),
|
||||
'mkpart', 'primary', '',
|
||||
add_bios_sz(513), add_bios_sz(1537)]
|
||||
else:
|
||||
expected_mkpart = ['mkpart', 'primary', 'linux-swap', '1',
|
||||
'513', 'mkpart', 'primary', '', '513',
|
||||
'1537', 'set', '2', 'boot', 'on']
|
||||
else:
|
||||
expected_mkpart = ['mkpart', 'primary', 'linux-swap', '1',
|
||||
'513', 'mkpart', 'primary', '', '513',
|
||||
'1537']
|
||||
self.dev = 'fake-dev'
|
||||
parted_cmd = (self._get_parted_cmd(self.dev, disk_label) +
|
||||
expected_mkpart)
|
||||
@ -275,6 +304,14 @@ class MakePartitionsTestCase(test_base.BaseTestCase):
|
||||
def test_make_partitions_local_boot(self, mock_exc):
|
||||
self._test_make_partitions(mock_exc, boot_option="local")
|
||||
|
||||
def test_make_partitions_local_boot_uefi(self, mock_exc):
|
||||
self._test_make_partitions(mock_exc, boot_option="local",
|
||||
boot_mode="uefi", disk_label="gpt")
|
||||
|
||||
def test_make_partitions_local_boot_gpt_bios(self, mock_exc):
|
||||
self._test_make_partitions(mock_exc, boot_option="local",
|
||||
disk_label="gpt")
|
||||
|
||||
def test_make_partitions_disk_label_gpt(self, mock_exc):
|
||||
self._test_make_partitions(mock_exc, boot_option="netboot",
|
||||
disk_label="gpt")
|
||||
|
4
releasenotes/notes/gpt-bios-425e703770fae46d.yaml
Normal file
4
releasenotes/notes/gpt-bios-425e703770fae46d.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
fixes:
|
||||
- Fixes a problem where nodes being configured in BIOS mode to boot
|
||||
from the local disk with a GPT partition table would fail at boot time.
|
Loading…
x
Reference in New Issue
Block a user