diff options
author | ankit <ankit.dhn31@gmail.com> | 2019-08-22 12:04:15 +0000 |
---|---|---|
committer | ankit <ankit.dhn31@gmail.com> | 2020-04-11 18:04:09 +0000 |
commit | c4d9984c51b15680ab4bfe38764942278ece5e1f (patch) | |
tree | 38b85cdbe68d3e3bf93ba7607e7b2d78e2288ab8 /ironic/drivers/modules/ilo | |
parent | 117879f80b87e3779b34ce5190c9b8141c9511da (diff) | |
download | ironic-c4d9984c51b15680ab4bfe38764942278ece5e1f.tar.gz |
Generalize ISO building for virtual media driver
Restructures code for virtual media deployment which creates
deploy/rescue/boot iso out of common kernel/ramdisk pair.
Currently hardware type ilo and redfish use this code.
Change-Id: Ifb66524c762ebe30e5c61b0c77ced65a817bbf19
Story: #2006437
Task: #36352
Diffstat (limited to 'ironic/drivers/modules/ilo')
-rw-r--r-- | ironic/drivers/modules/ilo/boot.py | 171 | ||||
-rw-r--r-- | ironic/drivers/modules/ilo/common.py | 20 | ||||
-rw-r--r-- | ironic/drivers/modules/ilo/firmware_processor.py | 3 |
3 files changed, 95 insertions, 99 deletions
diff --git a/ironic/drivers/modules/ilo/boot.py b/ironic/drivers/modules/ilo/boot.py index b6142bb8b..8c93ccc97 100644 --- a/ironic/drivers/modules/ilo/boot.py +++ b/ironic/drivers/modules/ilo/boot.py @@ -16,8 +16,6 @@ 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 @@ -40,6 +38,7 @@ from ironic.drivers.modules import deploy_utils from ironic.drivers.modules.ilo import common as ilo_common from ironic.drivers.modules import ipxe from ironic.drivers.modules import pxe +from ironic.drivers.modules import virtual_media_base LOG = logging.getLogger(__name__) @@ -47,16 +46,45 @@ METRICS = metrics_utils.get_metrics_logger(__name__) CONF = cfg.CONF -REQUIRED_PROPERTIES = { +DEPLOY_ISO_PROPERTIES = { 'ilo_deploy_iso': _("UUID (from Glance) of the deployment ISO. " "Required.") } -RESCUE_PROPERTIES = { + +DEPLOY_RAMDISK_PROPERTIES = { + 'deploy_kernel': _("URL or Glance UUID of the deployment kernel. " + "Required."), + 'deploy_ramdisk': _("URL or Glance UUID of the ramdisk that is " + "mounted at boot time. Required.") +} + +OPTIONAL_PROPERTIES = { + '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_ISO_PROPERTIES = { 'ilo_rescue_iso': _("UUID (from Glance) of the rescue ISO. Only " "required if rescue mode is being used and ironic is " "managing booting the rescue ramdisk.") } -COMMON_PROPERTIES = REQUIRED_PROPERTIES + +RESCUE_RAMDISK_PROPERTIES = { + 'rescue_kernel': _("URL or Glance UUID of the rescue kernel. " + "Required."), + 'rescue_ramdisk': _("URL or Glance UUID of the ramdisk that is " + "mounted at boot time. Required.") +} + +COMMON_PROPERTIES = DEPLOY_ISO_PROPERTIES + +KERNEL_RAMDISK_LABELS = { + 'deploy': DEPLOY_RAMDISK_PROPERTIES, + 'rescue': RESCUE_RAMDISK_PROPERTIES +} def parse_driver_info(node, mode='deploy'): @@ -77,24 +105,35 @@ 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) + for k in params_to_check} + + error_msg = (_("Error validating iLO virtual media for %(mode)s. " + "Either 'ilo_%(mode)s_iso' is missing or " + "DEPLOY_RAMDISK_PROPERTIES or RESCUE_RAMDISK_PROPERTIES " + "were missing in node's driver_info.") % {'mode': 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( + {option: info.get(option, getattr(CONF.conductor, option, None)) + for option 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): @@ -171,12 +210,6 @@ def _get_boot_iso(task, root_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 @@ -186,43 +219,15 @@ 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 + use_web_server = CONF.ilo.use_web_server_for_images + container = CONF.ilo.swift_ilo_container + + return virtual_media_base.prepare_iso_image( + task, kernel_href, ramdisk_href, + deploy_iso_href=deploy_iso_uuid, + root_uuid=root_uuid, use_web_server=use_web_server, + container=container) def _clean_up_boot_iso_for_instance(node): @@ -230,25 +235,21 @@ def _clean_up_boot_iso_for_instance(node): :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'): + boot_iso_object_name = virtual_media_base.get_iso_image_name(node) + + if CONF.ilo.use_web_server_for_images: + boot_iso_path = os.path.join( + CONF.deploy.http_root, boot_iso_object_name) + ironic_utils.unlink_without_raise(boot_iso_path) + else: 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) def _parse_deploy_info(node): @@ -284,19 +285,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): @@ -518,11 +507,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: + elif node.driver_info.get('ilo_deploy_iso'): iso = node.driver_info['ilo_deploy_iso'] - + else: + mode = deploy_utils.rescue_or_deploy_mode(node) + d_info = parse_driver_info(node, mode) + use_web_server = CONF.ilo.use_web_server_for_images + container = CONF.ilo.swift_ilo_container + iso = virtual_media_base.prepare_deploy_iso( + task, ramdisk_params, mode, d_info, + use_web_server=use_web_server, container=container) ilo_common.setup_vmedia(task, iso, ramdisk_params) @METRICS.timer('IloVirtualMediaBoot.prepare_instance') @@ -636,6 +633,10 @@ class IloVirtualMediaBoot(base.BootInterface): :returns: None :raises: IloOperationError, if some operation on iLO failed. """ + info = task.node.driver_info + + if not info.get('ilo_deploy_iso') and not info.get('ilo_rescue_iso'): + _clean_up_boot_iso_for_instance(task.node) ilo_common.cleanup_vmedia_boot(task) def _configure_vmedia_boot(self, task, root_uuid): diff --git a/ironic/drivers/modules/ilo/common.py b/ironic/drivers/modules/ilo/common.py index 62c6bbb23..eb99c9568 100644 --- a/ironic/drivers/modules/ilo/common.py +++ b/ironic/drivers/modules/ilo/common.py @@ -17,7 +17,6 @@ Common functionalities shared between different iLO modules. """ import os -import shutil import tempfile from urllib import parse as urlparse @@ -134,17 +133,12 @@ def copy_image_to_web_server(source_file_path, destination): :returns: image url after the source image is uploaded. """ + LOG.warning( + 'This method is obsolete and will be removed in next release. ' + 'Please use deploy_utils.copy_image_to_web_server() instead.') - image_url = urlparse.urljoin(CONF.deploy.http_url, destination) - image_path = os.path.join(CONF.deploy.http_root, destination) - try: - shutil.copyfile(source_file_path, image_path) - except IOError as exc: - raise exception.ImageUploadFailed(image_name=destination, - web_server=CONF.deploy.http_url, - reason=exc) - os.chmod(image_path, 0o644) - return image_url + return deploy_utils.copy_image_to_web_server(source_file_path, + destination) def remove_image_from_web_server(object_name): @@ -420,8 +414,8 @@ def _prepare_floppy_image(task, params): images.create_vfat_image(vfat_image_tmpfile, parameters=params) object_name = _get_floppy_image_name(task.node) if CONF.ilo.use_web_server_for_images: - image_url = copy_image_to_web_server(vfat_image_tmpfile, - object_name) + image_url = deploy_utils.copy_image_to_web_server( + vfat_image_tmpfile, object_name) else: image_url = copy_image_to_swift(vfat_image_tmpfile, object_name) diff --git a/ironic/drivers/modules/ilo/firmware_processor.py b/ironic/drivers/modules/ilo/firmware_processor.py index 53282311e..ca704f5b8 100644 --- a/ironic/drivers/modules/ilo/firmware_processor.py +++ b/ironic/drivers/modules/ilo/firmware_processor.py @@ -32,6 +32,7 @@ from ironic.common import exception from ironic.common.i18n import _ from ironic.common import image_service from ironic.common import swift +from ironic.drivers.modules import deploy_utils from ironic.drivers.modules.ilo import common as ilo_common # Supported components for firmware update when invoked through manual clean @@ -370,7 +371,7 @@ def _extract_fw_from_file(node, target_file): "firmware file %(firmware_image)s on web server ...", {'firmware_image': fw_image_location, 'node': node.uuid}) - fw_image_uploaded_url = ilo_common.copy_image_to_web_server( + fw_image_uploaded_url = deploy_utils.copy_image_to_web_server( fw_image_location, fw_image_filename) fw_image_location_obj.fw_image_location = fw_image_uploaded_url |