summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/admin/drivers/ilo.rst5
-rw-r--r--doc/source/admin/drivers/redfish.rst5
-rw-r--r--ironic/drivers/modules/ilo/boot.py193
-rw-r--r--ironic/drivers/modules/ilo/common.py2
-rw-r--r--ironic/drivers/modules/image_utils.py23
-rw-r--r--ironic/tests/unit/drivers/modules/ilo/test_boot.py485
-rw-r--r--ironic/tests/unit/drivers/modules/ilo/test_common.py15
-rw-r--r--releasenotes/notes/add-iso-less-vmedia-ilo-5816922c03d0fd85.yaml18
8 files changed, 268 insertions, 478 deletions
diff --git a/doc/source/admin/drivers/ilo.rst b/doc/source/admin/drivers/ilo.rst
index 8395121f3..72778d09d 100644
--- a/doc/source/admin/drivers/ilo.rst
+++ b/doc/source/admin/drivers/ilo.rst
@@ -2162,6 +2162,11 @@ and ``ilo-uefi-https`` boot interface:
.. note::
UEFI secure boot is not supported with ``ilo-uefi-https`` boot interface.
+Layer 3 or DHCP-less ramdisk booting
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+DHCP-less deploy is supported by ``ilo`` and ``ilo5`` hardware types.
+However it would work only with ilo-virtual-media boot interface. See
+:ref:`dhcpless_booting` for more information.
.. _`ssacli documentation`: https://support.hpe.com/hpsc/doc/public/display?docId=c03909334
.. _`proliant-tools`: https://docs.openstack.org/diskimage-builder/latest/elements/proliant-tools/README.html
diff --git a/doc/source/admin/drivers/redfish.rst b/doc/source/admin/drivers/redfish.rst
index c2740452a..577d85f22 100644
--- a/doc/source/admin/drivers/redfish.rst
+++ b/doc/source/admin/drivers/redfish.rst
@@ -208,6 +208,9 @@ This initial interface does not support bootloader configuration
parameter injection, as such the ``[instance_info]/kernel_append_params``
setting is ignored.
+
+.. _`dhcpless_booting`:
+
Layer 3 or DHCP-less ramdisk booting
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -216,7 +219,7 @@ service since it's a User Datagram Protocol (UDP) like other protocols used by
the PXE suite, there is no guarantee that packets will be delivered.
One of the solutions is the reliance on virtual media boot capability coupled
-with another feature of ``redfish`` hardware type - its ability to provide
+with another feature of hardware type - its ability to provide
network configuration that is placed in the config-drive_ of the node, the
configuration follows the same schema that OpenStack Nova uses for the
``network_data.json``. The config drive filesystem information is on the IPA
diff --git a/ironic/drivers/modules/ilo/boot.py b/ironic/drivers/modules/ilo/boot.py
index 32ad16828..5ac645133 100644
--- a/ironic/drivers/modules/ilo/boot.py
+++ b/ironic/drivers/modules/ilo/boot.py
@@ -15,12 +15,9 @@
Boot Interface for iLO drivers and its supporting methods.
"""
-import os
-import tempfile
from urllib import parse as urlparse
from ironic_lib import metrics_utils
-from ironic_lib import utils as ironic_utils
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
@@ -32,7 +29,6 @@ from ironic.common.i18n import _
from ironic.common import image_service
from ironic.common import images
from ironic.common import states
-from ironic.common import swift
from ironic.conductor import utils as manager_utils
from ironic.drivers import base
from ironic.drivers.modules import boot_mode_utils
@@ -62,11 +58,6 @@ REQUIRED_PROPERTIES_UEFI_HTTPS_BOOT = {
"Required."),
'ilo_deploy_ramdisk': _("URL or Glance UUID of the ramdisk that is "
"mounted at boot time. Required."),
- 'ilo_bootloader': _("URL or Glance UUID of the EFI system partition "
- "image containing EFI boot loader. This image will "
- "be used by ironic when building UEFI-bootable ISO "
- "out of kernel and ramdisk. Required for UEFI "
- "boot from partition images.")
}
RESCUE_PROPERTIES_UEFI_HTTPS_BOOT = {
'ilo_rescue_kernel': _('URL or Glance UUID of the rescue kernel. This '
@@ -74,6 +65,8 @@ RESCUE_PROPERTIES_UEFI_HTTPS_BOOT = {
'ilo_rescue_ramdisk': _('URL or Glance UUID of the rescue ramdisk with '
'agent that is used at node rescue time. '
'The value is required for rescue mode.'),
+}
+OPTIONAL_PROPERTIES = {
'ilo_bootloader': _("URL or Glance UUID of the EFI system partition "
"image containing EFI boot loader. This image will "
"be used by ironic when building UEFI-bootable ISO "
@@ -82,6 +75,11 @@ RESCUE_PROPERTIES_UEFI_HTTPS_BOOT = {
}
COMMON_PROPERTIES = REQUIRED_PROPERTIES
+KERNEL_RAMDISK_LABELS = {
+ 'deploy': REQUIRED_PROPERTIES_UEFI_HTTPS_BOOT,
+ 'rescue': RESCUE_PROPERTIES_UEFI_HTTPS_BOOT
+}
+
def parse_driver_info(node, mode='deploy'):
"""Gets the driver specific Node deployment info.
@@ -101,36 +99,43 @@ def parse_driver_info(node, mode='deploy'):
"""
info = node.driver_info
d_info = {}
- if mode == 'rescue':
+ if mode == 'rescue' and info.get('ilo_rescue_iso'):
d_info['ilo_rescue_iso'] = info.get('ilo_rescue_iso')
- else:
+ elif mode == 'deploy' and info.get('ilo_deploy_iso'):
d_info['ilo_deploy_iso'] = info.get('ilo_deploy_iso')
+ else:
+ params_to_check = KERNEL_RAMDISK_LABELS[mode]
- error_msg = (_("Error validating iLO virtual media for %s. Some "
- "parameters were missing in node's driver_info") % mode)
- deploy_utils.check_for_missing_params(d_info, error_msg)
+ d_info = {option: info.get(option)
+ for option in params_to_check}
- return d_info
+ if not any(d_info.values()):
+ # NOTE(dtantsur): avoid situation when e.g. deploy_kernel comes
+ # from driver_info but deploy_ramdisk comes from configuration,
+ # since it's a sign of a potential operator's mistake.
+ d_info = {k: getattr(CONF.conductor, k.replace('ilo_', ''))
+ for k in params_to_check}
+ error_msg = (_("Error validating iLO virtual media for %s. Some "
+ "parameters were missing in node's driver_info.") % mode)
+ deploy_utils.check_for_missing_params(d_info, error_msg)
-def _get_boot_iso_object_name(node):
- """Returns the boot iso object name for a given node.
+ d_info.update(
+ {k: info.get(k, getattr(CONF.conductor, k.replace('ilo_', ''), None))
+ for k in OPTIONAL_PROPERTIES})
- :param node: the node for which object name is to be provided.
- """
- return "boot-%s" % node.uuid
+ return d_info
def _get_boot_iso(task, root_uuid):
"""This method returns a boot ISO to boot the node.
It chooses one of the three options in the order as below:
- 1. Does nothing if 'ilo_boot_iso' is present in node's instance_info and
- 'boot_iso_created_in_web_server' is not set in 'driver_internal_info'.
+ 1. Does nothing if 'ilo_boot_iso' is present in node's instance_info.
2. Image deployed has a meta-property 'boot_iso' in Glance. This should
refer to the UUID of the boot_iso which exists in Glance.
- 3. Generates a boot ISO on the fly using kernel and ramdisk mentioned in
- the image deployed. It uploads the generated boot ISO to Swift.
+ 3. Returns a boot ISO created on the fly using kernel and ramdisk
+ mentioned in the image deployed.
:param task: a TaskManager instance containing the node to act on.
:param root_uuid: the uuid of the root partition.
@@ -155,12 +160,7 @@ def _get_boot_iso(task, root_uuid):
# Option 1 - Check if user has provided ilo_boot_iso in node's
# instance_info
- driver_internal_info = task.node.driver_internal_info
- boot_iso_created_in_web_server = (
- driver_internal_info.get('boot_iso_created_in_web_server'))
-
- if (task.node.instance_info.get('ilo_boot_iso')
- and not boot_iso_created_in_web_server):
+ if task.node.instance_info.get('ilo_boot_iso'):
LOG.debug("Using ilo_boot_iso provided in node's instance_info")
boot_iso = task.node.instance_info['ilo_boot_iso']
if not service_utils.is_glance_image(boot_iso):
@@ -183,24 +183,14 @@ def _get_boot_iso(task, root_uuid):
image_href = deploy_info['image_source']
image_properties = (
images.get_image_properties(
- task.context, image_href, ['boot_iso', 'kernel_id', 'ramdisk_id']))
+ task.context, image_href, ['boot_iso']))
boot_iso_uuid = image_properties.get('boot_iso')
- kernel_href = (task.node.instance_info.get('kernel')
- or image_properties.get('kernel_id'))
- ramdisk_href = (task.node.instance_info.get('ramdisk')
- or image_properties.get('ramdisk_id'))
if boot_iso_uuid:
LOG.debug("Found boot_iso %s in Glance", boot_iso_uuid)
return boot_iso_uuid
- if not kernel_href or not ramdisk_href:
- LOG.error("Unable to find kernel or ramdisk for "
- "image %(image)s to generate boot ISO for %(node)s",
- {'image': image_href, 'node': task.node.uuid})
- return
-
# NOTE(rameshg87): Functionality to share the boot ISOs created for
# similar instances (instances with same deployed image) is
# not implemented as of now. Creation/Deletion of such a shared boot ISO
@@ -209,70 +199,7 @@ def _get_boot_iso(task, root_uuid):
# Option 3 - Create boot_iso from kernel/ramdisk, upload to Swift
# or web server and provide its name.
- deploy_iso_uuid = deploy_info['ilo_deploy_iso']
- boot_mode = boot_mode_utils.get_boot_mode(task.node)
- boot_iso_object_name = _get_boot_iso_object_name(task.node)
- kernel_params = ""
- if deploy_utils.get_boot_option(task.node) == "ramdisk":
- i_info = task.node.instance_info
- kernel_params = "root=/dev/ram0 text "
- kernel_params += i_info.get("ramdisk_kernel_arguments", "")
- else:
- kernel_params = CONF.pxe.pxe_append_params
- with tempfile.NamedTemporaryFile(dir=CONF.tempdir) as fileobj:
- boot_iso_tmp_file = fileobj.name
- images.create_boot_iso(task.context, boot_iso_tmp_file,
- kernel_href, ramdisk_href,
- deploy_iso_href=deploy_iso_uuid,
- root_uuid=root_uuid,
- kernel_params=kernel_params,
- boot_mode=boot_mode)
-
- if CONF.ilo.use_web_server_for_images:
- boot_iso_url = (
- ilo_common.copy_image_to_web_server(boot_iso_tmp_file,
- boot_iso_object_name))
- driver_internal_info = task.node.driver_internal_info
- driver_internal_info['boot_iso_created_in_web_server'] = True
- task.node.driver_internal_info = driver_internal_info
- task.node.save()
- LOG.debug("Created boot_iso %(boot_iso)s for node %(node)s",
- {'boot_iso': boot_iso_url, 'node': task.node.uuid})
- return boot_iso_url
- else:
- container = CONF.ilo.swift_ilo_container
- swift_api = swift.SwiftAPI()
- swift_api.create_object(container, boot_iso_object_name,
- boot_iso_tmp_file)
-
- LOG.debug("Created boot_iso %s in Swift", boot_iso_object_name)
- return 'swift:%s' % boot_iso_object_name
-
-
-def _clean_up_boot_iso_for_instance(node):
- """Deletes the boot ISO if it was created for the instance.
-
- :param node: an ironic node object.
- """
- ilo_boot_iso = node.instance_info.get('ilo_boot_iso')
- if not ilo_boot_iso:
- return
- if ilo_boot_iso.startswith('swift'):
- swift_api = swift.SwiftAPI()
- container = CONF.ilo.swift_ilo_container
- boot_iso_object_name = _get_boot_iso_object_name(node)
- try:
- swift_api.delete_object(container, boot_iso_object_name)
- except exception.SwiftOperationError as e:
- LOG.exception("Failed to clean up boot ISO for node "
- "%(node)s. Error: %(error)s.",
- {'node': node.uuid, 'error': e})
- elif CONF.ilo.use_web_server_for_images:
- result = urlparse.urlparse(ilo_boot_iso)
- ilo_boot_iso_name = os.path.basename(result.path)
- boot_iso_path = os.path.join(
- CONF.deploy.http_root, ilo_boot_iso_name)
- ironic_utils.unlink_without_raise(boot_iso_path)
+ return image_utils.prepare_boot_iso(task, deploy_info, root_uuid)
def _parse_deploy_info(node):
@@ -308,19 +235,7 @@ def _validate_driver_info(task):
"""
node = task.node
ilo_common.parse_driver_info(node)
- if 'ilo_deploy_iso' not in node.driver_info:
- raise exception.MissingParameterValue(_(
- "Missing 'ilo_deploy_iso' parameter in node's 'driver_info'."))
- deploy_iso = node.driver_info['ilo_deploy_iso']
- if not service_utils.is_glance_image(deploy_iso):
- try:
- image_service.HttpImageService().validate_href(deploy_iso)
- except exception.ImageRefValidationFailed:
- raise exception.InvalidParameterValue(_(
- "Virtual media boot accepts only Glance images or "
- "HTTP(S) as driver_info['ilo_deploy_iso']. Either '%s' "
- "is not a glance UUID or not a valid HTTP(S) URL or "
- "the given URL is not reachable.") % deploy_iso)
+ parse_driver_info(node)
def _validate_instance_image_info(task):
@@ -542,12 +457,19 @@ class IloVirtualMediaBoot(base.BootInterface):
deploy_nic_mac = deploy_utils.get_single_nic_with_vif_port_id(task)
ramdisk_params['BOOTIF'] = deploy_nic_mac
- if node.provision_state == states.RESCUING:
+ if (node.driver_info.get('ilo_rescue_iso')
+ and node.provision_state == states.RESCUING):
iso = node.driver_info['ilo_rescue_iso']
- else:
+ ilo_common.setup_vmedia(task, iso, ramdisk_params)
+ elif node.driver_info.get('ilo_deploy_iso'):
iso = node.driver_info['ilo_deploy_iso']
-
- ilo_common.setup_vmedia(task, iso, ramdisk_params)
+ ilo_common.setup_vmedia(task, iso, ramdisk_params)
+ else:
+ mode = deploy_utils.rescue_or_deploy_mode(node)
+ d_info = parse_driver_info(node, mode)
+ iso = image_utils.prepare_deploy_iso(task, ramdisk_params,
+ mode, d_info)
+ ilo_common.setup_vmedia(task, iso)
@METRICS.timer('IloVirtualMediaBoot.prepare_instance')
def prepare_instance(self, task):
@@ -635,19 +557,18 @@ class IloVirtualMediaBoot(base.BootInterface):
LOG.debug("Cleaning up the instance.")
manager_utils.node_power_action(task, states.POWER_OFF)
disable_secure_boot_if_supported(task)
- driver_internal_info = task.node.driver_internal_info
if (deploy_utils.is_iscsi_boot(task)
and task.node.driver_internal_info.get('ilo_uefi_iscsi_boot')):
# It will clear iSCSI info from iLO
task.driver.management.clear_iscsi_boot_target(task)
+ driver_internal_info = task.node.driver_internal_info
driver_internal_info.pop('ilo_uefi_iscsi_boot', None)
+ task.node.driver_internal_info = driver_internal_info
+ task.node.save()
else:
- _clean_up_boot_iso_for_instance(task.node)
- driver_internal_info.pop('boot_iso_created_in_web_server', None)
+ image_utils.cleanup_iso_image(task)
ilo_common.cleanup_vmedia_boot(task)
- task.node.driver_internal_info = driver_internal_info
- task.node.save()
@METRICS.timer('IloVirtualMediaBoot.clean_up_ramdisk')
def clean_up_ramdisk(self, task):
@@ -662,6 +583,12 @@ class IloVirtualMediaBoot(base.BootInterface):
"""
ilo_common.cleanup_vmedia_boot(task)
+ info = task.node.driver_info
+ mode = deploy_utils.rescue_or_deploy_mode(task.node)
+ if ((mode == 'rescue' and not info.get('ilo_rescue_iso'))
+ or (mode == 'deploy' and not info.get('ilo_deploy_iso'))):
+ image_utils.cleanup_iso_image(task)
+
def _configure_vmedia_boot(self, task, root_uuid):
"""Configure vmedia boot for the node.
@@ -978,6 +905,18 @@ class IloUefiHttpsBoot(base.BootInterface):
deploy_info = {option: info.get(option)
for option in params_to_check}
+ if not any(deploy_info.values()):
+ # NOTE(dtantsur): avoid situation when e.g. deploy_kernel comes
+ # from driver_info but deploy_ramdisk comes from configuration,
+ # since it's a sign of a potential operator's mistake.
+ deploy_info = {k: getattr(CONF.conductor, k.replace('ilo_', ''))
+ for k in params_to_check}
+
+ deploy_info.update(
+ {k: info.get(k, getattr(CONF.conductor,
+ k.replace('ilo_', ''), None))
+ for k in OPTIONAL_PROPERTIES})
+
self._validate_hrefs(deploy_info)
error_msg = (_("Error validating %s for iLO UEFI HTTPS boot. Some "
diff --git a/ironic/drivers/modules/ilo/common.py b/ironic/drivers/modules/ilo/common.py
index 4ef8dc85e..d76d4a04a 100644
--- a/ironic/drivers/modules/ilo/common.py
+++ b/ironic/drivers/modules/ilo/common.py
@@ -645,7 +645,7 @@ def update_boot_mode(task):
node.save()
-def setup_vmedia(task, iso, ramdisk_options):
+def setup_vmedia(task, iso, ramdisk_options=None):
"""Attaches virtual media and sets it as boot device.
This method attaches the given bootable ISO as virtual media, prepares the
diff --git a/ironic/drivers/modules/image_utils.py b/ironic/drivers/modules/image_utils.py
index f341d6873..ce87adc93 100644
--- a/ironic/drivers/modules/image_utils.py
+++ b/ironic/drivers/modules/image_utils.py
@@ -43,14 +43,24 @@ class ImageHandler(object):
"container": CONF.redfish.swift_container,
"timeout": CONF.redfish.swift_object_expiry_timeout,
"image_subdir": "redfish",
- "file_permission": CONF.redfish.file_permission
+ "file_permission": CONF.redfish.file_permission,
+ "kernel_params": CONF.redfish.kernel_append_params
},
"ilo5": {
"swift_enabled": not CONF.ilo.use_web_server_for_images,
"container": CONF.ilo.swift_ilo_container,
"timeout": CONF.ilo.swift_object_expiry_timeout,
"image_subdir": "ilo",
- "file_permission": CONF.ilo.file_permission
+ "file_permission": CONF.ilo.file_permission,
+ "kernel_params": CONF.pxe.pxe_append_params
+ },
+ "ilo": {
+ "swift_enabled": not CONF.ilo.use_web_server_for_images,
+ "container": CONF.ilo.swift_ilo_container,
+ "timeout": CONF.ilo.swift_object_expiry_timeout,
+ "image_subdir": "ilo",
+ "file_permission": CONF.ilo.file_permission,
+ "kernel_params": CONF.pxe.pxe_append_params
},
}
@@ -60,6 +70,8 @@ class ImageHandler(object):
self._timeout = self._SWIFT_MAP[driver].get("timeout")
self._image_subdir = self._SWIFT_MAP[driver].get("image_subdir")
self._file_permission = self._SWIFT_MAP[driver].get("file_permission")
+ # To get the kernel parameters
+ self.kernel_params = self._SWIFT_MAP[driver].get("kernel_params")
def _is_swift_enabled(self):
try:
@@ -303,6 +315,9 @@ def _prepare_iso_image(task, kernel_href, ramdisk_href,
"building ISO, or explicit ISO for %(node)s") %
{'node': task.node.uuid})
+ img_handler = ImageHandler(task.node.driver)
+ k_param = img_handler.kernel_params
+
i_info = task.node.instance_info
# NOTE(TheJulia): Until we support modifying a base iso, most of
@@ -315,8 +330,7 @@ def _prepare_iso_image(task, kernel_href, ramdisk_href,
kernel_params = None
else:
- kernel_params = i_info.get(
- 'kernel_append_params', CONF.redfish.kernel_append_params)
+ kernel_params = i_info.get('kernel_append_params', k_param)
if params and not base_iso:
kernel_params = ' '.join(
@@ -374,7 +388,6 @@ def _prepare_iso_image(task, kernel_href, ramdisk_href,
iso_object_name = _get_iso_image_name(task.node)
- img_handler = ImageHandler(task.node.driver)
image_url = img_handler.publish_image(
boot_iso_tmp_file, iso_object_name)
diff --git a/ironic/tests/unit/drivers/modules/ilo/test_boot.py b/ironic/tests/unit/drivers/modules/ilo/test_boot.py
index d681cb72c..0a435dde3 100644
--- a/ironic/tests/unit/drivers/modules/ilo/test_boot.py
+++ b/ironic/tests/unit/drivers/modules/ilo/test_boot.py
@@ -15,12 +15,9 @@
"""Test class for boot methods used by iLO modules."""
-import io
-import tempfile
from unittest import mock
from urllib import parse as urlparse
-from ironic_lib import utils as ironic_utils
from oslo_config import cfg
from ironic.common import boot_devices
@@ -29,7 +26,6 @@ from ironic.common.glance_service import service_utils
from ironic.common import image_service
from ironic.common import images
from ironic.common import states
-from ironic.common import swift
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.drivers.modules import boot_mode_utils
@@ -56,9 +52,74 @@ class IloBootCommonMethodsTestCase(test_common.BaseIloTest):
boot_interface = 'ilo-virtual-media'
- def test_parse_driver_info(self):
+ def test_parse_driver_info_deploy_iso(self):
self.node.driver_info['ilo_deploy_iso'] = 'deploy-iso'
- expected_driver_info = {'ilo_deploy_iso': 'deploy-iso'}
+ expected_driver_info = {'ilo_bootloader': None,
+ 'ilo_deploy_iso': 'deploy-iso'}
+
+ actual_driver_info = ilo_boot.parse_driver_info(self.node)
+ self.assertEqual(expected_driver_info, actual_driver_info)
+
+ def test_parse_driver_info_rescue_iso(self):
+ self.node.driver_info['ilo_rescue_iso'] = 'rescue-iso'
+ expected_driver_info = {'ilo_bootloader': None,
+ 'ilo_rescue_iso': 'rescue-iso'}
+
+ actual_driver_info = ilo_boot.parse_driver_info(self.node, 'rescue')
+ self.assertEqual(expected_driver_info, actual_driver_info)
+
+ def test_parse_driver_info_deploy(self):
+ self.node.driver_info['ilo_deploy_kernel'] = 'kernel'
+ self.node.driver_info['ilo_deploy_ramdisk'] = 'ramdisk'
+ self.node.driver_info['ilo_bootloader'] = 'bootloader'
+ expected_driver_info = {'ilo_deploy_kernel': 'kernel',
+ 'ilo_deploy_ramdisk': 'ramdisk',
+ 'ilo_bootloader': 'bootloader'}
+
+ actual_driver_info = ilo_boot.parse_driver_info(self.node)
+ self.assertEqual(expected_driver_info, actual_driver_info)
+
+ def test_parse_driver_info_rescue(self):
+ self.node.driver_info['ilo_rescue_kernel'] = 'kernel'
+ self.node.driver_info['ilo_rescue_ramdisk'] = 'ramdisk'
+ self.node.driver_info['ilo_bootloader'] = 'bootloader'
+ expected_driver_info = {'ilo_rescue_kernel': 'kernel',
+ 'ilo_rescue_ramdisk': 'ramdisk',
+ 'ilo_bootloader': 'bootloader'}
+
+ actual_driver_info = ilo_boot.parse_driver_info(self.node, 'rescue')
+ self.assertEqual(expected_driver_info, actual_driver_info)
+
+ def test_parse_driver_info_deploy_config(self):
+ CONF.conductor.deploy_kernel = 'kernel'
+ CONF.conductor.deploy_ramdisk = 'ramdisk'
+ CONF.conductor.bootloader = 'bootloader'
+ expected_driver_info = {'ilo_deploy_kernel': 'kernel',
+ 'ilo_deploy_ramdisk': 'ramdisk',
+ 'ilo_bootloader': 'bootloader'}
+
+ actual_driver_info = ilo_boot.parse_driver_info(self.node)
+ self.assertEqual(expected_driver_info, actual_driver_info)
+
+ def test_parse_driver_info_rescue_config(self):
+ CONF.conductor.rescue_kernel = 'kernel'
+ CONF.conductor.rescue_ramdisk = 'ramdisk'
+ CONF.conductor.bootloader = 'bootloader'
+
+ expected_driver_info = {'ilo_rescue_kernel': 'kernel',
+ 'ilo_rescue_ramdisk': 'ramdisk',
+ 'ilo_bootloader': 'bootloader'}
+
+ actual_driver_info = ilo_boot.parse_driver_info(self.node, 'rescue')
+ self.assertEqual(expected_driver_info, actual_driver_info)
+
+ def test_parse_driver_info_bootloader_none(self):
+ CONF.conductor.deploy_kernel = 'kernel'
+ CONF.conductor.deploy_ramdisk = 'ramdisk'
+
+ expected_driver_info = {'ilo_deploy_kernel': 'kernel',
+ 'ilo_deploy_ramdisk': 'ramdisk',
+ 'ilo_bootloader': None}
actual_driver_info = ilo_boot.parse_driver_info(self.node)
self.assertEqual(expected_driver_info, actual_driver_info)
@@ -72,11 +133,6 @@ class IloBootPrivateMethodsTestCase(test_common.BaseIloTest):
boot_interface = 'ilo-virtual-media'
- def test__get_boot_iso_object_name(self):
- boot_iso_actual = ilo_boot._get_boot_iso_object_name(self.node)
- boot_iso_expected = "boot-%s" % self.node.uuid
- self.assertEqual(boot_iso_expected, boot_iso_actual)
-
@mock.patch.object(image_service.HttpImageService, 'validate_href',
spec_set=True, autospec=True)
def test__get_boot_iso_http_url(self, service_mock):
@@ -116,294 +172,44 @@ class IloBootPrivateMethodsTestCase(test_common.BaseIloTest):
image_props_mock):
deploy_info_mock.return_value = {'image_source': 'image-uuid',
'ilo_deploy_iso': 'deploy_iso_uuid'}
- image_props_mock.return_value = {'boot_iso': u'glance://uui\u0111',
- 'kernel_id': None,
- 'ramdisk_id': None}
+ image_props_mock.return_value = {'boot_iso': u'glance://uui\u0111'}
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- driver_internal_info = task.node.driver_internal_info
- driver_internal_info['boot_iso_created_in_web_server'] = False
- task.node.driver_internal_info = driver_internal_info
- task.node.save()
boot_iso_actual = ilo_boot._get_boot_iso(task, 'root-uuid')
deploy_info_mock.assert_called_once_with(task.node)
image_props_mock.assert_called_once_with(
- task.context, 'image-uuid',
- ['boot_iso', 'kernel_id', 'ramdisk_id'])
+ task.context, 'image-uuid', ['boot_iso'])
boot_iso_expected = u'glance://uui\u0111'
self.assertEqual(boot_iso_expected, boot_iso_actual)
- @mock.patch.object(boot_mode_utils, 'get_boot_mode_for_deploy',
- spec_set=True, autospec=True)
- @mock.patch.object(ilo_boot.LOG, 'error', spec_set=True, autospec=True)
- @mock.patch.object(images, 'get_image_properties', spec_set=True,
- autospec=True)
- @mock.patch.object(ilo_boot, '_parse_deploy_info', spec_set=True,
- autospec=True)
- def test__get_boot_iso_uefi_no_glance_image(self,
- deploy_info_mock,
- image_props_mock,
- log_mock,
- boot_mode_mock):
- deploy_info_mock.return_value = {'image_source': 'image-uuid',
- 'ilo_deploy_iso': 'deploy_iso_uuid'}
- image_props_mock.return_value = {'boot_iso': None,
- 'kernel_id': None,
- 'ramdisk_id': None}
- properties = {'capabilities': 'boot_mode:uefi'}
-
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- task.node.properties = properties
- boot_iso_result = ilo_boot._get_boot_iso(task, 'root-uuid')
- deploy_info_mock.assert_called_once_with(task.node)
- image_props_mock.assert_called_once_with(
- task.context, 'image-uuid',
- ['boot_iso', 'kernel_id', 'ramdisk_id'])
- self.assertTrue(log_mock.called)
- self.assertFalse(boot_mode_mock.called)
- self.assertIsNone(boot_iso_result)
-
- @mock.patch.object(tempfile, 'NamedTemporaryFile', spec_set=True,
- autospec=True)
- @mock.patch.object(images, 'create_boot_iso', spec_set=True, autospec=True)
- @mock.patch.object(swift, 'SwiftAPI', spec_set=True, autospec=True)
- @mock.patch.object(ilo_boot, '_get_boot_iso_object_name', spec_set=True,
- autospec=True)
- @mock.patch.object(driver_utils, 'get_node_capability', spec_set=True,
+ @mock.patch.object(image_utils, 'prepare_boot_iso', spec_set=True,
autospec=True)
@mock.patch.object(images, 'get_image_properties', spec_set=True,
autospec=True)
@mock.patch.object(ilo_boot, '_parse_deploy_info', spec_set=True,
autospec=True)
def test__get_boot_iso_create(self, deploy_info_mock, image_props_mock,
- capability_mock, boot_object_name_mock,
- swift_api_mock,
- create_boot_iso_mock, tempfile_mock):
- CONF.ilo.swift_ilo_container = 'ilo-cont'
- CONF.pxe.pxe_append_params = 'kernel-params'
-
- swift_obj_mock = swift_api_mock.return_value
- fileobj_mock = mock.MagicMock(spec=io.BytesIO)
- fileobj_mock.name = 'tmpfile'
- mock_file_handle = mock.MagicMock(spec=io.BytesIO)
- mock_file_handle.__enter__.return_value = fileobj_mock
- tempfile_mock.return_value = mock_file_handle
+ prepare_iso_mock):
deploy_info_mock.return_value = {'image_source': 'image-uuid',
'ilo_deploy_iso': 'deploy_iso_uuid'}
- image_props_mock.return_value = {'boot_iso': None,
- 'kernel_id': 'kernel_uuid',
- 'ramdisk_id': 'ramdisk_uuid'}
- boot_object_name_mock.return_value = 'abcdef'
- create_boot_iso_mock.return_value = '/path/to/boot-iso'
- capability_mock.return_value = 'uefi'
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- boot_iso_actual = ilo_boot._get_boot_iso(task, 'root-uuid')
- deploy_info_mock.assert_called_once_with(task.node)
- image_props_mock.assert_called_once_with(
- task.context, 'image-uuid',
- ['boot_iso', 'kernel_id', 'ramdisk_id'])
- boot_object_name_mock.assert_called_once_with(task.node)
- create_boot_iso_mock.assert_called_once_with(
- task.context, 'tmpfile', 'kernel_uuid', 'ramdisk_uuid',
- deploy_iso_href='deploy_iso_uuid',
- root_uuid='root-uuid',
- kernel_params='kernel-params',
- boot_mode='uefi')
- swift_obj_mock.create_object.assert_called_once_with('ilo-cont',
- 'abcdef',
- 'tmpfile')
- boot_iso_expected = 'swift:abcdef'
- self.assertEqual(boot_iso_expected, boot_iso_actual)
-
- @mock.patch.object(ilo_common, 'copy_image_to_web_server', spec_set=True,
- autospec=True)
- @mock.patch.object(tempfile, 'NamedTemporaryFile', spec_set=True,
- autospec=True)
- @mock.patch.object(images, 'create_boot_iso', spec_set=True, autospec=True)
- @mock.patch.object(ilo_boot, '_get_boot_iso_object_name', spec_set=True,
- autospec=True)
- @mock.patch.object(driver_utils, 'get_node_capability', spec_set=True,
- autospec=True)
- @mock.patch.object(images, 'get_image_properties', spec_set=True,
- autospec=True)
- @mock.patch.object(ilo_boot, '_parse_deploy_info', spec_set=True,
- autospec=True)
- def test__get_boot_iso_recreate_boot_iso_use_webserver(
- self, deploy_info_mock, image_props_mock,
- capability_mock, boot_object_name_mock,
- create_boot_iso_mock, tempfile_mock,
- copy_file_mock):
- CONF.ilo.swift_ilo_container = 'ilo-cont'
- CONF.ilo.use_web_server_for_images = True
- CONF.deploy.http_url = "http://10.10.1.30/httpboot"
- CONF.deploy.http_root = "/httpboot"
- CONF.pxe.pxe_append_params = 'kernel-params'
-
- fileobj_mock = mock.MagicMock(spec=io.BytesIO)
- fileobj_mock.name = 'tmpfile'
- mock_file_handle = mock.MagicMock(spec=io.BytesIO)
- mock_file_handle.__enter__.return_value = fileobj_mock
- tempfile_mock.return_value = mock_file_handle
-
- ramdisk_href = "http://10.10.1.30/httpboot/ramdisk"
- kernel_href = "http://10.10.1.30/httpboot/kernel"
- deploy_info_mock.return_value = {'image_source': 'image-uuid',
- 'ilo_deploy_iso': 'deploy_iso_uuid'}
- image_props_mock.return_value = {'boot_iso': None,
- 'kernel_id': kernel_href,
- 'ramdisk_id': ramdisk_href}
- boot_object_name_mock.return_value = 'new_boot_iso'
- create_boot_iso_mock.return_value = '/path/to/boot-iso'
- capability_mock.return_value = 'uefi'
- copy_file_mock.return_value = "http://10.10.1.30/httpboot/new_boot_iso"
-
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- driver_internal_info = task.node.driver_internal_info
- driver_internal_info['boot_iso_created_in_web_server'] = True
- instance_info = task.node.instance_info
- old_boot_iso = 'http://10.10.1.30/httpboot/old_boot_iso'
- instance_info['ilo_boot_iso'] = old_boot_iso
- boot_iso_actual = ilo_boot._get_boot_iso(task, 'root-uuid')
- deploy_info_mock.assert_called_once_with(task.node)
- image_props_mock.assert_called_once_with(
- task.context, 'image-uuid',
- ['boot_iso', 'kernel_id', 'ramdisk_id'])
- boot_object_name_mock.assert_called_once_with(task.node)
- create_boot_iso_mock.assert_called_once_with(
- task.context, 'tmpfile', kernel_href, ramdisk_href,
- deploy_iso_href='deploy_iso_uuid',
- root_uuid='root-uuid',
- kernel_params='kernel-params',
- boot_mode='uefi')
- boot_iso_expected = 'http://10.10.1.30/httpboot/new_boot_iso'
- self.assertEqual(boot_iso_expected, boot_iso_actual)
- copy_file_mock.assert_called_once_with(fileobj_mock.name,
- 'new_boot_iso')
+ image_props_mock.return_value = {'boot_iso': None}
- @mock.patch.object(ilo_common, 'copy_image_to_web_server', spec_set=True,
- autospec=True)
- @mock.patch.object(tempfile, 'NamedTemporaryFile', spec_set=True,
- autospec=True)
- @mock.patch.object(images, 'create_boot_iso', spec_set=True, autospec=True)
- @mock.patch.object(ilo_boot, '_get_boot_iso_object_name', spec_set=True,
- autospec=True)
- @mock.patch.object(driver_utils, 'get_node_capability', spec_set=True,
- autospec=True)
- @mock.patch.object(images, 'get_image_properties', spec_set=True,
- autospec=True)
- @mock.patch.object(ilo_boot, '_parse_deploy_info', spec_set=True,
- autospec=True)
- def test__get_boot_iso_create_use_webserver_true_ramdisk_webserver(
- self, deploy_info_mock, image_props_mock,
- capability_mock, boot_object_name_mock,
- create_boot_iso_mock, tempfile_mock,
- copy_file_mock):
- CONF.ilo.swift_ilo_container = 'ilo-cont'
- CONF.ilo.use_web_server_for_images = True
- CONF.deploy.http_url = "http://10.10.1.30/httpboot"
- CONF.deploy.http_root = "/httpboot"
- CONF.pxe.pxe_append_params = 'kernel-params'
-
- fileobj_mock = mock.MagicMock(spec=io.BytesIO)
- fileobj_mock.name = 'tmpfile'
- mock_file_handle = mock.MagicMock(spec=io.BytesIO)
- mock_file_handle.__enter__.return_value = fileobj_mock
- tempfile_mock.return_value = mock_file_handle
-
- ramdisk_href = "http://10.10.1.30/httpboot/ramdisk"
- kernel_href = "http://10.10.1.30/httpboot/kernel"
- deploy_info_mock.return_value = {'image_source': 'image-uuid',
- 'ilo_deploy_iso': 'deploy_iso_uuid'}
- image_props_mock.return_value = {'boot_iso': None,
- 'kernel_id': kernel_href,
- 'ramdisk_id': ramdisk_href}
- boot_object_name_mock.return_value = 'abcdef'
- create_boot_iso_mock.return_value = '/path/to/boot-iso'
- capability_mock.return_value = 'uefi'
- copy_file_mock.return_value = "http://10.10.1.30/httpboot/abcdef"
+ prepare_iso_mock.return_value = 'swift:boot-iso'
+ d_info = {'image_source': 'image-uuid',
+ 'ilo_deploy_iso': 'deploy_iso_uuid'}
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
boot_iso_actual = ilo_boot._get_boot_iso(task, 'root-uuid')
deploy_info_mock.assert_called_once_with(task.node)
image_props_mock.assert_called_once_with(
- task.context, 'image-uuid',
- ['boot_iso', 'kernel_id', 'ramdisk_id'])
- boot_object_name_mock.assert_called_once_with(task.node)
- create_boot_iso_mock.assert_called_once_with(
- task.context, 'tmpfile', kernel_href, ramdisk_href,
- deploy_iso_href='deploy_iso_uuid',
- root_uuid='root-uuid',
- kernel_params='kernel-params',
- boot_mode='uefi')
- boot_iso_expected = 'http://10.10.1.30/httpboot/abcdef'
+ task.context, 'image-uuid', ['boot_iso'])
+ prepare_iso_mock.assert_called_once_with(
+ task, d_info, 'root-uuid')
+ boot_iso_expected = 'swift:boot-iso'
self.assertEqual(boot_iso_expected, boot_iso_actual)
- copy_file_mock.assert_called_once_with(fileobj_mock.name,
- 'abcdef')
-
- @mock.patch.object(ilo_boot, '_get_boot_iso_object_name', spec_set=True,
- autospec=True)
- @mock.patch.object(swift, 'SwiftAPI', spec_set=True, autospec=True)
- def test__clean_up_boot_iso_for_instance(self, swift_mock,
- boot_object_name_mock):
- swift_obj_mock = swift_mock.return_value
- CONF.ilo.swift_ilo_container = 'ilo-cont'
- boot_object_name_mock.return_value = 'boot-object'
- i_info = self.node.instance_info
- i_info['ilo_boot_iso'] = 'swift:bootiso'
- self.node.instance_info = i_info
- self.node.save()
- ilo_boot._clean_up_boot_iso_for_instance(self.node)
- swift_obj_mock.delete_object.assert_called_once_with('ilo-cont',
- 'boot-object')
-
- @mock.patch.object(ilo_boot.LOG, 'exception', spec_set=True,
- autospec=True)
- @mock.patch.object(ilo_boot, '_get_boot_iso_object_name', spec_set=True,
- autospec=True)
- @mock.patch.object(swift, 'SwiftAPI', spec_set=True, autospec=True)
- def test__clean_up_boot_iso_for_instance_exc(self, swift_mock,
- boot_object_name_mock,
- log_mock):
- swift_obj_mock = swift_mock.return_value
- exc = exception.SwiftObjectNotFoundError('error')
- swift_obj_mock.delete_object.side_effect = exc
- CONF.ilo.swift_ilo_container = 'ilo-cont'
- boot_object_name_mock.return_value = 'boot-object'
- i_info = self.node.instance_info
- i_info['ilo_boot_iso'] = 'swift:bootiso'
- self.node.instance_info = i_info
- self.node.save()
- ilo_boot._clean_up_boot_iso_for_instance(self.node)
- swift_obj_mock.delete_object.assert_called_once_with('ilo-cont',
- 'boot-object')
- self.assertTrue(log_mock.called)
-
- @mock.patch.object(ironic_utils, 'unlink_without_raise', spec_set=True,
- autospec=True)
- def test__clean_up_boot_iso_for_instance_on_webserver(self, unlink_mock):
-
- CONF.ilo.use_web_server_for_images = True
- CONF.deploy.http_root = "/webserver"
- i_info = self.node.instance_info
- i_info['ilo_boot_iso'] = 'http://x.y.z.a/webserver/boot-object'
- self.node.instance_info = i_info
- self.node.save()
- boot_iso_path = "/webserver/boot-object"
- ilo_boot._clean_up_boot_iso_for_instance(self.node)
- unlink_mock.assert_called_once_with(boot_iso_path)
-
- @mock.patch.object(ilo_boot, '_get_boot_iso_object_name', spec_set=True,
- autospec=True)
- def test__clean_up_boot_iso_for_instance_no_boot_iso(
- self, boot_object_name_mock):
- ilo_boot._clean_up_boot_iso_for_instance(self.node)
- self.assertFalse(boot_object_name_mock.called)
@mock.patch.object(ilo_boot, 'parse_driver_info', spec_set=True,
autospec=True)
@@ -418,68 +224,15 @@ class IloBootPrivateMethodsTestCase(test_common.BaseIloTest):
@mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
autospec=True)
- def test__validate_driver_info_MissingParam(self, mock_parse_driver_info):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- self.assertRaisesRegex(exception.MissingParameterValue,
- "Missing 'ilo_deploy_iso'",
- ilo_boot._validate_driver_info, task)
- mock_parse_driver_info.assert_called_once_with(task.node)
-
- @mock.patch.object(service_utils, 'is_glance_image', spec_set=True,
- autospec=True)
- @mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
- autospec=True)
- def test__validate_driver_info_valid_uuid(self, mock_parse_driver_info,
- mock_is_glance_image):
- mock_is_glance_image.return_value = True
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- deploy_iso = '8a81759a-f29b-454b-8ab3-161c6ca1882c'
- task.node.driver_info['ilo_deploy_iso'] = deploy_iso
- ilo_boot._validate_driver_info(task)
- mock_parse_driver_info.assert_called_once_with(task.node)
- mock_is_glance_image.assert_called_once_with(deploy_iso)
-
- @mock.patch.object(image_service.HttpImageService, 'validate_href',
- spec_set=True, autospec=True)
- @mock.patch.object(service_utils, 'is_glance_image', spec_set=True,
- autospec=True)
- @mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
- autospec=True)
- def test__validate_driver_info_InvalidParam(self, mock_parse_driver_info,
- mock_is_glance_image,
- mock_validate_href):
- deploy_iso = 'http://abc.org/image/qcow2'
- mock_validate_href.side_effect = exception.ImageRefValidationFailed(
- image_href='http://abc.org/image/qcow2', reason='fail')
- mock_is_glance_image.return_value = False
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- task.node.driver_info['ilo_deploy_iso'] = deploy_iso
- self.assertRaisesRegex(exception.InvalidParameterValue,
- "Virtual media boot accepts",
- ilo_boot._validate_driver_info, task)
- mock_parse_driver_info.assert_called_once_with(task.node)
- mock_validate_href.assert_called_once_with(mock.ANY, deploy_iso)
-
- @mock.patch.object(image_service.HttpImageService, 'validate_href',
- spec_set=True, autospec=True)
- @mock.patch.object(service_utils, 'is_glance_image', spec_set=True,
- autospec=True)
- @mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
+ @mock.patch.object(ilo_boot, 'parse_driver_info', spec_set=True,
autospec=True)
- def test__validate_driver_info_valid_url(self, mock_parse_driver_info,
- mock_is_glance_image,
- mock_validate_href):
- deploy_iso = 'http://abc.org/image/deploy.iso'
- mock_is_glance_image.return_value = False
+ def test__validate_driver_info(self, mock_driver_info,
+ mock_parse_driver_info):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- task.node.driver_info['ilo_deploy_iso'] = deploy_iso
ilo_boot._validate_driver_info(task)
mock_parse_driver_info.assert_called_once_with(task.node)
- mock_validate_href.assert_called_once_with(mock.ANY, deploy_iso)
+ mock_driver_info.assert_called_once_with(task.node)
@mock.patch.object(deploy_utils, 'validate_image_properties',
spec_set=True, autospec=True)
@@ -907,6 +660,48 @@ class IloVirtualMediaBootTestCase(test_common.BaseIloTest):
self.assertEqual('http://mybootiso',
self.node.instance_info['ilo_boot_iso'])
+ @mock.patch.object(ilo_boot, 'prepare_node_for_deploy',
+ spec_set=True, autospec=True)
+ @mock.patch.object(ilo_common, 'eject_vmedia_devices',
+ spec_set=True, autospec=True)
+ @mock.patch.object(ilo_common, 'setup_vmedia', spec_set=True,
+ autospec=True)
+ @mock.patch.object(deploy_utils, 'get_single_nic_with_vif_port_id',
+ spec_set=True, autospec=True)
+ @mock.patch.object(deploy_utils, 'rescue_or_deploy_mode',
+ spec_set=True, autospec=True)
+ @mock.patch.object(ilo_boot, 'parse_driver_info', spec_set=True,
+ autospec=True)
+ @mock.patch.object(image_utils, 'prepare_deploy_iso',
+ spec_set=True, autospec=True)
+ def test_prepare_ramdisk_not_iso(
+ self, prepare_deploy_iso_mock, driver_info_mock,
+ mode_mock, get_nic_mock, setup_vmedia_mock,
+ eject_mock, prepare_node_for_deploy_mock):
+ self.node.provision_state = states.DEPLOYING
+ self.node.save()
+ mode = 'deploy'
+ ramdisk_params = {'a': 'b'}
+ d_info = {
+ 'ilo_deploy_kernel': 'kernel',
+ 'ilo_deploy_ramdisk': 'ramdisk',
+ 'ilo_bootloader': 'bootloader'
+ }
+ driver_info_mock.return_value = d_info
+ prepare_deploy_iso_mock.return_value = 'recreated-iso'
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ mode_mock.return_value = 'deploy'
+ get_nic_mock.return_value = '12:34:56:78:90:ab'
+ task.driver.boot.prepare_ramdisk(task, ramdisk_params)
+ prepare_node_for_deploy_mock.assert_called_once_with(task)
+ eject_mock.assert_called_once_with(task)
+ driver_info_mock.assert_called_once_with(task.node, mode)
+ prepare_deploy_iso_mock.assert_called_once_with(
+ task, ramdisk_params, mode, d_info)
+ setup_vmedia_mock.assert_called_once_with(task, 'recreated-iso')
+
@mock.patch.object(manager_utils, 'node_set_boot_device', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'setup_vmedia_for_boot', spec_set=True,
@@ -963,8 +758,8 @@ class IloVirtualMediaBootTestCase(test_common.BaseIloTest):
autospec=True)
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot', spec_set=True,
autospec=True)
- @mock.patch.object(ilo_boot, '_clean_up_boot_iso_for_instance',
- spec_set=True, autospec=True)
+ @mock.patch.object(image_utils, 'cleanup_iso_image', spec_set=True,
+ autospec=True)
def _test_clean_up_instance(self, cleanup_iso_mock,
cleanup_vmedia_mock, node_power_mock,
update_secure_boot_mode_mock,
@@ -972,16 +767,13 @@ class IloVirtualMediaBootTestCase(test_common.BaseIloTest):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
driver_internal_info = task.node.driver_internal_info
- driver_internal_info['boot_iso_created_in_web_server'] = False
task.node.driver_internal_info = driver_internal_info
task.node.save()
is_iscsi_boot_mock.return_value = False
task.driver.boot.clean_up_instance(task)
- cleanup_iso_mock.assert_called_once_with(task.node)
+ cleanup_iso_mock.assert_called_once_with(task)
cleanup_vmedia_mock.assert_called_once_with(task)
driver_internal_info = task.node.driver_internal_info
- self.assertNotIn('boot_iso_created_in_web_server',
- driver_internal_info)
node_power_mock.assert_called_once_with(task,
states.POWER_OFF)
update_secure_boot_mode_mock.assert_called_once_with(task, False)
@@ -1024,8 +816,8 @@ class IloVirtualMediaBootTestCase(test_common.BaseIloTest):
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot', spec_set=True,
autospec=True)
- @mock.patch.object(ilo_boot, '_clean_up_boot_iso_for_instance',
- spec_set=True, autospec=True)
+ @mock.patch.object(image_utils, 'cleanup_iso_image', spec_set=True,
+ autospec=True)
@mock.patch.object(deploy_utils, 'is_iscsi_boot',
spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'update_secure_boot_mode', spec_set=True,
@@ -1039,22 +831,27 @@ class IloVirtualMediaBootTestCase(test_common.BaseIloTest):
shared=False) as task:
is_iscsi_boot_mock.return_value = False
task.driver.boot.clean_up_instance(task)
- cleanup_iso_mock.assert_called_once_with(task.node)
+ cleanup_iso_mock.assert_called_once_with(task)
cleanup_vmedia_mock.assert_called_once_with(task)
- driver_internal_info = task.node.driver_internal_info
- self.assertNotIn('boot_iso_created_in_web_server',
- driver_internal_info)
node_power_mock.assert_called_once_with(task,
states.POWER_OFF)
update_secure_boot_mode_mock.assert_called_once_with(task, False)
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot', spec_set=True,
autospec=True)
- def test_clean_up_ramdisk(self, cleanup_vmedia_mock):
+ @mock.patch.object(deploy_utils, 'rescue_or_deploy_mode',
+ spec_set=True, autospec=True)
+ @mock.patch.object(image_utils, 'cleanup_iso_image', spec_set=True,
+ autospec=True)
+ def test_clean_up_ramdisk(self, cleanup_iso_mock, mode_mock,
+ cleanup_vmedia_mock):
+ mode_mock.return_value = 'deploy'
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.boot.clean_up_ramdisk(task)
cleanup_vmedia_mock.assert_called_once_with(task)
+ mode_mock.assert_called_once_with(task.node)
+ cleanup_iso_mock.assert_called_once_with(task)
@mock.patch.object(deploy_utils, 'is_iscsi_boot',
spec_set=True, autospec=True)
@@ -1234,7 +1031,7 @@ class IloVirtualMediaBootTestCase(test_common.BaseIloTest):
def test_validate_rescue_no_rescue_ramdisk(self):
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaisesRegex(exception.MissingParameterValue,
- 'Missing.*ilo_rescue_iso',
+ 'Some parameters were missing*',
task.driver.boot.validate_rescue, task)
diff --git a/ironic/tests/unit/drivers/modules/ilo/test_common.py b/ironic/tests/unit/drivers/modules/ilo/test_common.py
index 2877e6195..c8adbf93f 100644
--- a/ironic/tests/unit/drivers/modules/ilo/test_common.py
+++ b/ironic/tests/unit/drivers/modules/ilo/test_common.py
@@ -1079,6 +1079,21 @@ class IloCommonMethodsTestCase(BaseIloTest):
func_set_boot_device.assert_called_once_with(task,
boot_devices.CDROM)
+ @mock.patch.object(manager_utils, 'node_set_boot_device', spec_set=True,
+ autospec=True)
+ @mock.patch.object(ilo_common, 'setup_vmedia_for_boot', spec_set=True,
+ autospec=True)
+ def test_setup_vmedia_without_params(self,
+ func_setup_vmedia_for_boot,
+ func_set_boot_device):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ iso = '733d1c44-a2ea-414b-aca7-69decf20d810'
+ ilo_common.setup_vmedia(task, iso)
+ func_setup_vmedia_for_boot.assert_called_once_with(task, iso, None)
+ func_set_boot_device.assert_called_once_with(task,
+ boot_devices.CDROM)
+
@mock.patch.object(deploy_utils, 'is_secure_boot_requested', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'set_secure_boot_mode', spec_set=True,
diff --git a/releasenotes/notes/add-iso-less-vmedia-ilo-5816922c03d0fd85.yaml b/releasenotes/notes/add-iso-less-vmedia-ilo-5816922c03d0fd85.yaml
new file mode 100644
index 000000000..3d58db33f
--- /dev/null
+++ b/releasenotes/notes/add-iso-less-vmedia-ilo-5816922c03d0fd85.yaml
@@ -0,0 +1,18 @@
+---
+features:
+ - |
+ Adds functionality to the ``ilo`` and ``ilo5`` hardware types
+ by enabling virtual media boot without user-built
+ deploy/rescue/boot ISO images. Instead, ironic will
+ build necessary images out of common kernel/ramdisk
+ pair (though user needs to provide ESP image).
+ User provided deploy/rescue/boot ISO images are
+ also supported.
+ - |
+ Adds support of DHCP less deploy to ``ilo`` and ``ilo5``
+ hardware types by using the ``network_data`` property
+ on the node field, operators can now apply network
+ configuration to be embedded in iLO based Virtual
+ Media based deployment ramdisks which include networking
+ configuration enabling the deployment to operate without
+ the use of DHCP.