Adding changes for iso less vmedia support
This commit allows virtual media deployment/rescue using kernel/ramdisk pair by creating iso on the fly for ilo and ilo5 hardware types. Also it adds support of dhcp less deploy to ilo and ilo5 hardware type. Change-Id: I08e37a9f5268c15ba954b34ad706b900e5430da6 Story: #2006691 Task: #40893
This commit is contained in:
parent
484dcd5b60
commit
b4fafd8878
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
||||
d_info = {option: info.get(option)
|
||||
for option in params_to_check}
|
||||
|
||||
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)
|
||||
"parameters were missing in node's driver_info.") % mode)
|
||||
deploy_utils.check_for_missing_params(d_info, error_msg)
|
||||
|
||||
d_info.update(
|
||||
{k: info.get(k, getattr(CONF.conductor, k.replace('ilo_', ''), None))
|
||||
for k in OPTIONAL_PROPERTIES})
|
||||
|
||||
return d_info
|
||||
|
||||
|
||||
def _get_boot_iso_object_name(node):
|
||||
"""Returns the boot iso object name for a given node.
|
||||
|
||||
:param node: the node for which object name is to be provided.
|
||||
"""
|
||||
return "boot-%s" % node.uuid
|
||||
|
||||
|
||||
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 "
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
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_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')
|
||||
|
||||
@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):
|
||||
@mock.patch.object(ilo_boot, 'parse_driver_info', spec_set=True,
|
||||
autospec=True)
|
||||
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:
|
||||
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,
|
||||
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
|
||||
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)
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user