Support pre-built deploy/rescue ISO in Redfish
This change adds support to pre-built ISO images via the new driver_info parameters redfish_deploy_iso and redfish_rescue_iso, similarly to the iLO hardware type. Also removes overly eager mocking in image unit tests. Change-Id: I1366791a6c6eb34f3a43337c4199592783765912
This commit is contained in:
parent
8762fb1eb3
commit
d55929fc7d
@ -198,6 +198,27 @@ property can be used to pass user-specified kernel command line parameters.
|
|||||||
For ramdisk kernel, ``[instance_info]/kernel_append_params`` property serves
|
For ramdisk kernel, ``[instance_info]/kernel_append_params`` property serves
|
||||||
the same purpose.
|
the same purpose.
|
||||||
|
|
||||||
|
Pre-built ISO images
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
By default an ISO images is built per node using the deploy kernel and
|
||||||
|
initramfs provided in the configuration or the node's ``driver_info``. Starting
|
||||||
|
with the Wallaby release it's possible to provide a pre-built ISO image:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
baremetal node set node-0 \
|
||||||
|
--driver_info redfish_deploy_iso=http://url/of/deploy.iso \
|
||||||
|
--driver_info redfish_rescue_iso=http://url/of/rescue.iso
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
OpenStack Image service (glance) image IDs and ``file://`` links are also
|
||||||
|
accepted.
|
||||||
|
|
||||||
|
No customization is currently done to the image, so e.g.
|
||||||
|
:doc:`/admin/dhcp-less` won't work. `Configuring an ESP image`_ is also
|
||||||
|
unnecessary.
|
||||||
|
|
||||||
Configuring an ESP image
|
Configuring an ESP image
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -436,6 +436,14 @@ def _prepare_iso_image(task, kernel_href, ramdisk_href,
|
|||||||
|
|
||||||
boot_mode = boot_mode_utils.get_boot_mode(task.node)
|
boot_mode = boot_mode_utils.get_boot_mode(task.node)
|
||||||
|
|
||||||
|
if base_iso:
|
||||||
|
# TODO(dtantsur): fix this limitation eventually (see
|
||||||
|
# images.create_boot_iso).
|
||||||
|
LOG.debug('Using pre-built %(boot_mode)s ISO %(iso)s for node '
|
||||||
|
'%(node)s, custom configuration will not be available',
|
||||||
|
{'boot_mode': boot_mode, 'node': task.node.uuid,
|
||||||
|
'iso': base_iso})
|
||||||
|
else:
|
||||||
LOG.debug("Trying to create %(boot_mode)s ISO image for node %(node)s "
|
LOG.debug("Trying to create %(boot_mode)s ISO image for node %(node)s "
|
||||||
"with kernel %(kernel_href)s, ramdisk %(ramdisk_href)s, "
|
"with kernel %(kernel_href)s, ramdisk %(ramdisk_href)s, "
|
||||||
"bootloader %(bootloader_href)s and kernel params %(params)s"
|
"bootloader %(bootloader_href)s and kernel params %(params)s"
|
||||||
@ -479,6 +487,7 @@ def _find_param(param_str, param_dict):
|
|||||||
for param_key in param_dict:
|
for param_key in param_dict:
|
||||||
if param_str in param_key:
|
if param_str in param_key:
|
||||||
val = param_dict.get(param_key)
|
val = param_dict.get(param_key)
|
||||||
|
if val is not None:
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
@ -516,10 +525,12 @@ def prepare_deploy_iso(task, params, mode, d_info):
|
|||||||
|
|
||||||
kernel_str = '%s_kernel' % mode
|
kernel_str = '%s_kernel' % mode
|
||||||
ramdisk_str = '%s_ramdisk' % mode
|
ramdisk_str = '%s_ramdisk' % mode
|
||||||
|
iso_str = '%s_iso' % mode
|
||||||
bootloader_str = 'bootloader'
|
bootloader_str = 'bootloader'
|
||||||
|
|
||||||
kernel_href = _find_param(kernel_str, d_info)
|
kernel_href = _find_param(kernel_str, d_info)
|
||||||
ramdisk_href = _find_param(ramdisk_str, d_info)
|
ramdisk_href = _find_param(ramdisk_str, d_info)
|
||||||
|
iso_href = _find_param(iso_str, d_info)
|
||||||
bootloader_href = _find_param(bootloader_str, d_info)
|
bootloader_href = _find_param(bootloader_str, d_info)
|
||||||
|
|
||||||
# TODO(TheJulia): At some point we should support something like
|
# TODO(TheJulia): At some point we should support something like
|
||||||
@ -527,7 +538,7 @@ def prepare_deploy_iso(task, params, mode, d_info):
|
|||||||
# injection.
|
# injection.
|
||||||
prepare_iso_image = functools.partial(
|
prepare_iso_image = functools.partial(
|
||||||
_prepare_iso_image, task, kernel_href, ramdisk_href,
|
_prepare_iso_image, task, kernel_href, ramdisk_href,
|
||||||
bootloader_href=bootloader_href, params=params)
|
bootloader_href=bootloader_href, params=params, base_iso=iso_href)
|
||||||
|
|
||||||
inject_files = {}
|
inject_files = {}
|
||||||
if CONF.agent.api_ca_file:
|
if CONF.agent.api_ca_file:
|
||||||
|
@ -100,6 +100,11 @@ def _parse_driver_info(node):
|
|||||||
d_info = node.driver_info
|
d_info = node.driver_info
|
||||||
|
|
||||||
mode = deploy_utils.rescue_or_deploy_mode(node)
|
mode = deploy_utils.rescue_or_deploy_mode(node)
|
||||||
|
iso_param = 'redfish_%s_iso' % mode
|
||||||
|
iso_ref = d_info.get(iso_param)
|
||||||
|
if iso_ref is not None:
|
||||||
|
deploy_info = {iso_param: iso_ref}
|
||||||
|
else:
|
||||||
params_to_check = KERNEL_RAMDISK_LABELS[mode]
|
params_to_check = KERNEL_RAMDISK_LABELS[mode]
|
||||||
|
|
||||||
deploy_info = {option: d_info.get(option)
|
deploy_info = {option: d_info.get(option)
|
||||||
|
@ -72,6 +72,17 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
|
|||||||
self.assertIn('ramdisk', actual_driver_info['deploy_ramdisk'])
|
self.assertIn('ramdisk', actual_driver_info['deploy_ramdisk'])
|
||||||
self.assertIn('bootloader', actual_driver_info['bootloader'])
|
self.assertIn('bootloader', actual_driver_info['bootloader'])
|
||||||
|
|
||||||
|
def test_parse_driver_info_iso(self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.node.driver_info.update(
|
||||||
|
{'redfish_deploy_iso': 'http://boot.iso'})
|
||||||
|
|
||||||
|
actual_driver_info = redfish_boot._parse_driver_info(task.node)
|
||||||
|
|
||||||
|
self.assertEqual('http://boot.iso',
|
||||||
|
actual_driver_info['redfish_deploy_iso'])
|
||||||
|
|
||||||
def test_parse_driver_info_rescue(self):
|
def test_parse_driver_info_rescue(self):
|
||||||
with task_manager.acquire(self.context, self.node.uuid,
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
shared=True) as task:
|
shared=True) as task:
|
||||||
|
@ -529,10 +529,8 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
|||||||
actual = image_utils._find_param(param_str, param_dict)
|
actual = image_utils._find_param(param_str, param_dict)
|
||||||
self.assertEqual(actual, expected)
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
@mock.patch.object(image_utils, '_find_param', autospec=True)
|
|
||||||
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
||||||
def test_prepare_deploy_iso(self, mock__prepare_iso_image,
|
def test_prepare_deploy_iso(self, mock__prepare_iso_image):
|
||||||
find_mock):
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid,
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
shared=True) as task:
|
shared=True) as task:
|
||||||
|
|
||||||
@ -543,29 +541,34 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
|||||||
}
|
}
|
||||||
task.node.driver_info.update(d_info)
|
task.node.driver_info.update(d_info)
|
||||||
|
|
||||||
find_call_list = [
|
|
||||||
mock.call('deploy_kernel', d_info),
|
|
||||||
mock.call('deploy_ramdisk', d_info),
|
|
||||||
mock.call('bootloader', d_info)
|
|
||||||
]
|
|
||||||
find_mock.side_effect = [
|
|
||||||
'kernel', 'ramdisk', 'bootloader'
|
|
||||||
]
|
|
||||||
|
|
||||||
task.node.instance_info.update(deploy_boot_mode='uefi')
|
task.node.instance_info.update(deploy_boot_mode='uefi')
|
||||||
|
|
||||||
image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info)
|
image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info)
|
||||||
|
|
||||||
mock__prepare_iso_image.assert_called_once_with(
|
mock__prepare_iso_image.assert_called_once_with(
|
||||||
task, 'kernel', 'ramdisk', 'bootloader', params={},
|
task, 'kernel', 'ramdisk', 'bootloader', params={},
|
||||||
inject_files={})
|
inject_files={}, base_iso=None)
|
||||||
|
|
||||||
find_mock.assert_has_calls(find_call_list)
|
|
||||||
|
|
||||||
@mock.patch.object(image_utils, '_find_param', autospec=True)
|
|
||||||
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
||||||
def test_prepare_deploy_iso_network_data(
|
def test_prepare_deploy_iso_existing_iso(self, mock__prepare_iso_image):
|
||||||
self, mock__prepare_iso_image, find_mock):
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
|
||||||
|
d_info = {
|
||||||
|
'redfish_deploy_iso': 'iso',
|
||||||
|
}
|
||||||
|
task.node.driver_info.update(d_info)
|
||||||
|
|
||||||
|
task.node.instance_info.update(deploy_boot_mode='uefi')
|
||||||
|
|
||||||
|
image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info)
|
||||||
|
|
||||||
|
mock__prepare_iso_image.assert_called_once_with(
|
||||||
|
task, None, None, None, params={},
|
||||||
|
inject_files={}, base_iso='iso')
|
||||||
|
|
||||||
|
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
||||||
|
def test_prepare_deploy_iso_network_data(self, mock__prepare_iso_image):
|
||||||
with task_manager.acquire(self.context, self.node.uuid,
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
shared=True) as task:
|
shared=True) as task:
|
||||||
|
|
||||||
@ -577,14 +580,6 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
|||||||
|
|
||||||
task.node.instance_info.update()
|
task.node.instance_info.update()
|
||||||
|
|
||||||
find_call_list = [
|
|
||||||
mock.call('deploy_kernel', d_info),
|
|
||||||
mock.call('deploy_ramdisk', d_info),
|
|
||||||
mock.call('bootloader', d_info)
|
|
||||||
]
|
|
||||||
find_mock.side_effect = [
|
|
||||||
'kernel', 'ramdisk', None
|
|
||||||
]
|
|
||||||
network_data = {'a': ['b']}
|
network_data = {'a': ['b']}
|
||||||
|
|
||||||
mock_get_node_nw_data = mock.MagicMock(return_value=network_data)
|
mock_get_node_nw_data = mock.MagicMock(return_value=network_data)
|
||||||
@ -602,14 +597,10 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
|||||||
|
|
||||||
mock__prepare_iso_image.assert_called_once_with(
|
mock__prepare_iso_image.assert_called_once_with(
|
||||||
task, 'kernel', 'ramdisk', bootloader_href=None,
|
task, 'kernel', 'ramdisk', bootloader_href=None,
|
||||||
params={}, inject_files=expected_files)
|
params={}, inject_files=expected_files, base_iso=None)
|
||||||
|
|
||||||
find_mock.assert_has_calls(find_call_list)
|
|
||||||
|
|
||||||
@mock.patch.object(image_utils, '_find_param', autospec=True)
|
|
||||||
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
||||||
def test_prepare_deploy_iso_tls(self, mock__prepare_iso_image,
|
def test_prepare_deploy_iso_tls(self, mock__prepare_iso_image):
|
||||||
find_mock):
|
|
||||||
with tempfile.NamedTemporaryFile(delete=False) as tf:
|
with tempfile.NamedTemporaryFile(delete=False) as tf:
|
||||||
temp_name = tf.name
|
temp_name = tf.name
|
||||||
self.addCleanup(lambda: os.unlink(temp_name))
|
self.addCleanup(lambda: os.unlink(temp_name))
|
||||||
@ -626,15 +617,6 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
|||||||
}
|
}
|
||||||
task.node.driver_info.update(d_info)
|
task.node.driver_info.update(d_info)
|
||||||
|
|
||||||
find_call_list = [
|
|
||||||
mock.call('deploy_kernel', d_info),
|
|
||||||
mock.call('deploy_ramdisk', d_info),
|
|
||||||
mock.call('bootloader', d_info)
|
|
||||||
]
|
|
||||||
find_mock.side_effect = [
|
|
||||||
'kernel', 'ramdisk', 'bootloader'
|
|
||||||
]
|
|
||||||
|
|
||||||
task.node.instance_info.update(deploy_boot_mode='uefi')
|
task.node.instance_info.update(deploy_boot_mode='uefi')
|
||||||
|
|
||||||
image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info)
|
image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info)
|
||||||
@ -648,9 +630,7 @@ cafile = /etc/ironic-python-agent/ironic.crt
|
|||||||
|
|
||||||
mock__prepare_iso_image.assert_called_once_with(
|
mock__prepare_iso_image.assert_called_once_with(
|
||||||
task, 'kernel', 'ramdisk', 'bootloader', params={},
|
task, 'kernel', 'ramdisk', 'bootloader', params={},
|
||||||
inject_files=expected_files)
|
inject_files=expected_files, base_iso=None)
|
||||||
|
|
||||||
find_mock.assert_has_calls(find_call_list)
|
|
||||||
|
|
||||||
@mock.patch.object(image_utils, '_find_param', autospec=True)
|
@mock.patch.object(image_utils, '_find_param', autospec=True)
|
||||||
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds support for pre-built ISO images to the ``redfish-virtual-media``
|
||||||
|
boot interface and its derivatives.
|
Loading…
Reference in New Issue
Block a user