Add new 'disk_label' capability

This patch is adding support for a new capability called 'disk_label',
in the same way users can opt-in the boot mode for the target machine
they should also be able to choose the disk label that will be used when
formating the hard drive to accommodate their use cases; e.g users
operating machines in BIOS mode will be able to overcome the 2TB
limitation for partition size that is imposed by the MBR.

Closes-Bug: #1548788
Depends-On: I307315b1b32c9bf0babd7e42d4e9bc2030884980
Change-Id: I538029fea9326de9c62fdf965469dae8915551be
This commit is contained in:
Lucas Alvares Gomes 2016-02-23 10:36:19 +00:00
parent ee841f2a9f
commit 6f36a5e487
5 changed files with 67 additions and 22 deletions

View File

@ -93,6 +93,7 @@ SUPPORTED_CAPABILITIES = {
'boot_mode': ('bios', 'uefi'),
'secure_boot': ('true', 'false'),
'trusted_boot': ('true', 'false'),
'disk_label': ('msdos', 'gpt'),
}
@ -303,7 +304,7 @@ def deploy_partition_image(
address, port, iqn, lun, image_path,
root_mb, swap_mb, ephemeral_mb, ephemeral_format, node_uuid,
preserve_ephemeral=False, configdrive=None,
boot_option="netboot", boot_mode="bios"):
boot_option="netboot", boot_mode="bios", disk_label=None):
"""All-in-one function to deploy a partition image to a node.
:param address: The iSCSI IP address.
@ -325,6 +326,9 @@ def deploy_partition_image(
or configdrive HTTP URL.
:param boot_option: Can be "local" or "netboot". "netboot" by default.
:param boot_mode: Can be "bios" or "uefi". "bios" by default.
:param disk_label: The disk label to be used when creating the
partition table. Valid values are: "msdos", "gpt" or None; If None
Ironic will figure it out according to the boot_mode parameter.
:raises: InstanceDeployFailure if image virtual size is bigger than root
partition size.
:returns: a dictionary containing the following keys:
@ -346,7 +350,7 @@ def deploy_partition_image(
dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format, image_path,
node_uuid, preserve_ephemeral=preserve_ephemeral,
configdrive=configdrive, boot_option=boot_option,
boot_mode=boot_mode)
boot_mode=boot_mode, disk_label=disk_label)
return uuid_dict_returned
@ -742,6 +746,18 @@ def is_trusted_boot_requested(node):
return trusted_boot == 'true'
def get_disk_label(node):
"""Return the disk label requested for deploy, if any.
:param node: a single Node.
:raises: InvalidParameterValue if the capabilities string is not a
dictionary or is malformed.
:returns: the disk label or None if no disk label was specified.
"""
capabilities = parse_instance_info_capabilities(node)
return capabilities.get('disk_label')
def get_boot_mode_for_deploy(node):
"""Returns the boot mode that would be used for deploy.

View File

@ -319,6 +319,11 @@ def get_deploy_info(node, **kwargs):
'boot_option': deploy_utils.get_boot_option(node),
'boot_mode': _get_boot_mode(node)})
# Append disk label if specified
disk_label = deploy_utils.get_disk_label(node)
if disk_label is not None:
params['disk_label'] = disk_label
missing = [key for key in params if params[key] is None]
if missing:
raise exception.MissingParameterValue(

View File

@ -337,7 +337,7 @@ class PhysicalWorkTestCase(tests_base.TestCase):
return parent_mock
def _test_deploy_partition_image(self, boot_option=None,
boot_mode=None):
boot_mode=None, disk_label=None):
"""Check loosely all functions are called with right args."""
address = '127.0.0.1'
port = 3306
@ -375,7 +375,8 @@ class PhysicalWorkTestCase(tests_base.TestCase):
make_partitions_expected_args = [dev, root_mb, swap_mb, ephemeral_mb,
configdrive_mb, node_uuid]
make_partitions_expected_kwargs = {'commit': True, 'disk_label': None}
make_partitions_expected_kwargs = {'commit': True,
'disk_label': disk_label}
deploy_kwargs = {}
if boot_option:
@ -390,6 +391,9 @@ class PhysicalWorkTestCase(tests_base.TestCase):
else:
make_partitions_expected_kwargs['boot_mode'] = 'bios'
if disk_label:
deploy_kwargs['disk_label'] = disk_label
# If no boot_option, then it should default to netboot.
utils_calls_expected = [mock.call.get_dev(address, port, iqn, lun),
mock.call.discovery(address, port),
@ -447,6 +451,9 @@ class PhysicalWorkTestCase(tests_base.TestCase):
self._test_deploy_partition_image(boot_option="netboot",
boot_mode="uefi")
def test_deploy_partition_image_disk_label(self):
self._test_deploy_partition_image(disk_label='gpt')
@mock.patch.object(disk_utils, 'get_image_mb', return_value=129,
autospec=True)
def test_deploy_partition_image_image_exceeds_root_partition(self,
@ -1039,7 +1046,8 @@ class PhysicalWorkTestCase(tests_base.TestCase):
node_uuid, configdrive=None,
preserve_ephemeral=False,
boot_option="netboot",
boot_mode="bios")]
boot_mode="bios",
disk_label=None)]
self.assertRaises(TestException, utils.deploy_partition_image,
address, port, iqn, lun, image_path,
@ -1461,6 +1469,12 @@ class ParseInstanceInfoCapabilitiesTestCase(tests_base.TestCase):
self.assertEqual(('true', 'false'),
utils.SUPPORTED_CAPABILITIES['trusted_boot'])
def test_get_disk_label(self):
inst_info = {'capabilities': {'disk_label': 'gpt', 'foo': 'bar'}}
self.node.instance_info = inst_info
result = utils.get_disk_label(self.node)
self.assertEqual('gpt', result)
class TrySetBootDeviceTestCase(db_base.DbTestCase):

View File

@ -700,38 +700,43 @@ class IscsiDeployMethodsTestCase(db_base.DbTestCase):
mock_image_cache.return_value.clean_up.assert_called_once_with()
self.assertEqual(uuid_dict_returned, retval)
def test_get_deploy_info_boot_option_default(self):
def _test_get_deploy_info(self, extra_instance_info=None):
if extra_instance_info is None:
extra_instance_info = {}
instance_info = self.node.instance_info
instance_info['deploy_key'] = 'key'
instance_info.update(extra_instance_info)
self.node.instance_info = instance_info
kwargs = {'address': '1.1.1.1', 'iqn': 'target-iqn', 'key': 'key'}
ret_val = iscsi_deploy.get_deploy_info(self.node, **kwargs)
self.assertEqual('1.1.1.1', ret_val['address'])
self.assertEqual('target-iqn', ret_val['iqn'])
return ret_val
def test_get_deploy_info_boot_option_default(self):
ret_val = self._test_get_deploy_info()
self.assertEqual('netboot', ret_val['boot_option'])
def test_get_deploy_info_netboot_specified(self):
instance_info = self.node.instance_info
instance_info['deploy_key'] = 'key'
instance_info['capabilities'] = {'boot_option': 'netboot'}
self.node.instance_info = instance_info
kwargs = {'address': '1.1.1.1', 'iqn': 'target-iqn', 'key': 'key'}
ret_val = iscsi_deploy.get_deploy_info(self.node, **kwargs)
self.assertEqual('1.1.1.1', ret_val['address'])
self.assertEqual('target-iqn', ret_val['iqn'])
capabilities = {'capabilities': {'boot_option': 'netboot'}}
ret_val = self._test_get_deploy_info(extra_instance_info=capabilities)
self.assertEqual('netboot', ret_val['boot_option'])
def test_get_deploy_info_localboot(self):
instance_info = self.node.instance_info
instance_info['deploy_key'] = 'key'
instance_info['capabilities'] = {'boot_option': 'local'}
self.node.instance_info = instance_info
kwargs = {'address': '1.1.1.1', 'iqn': 'target-iqn', 'key': 'key'}
ret_val = iscsi_deploy.get_deploy_info(self.node, **kwargs)
self.assertEqual('1.1.1.1', ret_val['address'])
self.assertEqual('target-iqn', ret_val['iqn'])
capabilities = {'capabilities': {'boot_option': 'local'}}
ret_val = self._test_get_deploy_info(extra_instance_info=capabilities)
self.assertEqual('local', ret_val['boot_option'])
def test_get_deploy_info_disk_label(self):
capabilities = {'capabilities': {'disk_label': 'msdos'}}
ret_val = self._test_get_deploy_info(extra_instance_info=capabilities)
self.assertEqual('msdos', ret_val['disk_label'])
def test_get_deploy_info_not_specified(self):
ret_val = self._test_get_deploy_info()
self.assertNotIn('disk_label', ret_val)
@mock.patch.object(iscsi_deploy, 'continue_deploy', autospec=True)
@mock.patch.object(iscsi_deploy, 'build_deploy_ramdisk_options',
autospec=True)

View File

@ -0,0 +1,5 @@
---
features:
- Add support for a new capability called 'disk_label' to allow
operators to choose the disk label that will be used when Ironic is
partitioning the disk.