Beispiel #1
0
    def prepare(self, task):
        """Prepare the deployment environment for this task's node.

        Generates the TFTP configuration for PXE-booting both the deployment
        and user images, fetches the TFTP image from Glance and add it to the
        local cache.

        :param task: a TaskManager instance containing the node to act on.
        """
        node = task.node
        # TODO(deva): optimize this if rerun on existing files
        if CONF.pxe.ipxe_enabled:
            # Copy the iPXE boot script to HTTP root directory
            bootfile_path = os.path.join(CONF.pxe.http_root,
                                   os.path.basename(CONF.pxe.ipxe_boot_script))
            shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path)
        pxe_info = _get_image_info(node, task.context)
        pxe_options = _build_pxe_config_options(node, pxe_info,
                                                task.context)

        if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
            pxe_config_template = CONF.pxe.uefi_pxe_config_template
        else:
            pxe_config_template = CONF.pxe.pxe_config_template

        pxe_utils.create_pxe_config(task, pxe_options,
                                    pxe_config_template)

        # FIXME(lucasagomes): If it's local boot we should not cache
        # the image kernel and ramdisk (Or even require it).
        _cache_ramdisk_kernel(task.context, node, pxe_info)

        # NOTE(deva): prepare may be called from conductor._do_takeover
        # in which case, it may need to regenerate the PXE config file for an
        # already-active deployment.
        if node.provision_state == states.ACTIVE:
            # this should have been stashed when the deploy was done
            # but let's guard, just in case it's missing
            iwdi = node.driver_internal_info.get('is_whole_disk_image')
            try:
                root_uuid_or_disk_id = node.driver_internal_info[
                                                'root_uuid_or_disk_id']
            except KeyError:
                if not iwdi:
                    LOG.warn(_LW("The UUID for the root partition can't be "
                             "found, unable to switch the pxe config from "
                             "deployment mode to service (boot) mode for node "
                             "%(node)s"), {"node": node.uuid})
                else:
                    LOG.warn(_LW("The disk id for the whole disk image can't "
                             "be found, unable to switch the pxe config from "
                             "deployment mode to service (boot) mode for "
                             "node %(node)s"), {"node": node.uuid})
            else:
                pxe_config_path = pxe_utils.get_pxe_config_file_path(
                    node.uuid)
                deploy_utils.switch_pxe_config(
                    pxe_config_path, root_uuid_or_disk_id,
                    deploy_utils.get_boot_mode_for_deploy(node),
                    iwdi)
Beispiel #2
0
    def prepare(self, task):
        """Prepare the deployment environment for this task's node.

        Generates the TFTP configuration for PXE-booting both the deployment
        and user images, fetches the TFTP image from Glance and add it to the
        local cache.

        :param task: a TaskManager instance containing the node to act on.
        """
        node = task.node
        # TODO(deva): optimize this if rerun on existing files
        if CONF.pxe.ipxe_enabled:
            # Copy the iPXE boot script to HTTP root directory
            bootfile_path = os.path.join(
                CONF.pxe.http_root,
                os.path.basename(CONF.pxe.ipxe_boot_script))
            shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path)
        pxe_info = _get_image_info(node, task.context)
        pxe_options = _build_pxe_config_options(node, pxe_info, task.context)

        if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
            pxe_config_template = CONF.pxe.uefi_pxe_config_template
        else:
            pxe_config_template = CONF.pxe.pxe_config_template

        pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template)

        # FIXME(lucasagomes): If it's local boot we should not cache
        # the image kernel and ramdisk (Or even require it).
        _cache_ramdisk_kernel(task.context, node, pxe_info)

        # NOTE(deva): prepare may be called from conductor._do_takeover
        # in which case, it may need to regenerate the PXE config file for an
        # already-active deployment.
        if node.provision_state == states.ACTIVE:
            # this should have been stashed when the deploy was done
            # but let's guard, just in case it's missing
            iwdi = node.driver_internal_info.get('is_whole_disk_image')
            try:
                root_uuid_or_disk_id = (
                    node.driver_internal_info['root_uuid_or_disk_id'])
            except KeyError:
                if not iwdi:
                    LOG.warn(
                        _LW("The UUID for the root partition can't be "
                            "found, unable to switch the pxe config from "
                            "deployment mode to service (boot) mode for node "
                            "%(node)s"), {"node": node.uuid})
                else:
                    LOG.warn(
                        _LW("The disk id for the whole disk image can't "
                            "be found, unable to switch the pxe config from "
                            "deployment mode to service (boot) mode for "
                            "node %(node)s"), {"node": node.uuid})
            else:
                pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
                deploy_utils.switch_pxe_config(
                    pxe_config_path, root_uuid_or_disk_id,
                    deploy_utils.get_boot_mode_for_deploy(node), iwdi,
                    deploy_utils.is_trusted_boot_requested(node))
Beispiel #3
0
def _prepare_node_for_deploy(task):
    """Common preparatory steps for all iLO drivers.

    This method performs common preparatory steps required for all drivers.
    1. Power off node
    2. Disables secure boot, if it is in enabled state.
    3. Updates boot_mode capability to 'uefi' if secure boot is requested.
    4. Changes boot mode of the node if secure boot is disabled currently.

    :param task: a TaskManager instance containing the node to act on.
    :raises: IloOperationError, if some operation on iLO failed.
    """
    manager_utils.node_power_action(task, states.POWER_OFF)

    # Boot mode can be changed only if secure boot is in disabled state.
    # secure boot and boot mode cannot be changed together.
    change_boot_mode = True

    # Disable secure boot on the node if it is in enabled state.
    if _disable_secure_boot(task):
        change_boot_mode = False

    if change_boot_mode:
        ilo_common.update_boot_mode(task)
    else:
        # Need to update boot mode that will be used during deploy, if one is
        # not provided.
        # Since secure boot was disabled, we are in 'uefi' boot mode.
        if deploy_utils.get_boot_mode_for_deploy(task.node) is None:
            instance_info = task.node.instance_info
            instance_info['deploy_boot_mode'] = 'uefi'
            task.node.instance_info = instance_info
            task.node.save()
Beispiel #4
0
def create_pxe_config(task, pxe_options, template=None):
    """Generate PXE configuration file and MAC address links for it.

    This method will generate the PXE configuration file for the task's
    node under a directory named with the UUID of that node. For each
    MAC address (port) of that node, a symlink for the configuration file
    will be created under the PXE configuration directory, so regardless
    of which port boots first they'll get the same PXE configuration.

    :param task: A TaskManager instance.
    :param pxe_options: A dictionary with the PXE configuration
        parameters.
    :param template: The PXE configuration template. If no template is
        given the CONF.pxe.pxe_config_template will be used.

    """
    LOG.debug("Building PXE config for node %s", task.node.uuid)

    if template is None:
        template = CONF.pxe.pxe_config_template

    _ensure_config_dirs_exist(task.node.uuid)

    pxe_config_file_path = get_pxe_config_file_path(task.node.uuid)
    pxe_config = _build_pxe_config(pxe_options, template)
    utils.write_to_file(pxe_config_file_path, pxe_config)

    if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi':
        _link_ip_address_pxe_configs(task)
    else:
        _link_mac_pxe_configs(task)
Beispiel #5
0
def clean_up_pxe_config(task):
    """Clean up the TFTP environment for the task's node.

    :param task: A TaskManager instance.

    """
    LOG.debug("Cleaning up PXE config for node %s", task.node.uuid)

    if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi':
        api = dhcp_factory.DHCPFactory().provider
        ip_addresses = api.get_ip_addresses(task)
        if not ip_addresses:
            return

        for port_ip_address in ip_addresses:
            try:
                ip_address_path = _get_pxe_ip_address_path(port_ip_address)
            except exception.InvalidIPv4Address:
                continue
            utils.unlink_without_raise(ip_address_path)
    else:
        for mac in driver_utils.get_node_mac_addresses(task):
            utils.unlink_without_raise(_get_pxe_mac_path(mac))

    utils.rmtree_without_raise(os.path.join(get_root_dir(),
                                            task.node.uuid))
Beispiel #6
0
def create_pxe_config(task, pxe_options, template=None):
    """Generate PXE configuration file and MAC address links for it.

    This method will generate the PXE configuration file for the task's
    node under a directory named with the UUID of that node. For each
    MAC address (port) of that node, a symlink for the configuration file
    will be created under the PXE configuration directory, so regardless
    of which port boots first they'll get the same PXE configuration.

    :param task: A TaskManager instance.
    :param pxe_options: A dictionary with the PXE configuration
        parameters.
    :param template: The PXE configuration template. If no template is
        given the CONF.pxe.pxe_config_template will be used.

    """
    LOG.debug("Building PXE config for node %s", task.node.uuid)

    if template is None:
        template = CONF.pxe.pxe_config_template

    _ensure_config_dirs_exist(task.node.uuid)

    pxe_config_file_path = get_pxe_config_file_path(task.node.uuid)
    pxe_config = _build_pxe_config(pxe_options, template)
    utils.write_to_file(pxe_config_file_path, pxe_config)

    if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi':
        _link_ip_address_pxe_configs(task)
    else:
        _link_mac_pxe_configs(task)
Beispiel #7
0
def _prepare_node_for_deploy(task):
    """Common preparatory steps for all iLO drivers.

    This method performs common preparatory steps required for all drivers.
    1. Power off node
    2. Disables secure boot, if it is in enabled state.
    3. Updates boot_mode capability to 'uefi' if secure boot is requested.
    4. Changes boot mode of the node if secure boot is disabled currently.

    :param task: a TaskManager instance containing the node to act on.
    :raises: IloOperationError, if some operation on iLO failed.
    """
    manager_utils.node_power_action(task, states.POWER_OFF)

    # Boot mode can be changed only if secure boot is in disabled state.
    # secure boot and boot mode cannot be changed together.
    change_boot_mode = True

    # Disable secure boot on the node if it is in enabled state.
    if _disable_secure_boot(task):
        change_boot_mode = False

    if change_boot_mode:
        ilo_common.update_boot_mode(task)
    else:
        # Need to update boot mode that will be used during deploy, if one is
        # not provided.
        # Since secure boot was disabled, we are in 'uefi' boot mode.
        if deploy_utils.get_boot_mode_for_deploy(task.node) is None:
            instance_info = task.node.instance_info
            instance_info['deploy_boot_mode'] = 'uefi'
            task.node.instance_info = instance_info
            task.node.save()
Beispiel #8
0
def create_pxe_config(task, pxe_options, template=None):
    """Generate PXE configuration file and MAC address links for it.

    This method will generate the PXE configuration file for the task's
    node under a directory named with the UUID of that node. For each
    MAC address or DHCP IP address (port) of that node, a symlink for
    the configuration file will be created under the PXE configuration
    directory, so regardless of which port boots first they'll get the
    same PXE configuration.
    If elilo is the bootloader in use, then its configuration file will
    be created based on hex form of DHCP IP address.
    If grub2 bootloader is in use, then its configuration will be created
    based on DHCP IP address in the form nn.nn.nn.nn.

    :param task: A TaskManager instance.
    :param pxe_options: A dictionary with the PXE configuration
        parameters.
    :param template: The PXE configuration template. If no template is
        given the node specific template will be used.

    """
    LOG.debug("Building PXE config for node %s", task.node.uuid)

    if template is None:
        template = deploy_utils.get_pxe_config_template(task.node)

    _ensure_config_dirs_exist(task.node.uuid)

    pxe_config_file_path = get_pxe_config_file_path(task.node.uuid)
    is_uefi_boot_mode = (deploy_utils.get_boot_mode_for_deploy(task.node) ==
                         'uefi')

    # grub bootloader panics with '{}' around any of its tags in its
    # config file. To overcome that 'ROOT' and 'DISK_IDENTIFIER' are enclosed
    # with '(' and ')' in uefi boot mode.
    # These changes do not have any impact on elilo bootloader.
    hex_form = True
    if is_uefi_boot_mode and utils.is_regex_string_in_file(template,
                                                           '^menuentry'):
        hex_form = False
        pxe_config_root_tag = '(( ROOT ))'
        pxe_config_disk_ident = '(( DISK_IDENTIFIER ))'
    else:
        # TODO(stendulker): We should use '(' ')' as the delimiters for all our
        # config files so that we do not need special handling for each of the
        # bootloaders. Should be removed once the Mitaka release starts.
        pxe_config_root_tag = '{{ ROOT }}'
        pxe_config_disk_ident = '{{ DISK_IDENTIFIER }}'

    params = {'pxe_options': pxe_options,
              'ROOT': pxe_config_root_tag,
              'DISK_IDENTIFIER': pxe_config_disk_ident}

    pxe_config = utils.render_template(template, params)
    utils.write_to_file(pxe_config_file_path, pxe_config)

    if is_uefi_boot_mode and not CONF.pxe.ipxe_enabled:
        _link_ip_address_pxe_configs(task, hex_form)
    else:
        _link_mac_pxe_configs(task)
Beispiel #9
0
def clean_up_pxe_config(task):
    """Clean up the TFTP environment for the task's node.

    :param task: A TaskManager instance.

    """
    LOG.debug("Cleaning up PXE config for node %s", task.node.uuid)

    if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi':
        api = dhcp_factory.DHCPFactory().provider
        ip_addresses = api.get_ip_addresses(task)
        if not ip_addresses:
            return

        for port_ip_address in ip_addresses:
            try:
                ip_address_path = _get_pxe_ip_address_path(port_ip_address)
            except exception.InvalidIPv4Address:
                continue
            utils.unlink_without_raise(ip_address_path)
    else:
        for mac in driver_utils.get_node_mac_addresses(task):
            utils.unlink_without_raise(_get_pxe_mac_path(mac))

    utils.rmtree_without_raise(os.path.join(get_root_dir(), task.node.uuid))
Beispiel #10
0
def clean_up_pxe_config(task):
    """Clean up the TFTP environment for the task's node.

    :param task: A TaskManager instance.

    """
    LOG.debug("Cleaning up PXE config for node %s", task.node.uuid)

    if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi':
        api = dhcp_factory.DHCPFactory().provider
        ip_addresses = api.get_ip_addresses(task)
        if not ip_addresses:
            return

        for port_ip_address in ip_addresses:
            try:
                ip_address_path = _get_pxe_ip_address_path(port_ip_address)
            except exception.InvalidIPv4Address:
                continue
            utils.unlink_without_raise(ip_address_path)
    else:
        for mac in driver_utils.get_node_mac_addresses(task):
            utils.unlink_without_raise(_get_pxe_mac_path(mac))
            # TODO(lucasagomes): Backward compatibility with :hexraw,
            # to be removed in M.
            # see: https://bugs.launchpad.net/ironic/+bug/1441710
            if CONF.pxe.ipxe_enabled:
                utils.unlink_without_raise(_get_pxe_mac_path(mac,
                                                             delimiter=''))

    utils.rmtree_without_raise(os.path.join(get_root_dir(), task.node.uuid))
Beispiel #11
0
def clean_up_pxe_config(task):
    """Clean up the TFTP environment for the task's node.

    :param task: A TaskManager instance.

    """
    LOG.debug("Cleaning up PXE config for node %s", task.node.uuid)

    is_uefi_boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node) == "uefi"
    if is_uefi_boot_mode and not CONF.pxe.ipxe_enabled:
        api = dhcp_factory.DHCPFactory().provider
        ip_addresses = api.get_ip_addresses(task)
        if not ip_addresses:
            return

        for port_ip_address in ip_addresses:
            try:
                # Get xx.xx.xx.xx based grub config file
                ip_address_path = _get_pxe_ip_address_path(port_ip_address, False)
                # Get 0AOAOAOA based elilo config file
                hex_ip_path = _get_pxe_ip_address_path(port_ip_address, True)
            except exception.InvalidIPv4Address:
                continue
            # Cleaning up config files created for grub2.
            ironic_utils.unlink_without_raise(ip_address_path)
            # Cleaning up config files created for elilo.
            ironic_utils.unlink_without_raise(hex_ip_path)
    else:
        for port in task.ports:
            client_id = port.extra.get("client-id")
            ironic_utils.unlink_without_raise(_get_pxe_mac_path(port.address, client_id=client_id))

    utils.rmtree_without_raise(os.path.join(get_root_dir(), task.node.uuid))
Beispiel #12
0
def clean_up_pxe_config(task):
    """Clean up the TFTP environment for the task's node.

    :param task: A TaskManager instance.

    """
    LOG.debug("Cleaning up PXE config for node %s", task.node.uuid)

    is_uefi_boot_mode = (deploy_utils.get_boot_mode_for_deploy(
        task.node) == 'uefi')
    if is_uefi_boot_mode and not CONF.pxe.ipxe_enabled:
        api = dhcp_factory.DHCPFactory().provider
        ip_addresses = api.get_ip_addresses(task)
        if not ip_addresses:
            return

        for port_ip_address in ip_addresses:
            try:
                # Get xx.xx.xx.xx based grub config file
                ip_address_path = _get_pxe_ip_address_path(
                    port_ip_address, False)
                # Get 0AOAOAOA based elilo config file
                hex_ip_path = _get_pxe_ip_address_path(port_ip_address, True)
            except exception.InvalidIPv4Address:
                continue
            # Cleaning up config files created for grub2.
            ironic_utils.unlink_without_raise(ip_address_path)
            # Cleaning up config files created for elilo.
            ironic_utils.unlink_without_raise(hex_ip_path)
    else:
        for mac in driver_utils.get_node_mac_addresses(task):
            ironic_utils.unlink_without_raise(_get_pxe_mac_path(mac))

    utils.rmtree_without_raise(os.path.join(get_root_dir(), task.node.uuid))
Beispiel #13
0
def clean_up_pxe_config(task):
    """Clean up the TFTP environment for the task's node.

    :param task: A TaskManager instance.

    """
    LOG.debug("Cleaning up PXE config for node %s", task.node.uuid)

    if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi':
        api = dhcp_factory.DHCPFactory().provider
        ip_addresses = api.get_ip_addresses(task)
        if not ip_addresses:
            return

        for port_ip_address in ip_addresses:
            try:
                ip_address_path = _get_pxe_ip_address_path(port_ip_address)
            except exception.InvalidIPv4Address:
                continue
            utils.unlink_without_raise(ip_address_path)
    else:
        for mac in driver_utils.get_node_mac_addresses(task):
            utils.unlink_without_raise(_get_pxe_mac_path(mac))
            # TODO(lucasagomes): Backward compatibility with :hexraw,
            # to be removed in M.
            # see: https://bugs.launchpad.net/ironic/+bug/1441710
            if CONF.pxe.ipxe_enabled:
                utils.unlink_without_raise(_get_pxe_mac_path(mac,
                                           delimiter=''))

    utils.rmtree_without_raise(os.path.join(get_root_dir(),
                                            task.node.uuid))
Beispiel #14
0
def _prepare_boot_iso(task, root_uuid):
    """Prepare a boot ISO to boot the node.

    :param task: a TaskManager instance containing the node to act on.
    :param root_uuid: the uuid of the root partition.
    :raises: MissingParameterValue, if any of the required parameters are
        missing.
    :raises: InvalidParameterValue, if any of the parameters have invalid
        value.
    :raises: ImageCreationFailed, if creating boot ISO
       for BIOS boot_mode failed.
    """
    deploy_info = _parse_deploy_info(task.node)
    driver_internal_info = task.node.driver_internal_info

    # fetch boot iso
    if deploy_info.get('irmc_boot_iso'):
        boot_iso_href = deploy_info['irmc_boot_iso']
        if service_utils.is_image_href_ordinary_file_name(boot_iso_href):
            driver_internal_info['irmc_boot_iso'] = boot_iso_href
        else:
            boot_iso_filename = _get_boot_iso_name(task.node)
            boot_iso_fullpathname = os.path.join(
                CONF.irmc.remote_image_share_root, boot_iso_filename)
            images.fetch(task.context, boot_iso_href, boot_iso_fullpathname)

            driver_internal_info['irmc_boot_iso'] = boot_iso_filename

    # create boot iso
    else:
        image_href = deploy_info['image_source']
        image_props = ['kernel_id', 'ramdisk_id']
        image_properties = images.get_image_properties(
            task.context, image_href, image_props)
        kernel_href = (task.node.instance_info.get('kernel') or
                       image_properties['kernel_id'])
        ramdisk_href = (task.node.instance_info.get('ramdisk') or
                        image_properties['ramdisk_id'])

        deploy_iso_filename = _get_deploy_iso_name(task.node)
        deploy_iso = ('file://' + os.path.join(
            CONF.irmc.remote_image_share_root, deploy_iso_filename))
        boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node)
        kernel_params = CONF.pxe.pxe_append_params

        boot_iso_filename = _get_boot_iso_name(task.node)
        boot_iso_fullpathname = os.path.join(
            CONF.irmc.remote_image_share_root, boot_iso_filename)

        images.create_boot_iso(task.context, boot_iso_fullpathname,
                               kernel_href, ramdisk_href,
                               deploy_iso, root_uuid,
                               kernel_params, boot_mode)

        driver_internal_info['irmc_boot_iso'] = boot_iso_filename

    # save driver_internal_info['irmc_boot_iso']
    task.node.driver_internal_info = driver_internal_info
    task.node.save()
Beispiel #15
0
    def pass_deploy_info(self, task, **kwargs):
        """Continues the deployment of baremetal node over iSCSI.

        This method continues the deployment of the baremetal node over iSCSI
        from where the deployment ramdisk has left off.

        :param task: a TaskManager instance containing the node to act on.
        :param kwargs: kwargs for performing iscsi deployment.
        :raises: InvalidState
        """
        node = task.node
        task.process_event('resume')

        _destroy_token_file(node)
        is_whole_disk_image = node.driver_internal_info['is_whole_disk_image']
        uuid_dict = iscsi_deploy.continue_deploy(task, **kwargs)
        root_uuid_or_disk_id = uuid_dict.get(
            'root uuid', uuid_dict.get('disk identifier'))

        # save the node's root disk UUID so that another conductor could
        # rebuild the PXE config file. Due to a shortcoming in Nova objects,
        # we have to assign to node.driver_internal_info so the node knows it
        # has changed.
        driver_internal_info = node.driver_internal_info
        driver_internal_info['root_uuid_or_disk_id'] = root_uuid_or_disk_id
        node.driver_internal_info = driver_internal_info
        node.save()

        try:
            if iscsi_deploy.get_boot_option(node) == "local":
                deploy_utils.try_set_boot_device(task, boot_devices.DISK)

                # If it's going to boot from the local disk, get rid of
                # the PXE configuration files used for the deployment
                pxe_utils.clean_up_pxe_config(task)

                # Ask the ramdisk to install bootloader and
                # wait for the call-back through the vendor passthru
                # 'pass_bootloader_install_info', if it's not a
                # whole disk image.
                if not is_whole_disk_image:
                    deploy_utils.notify_ramdisk_to_proceed(kwargs['address'])
                    task.process_event('wait')
                    return
            else:
                pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
                boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
                deploy_utils.switch_pxe_config(pxe_config_path,
                                               root_uuid_or_disk_id,
                                               boot_mode, is_whole_disk_image)

        except Exception as e:
            LOG.error(_LE('Deploy failed for instance %(instance)s. '
                          'Error: %(error)s'),
                      {'instance': node.instance_uuid, 'error': e})
            msg = _('Failed to continue iSCSI deployment.')
            deploy_utils.set_failed_state(task, msg)
        else:
            iscsi_deploy.finish_deploy(task, kwargs.get('address'))
Beispiel #16
0
def _prepare_boot_iso(task, root_uuid):
    """Prepare a boot ISO to boot the node.

    :param task: a TaskManager instance containing the node to act on.
    :param root_uuid: the uuid of the root partition.
    :raises: MissingParameterValue, if any of the required parameters are
        missing.
    :raises: InvalidParameterValue, if any of the parameters have invalid
        value.
    :raises: ImageCreationFailed, if creating boot ISO
       for BIOS boot_mode failed.
    """
    deploy_info = _parse_deploy_info(task.node)
    driver_internal_info = task.node.driver_internal_info

    # fetch boot iso
    if deploy_info.get("irmc_boot_iso"):
        boot_iso_href = deploy_info["irmc_boot_iso"]
        if service_utils.is_image_href_ordinary_file_name(boot_iso_href):
            driver_internal_info["irmc_boot_iso"] = boot_iso_href
        else:
            boot_iso_filename = _get_boot_iso_name(task.node)
            boot_iso_fullpathname = os.path.join(CONF.irmc.remote_image_share_root, boot_iso_filename)
            images.fetch(task.context, boot_iso_href, boot_iso_fullpathname)

            driver_internal_info["irmc_boot_iso"] = boot_iso_filename

    # create boot iso
    else:
        image_href = deploy_info["image_source"]
        image_props = ["kernel_id", "ramdisk_id"]
        image_properties = images.get_image_properties(task.context, image_href, image_props)
        kernel_href = task.node.instance_info.get("kernel") or image_properties["kernel_id"]
        ramdisk_href = task.node.instance_info.get("ramdisk") or image_properties["ramdisk_id"]

        deploy_iso_filename = _get_deploy_iso_name(task.node)
        deploy_iso = "file://" + os.path.join(CONF.irmc.remote_image_share_root, deploy_iso_filename)
        boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node)
        kernel_params = CONF.pxe.pxe_append_params

        boot_iso_filename = _get_boot_iso_name(task.node)
        boot_iso_fullpathname = os.path.join(CONF.irmc.remote_image_share_root, boot_iso_filename)

        images.create_boot_iso(
            task.context,
            boot_iso_fullpathname,
            kernel_href,
            ramdisk_href,
            deploy_iso,
            root_uuid,
            kernel_params,
            boot_mode,
        )

        driver_internal_info["irmc_boot_iso"] = boot_iso_filename

    # save driver_internal_info['irmc_boot_iso']
    task.node.driver_internal_info = driver_internal_info
    task.node.save()
Beispiel #17
0
def update_boot_mode(task):
    """Update instance_info with boot mode to be used for deploy.

    This method updates instance_info with boot mode to be used for
    deploy if node properties['capabilities'] do not have boot_mode.
    It sets the boot mode on the node.

    :param task: Task object.
    :raises: IloOperationError if setting boot mode failed.
    """

    node = task.node
    boot_mode = deploy_utils.get_boot_mode_for_deploy(node)

    if boot_mode is not None:
        LOG.debug("Node %(uuid)s boot mode is being set to %(boot_mode)s", {
            'uuid': node.uuid,
            'boot_mode': boot_mode
        })
        set_boot_mode(node, boot_mode)
        return

    LOG.debug("Check pending boot mode for node %s.", node.uuid)
    ilo_object = get_ilo_object(node)

    try:
        boot_mode = ilo_object.get_pending_boot_mode()
    except ilo_error.IloCommandNotSupportedError:
        boot_mode = 'legacy'

    if boot_mode != 'UNKNOWN':
        boot_mode = BOOT_MODE_ILO_TO_GENERIC[boot_mode.lower()]

    if boot_mode == 'UNKNOWN':
        # NOTE(faizan) ILO will return this in remote cases and mostly on
        # the nodes which supports UEFI. Such nodes mostly comes with UEFI
        # as default boot mode. So we will try setting bootmode to UEFI
        # and if it fails then we fall back to BIOS boot mode.
        try:
            boot_mode = 'uefi'
            ilo_object.set_pending_boot_mode(
                BOOT_MODE_GENERIC_TO_ILO[boot_mode].upper())
        except ilo_error.IloError as ilo_exception:
            operation = _("Setting %s as boot mode") % boot_mode
            raise exception.IloOperationError(operation=operation,
                                              error=ilo_exception)

        LOG.debug(
            "Node %(uuid)s boot mode is being set to %(boot_mode)s "
            "as pending boot mode is unknown.", {
                'uuid': node.uuid,
                'boot_mode': boot_mode
            })

    instance_info = node.instance_info
    instance_info['deploy_boot_mode'] = boot_mode
    node.instance_info = instance_info
    node.save()
Beispiel #18
0
    def prepare_ramdisk(self, task, ramdisk_params):
        """Prepares the boot of Ironic ramdisk using PXE.

        This method prepares the boot of the deploy kernel/ramdisk after
        reading relevant information from the node's driver_info and
        instance_info.

        :param task: a task from TaskManager.
        :param ramdisk_params: the parameters to be passed to the ramdisk.
            pxe driver passes these parameters as kernel command-line
            arguments.
        :returns: None
        :raises: MissingParameterValue, if some information is missing in
            node's driver_info or instance_info.
        :raises: InvalidParameterValue, if some information provided is
            invalid.
        :raises: IronicException, if some power or set boot boot device
            operation failed on the node.
        """
        node = task.node

        if CONF.pxe.ipxe_enabled:
            # Copy the iPXE boot script to HTTP root directory
            bootfile_path = os.path.join(
                CONF.deploy.http_root,
                os.path.basename(CONF.pxe.ipxe_boot_script))
            if (not os.path.isfile(bootfile_path) or
                    not filecmp.cmp(CONF.pxe.ipxe_boot_script, bootfile_path)):
                shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path)

        dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
        provider = dhcp_factory.DHCPFactory()
        provider.update_dhcp(task, dhcp_opts)

        pxe_info = _get_deploy_image_info(node)

        # NODE: Try to validate and fetch instance images only
        # if we are in DEPLOYING state.
        if node.provision_state == states.DEPLOYING:
            pxe_info.update(_get_instance_image_info(node, task.context))

        pxe_options = _build_pxe_config_options(task, pxe_info)
        pxe_options.update(ramdisk_params)

        if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
            pxe_config_template = CONF.pxe.uefi_pxe_config_template
        else:
            pxe_config_template = CONF.pxe.pxe_config_template

        pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template)
        deploy_utils.try_set_boot_device(task, boot_devices.PXE)

        if CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_use_swift:
            pxe_info.pop('deploy_kernel', None)
            pxe_info.pop('deploy_ramdisk', None)
        if pxe_info:
            _cache_ramdisk_kernel(task.context, node, pxe_info)
Beispiel #19
0
    def validate(self, task):
        """Validate the PXE-specific info for booting deploy/instance images.

        This method validates the PXE-specific info for booting the
        ramdisk and instance on the node.  If invalid, raises an
        exception; otherwise returns None.

        :param task: a task from TaskManager.
        :returns: None
        :raises: InvalidParameterValue, if some parameters are invalid.
        :raises: MissingParameterValue, if some required parameters are
            missing.
        """
        node = task.node

        if not driver_utils.get_node_mac_addresses(task):
            raise exception.MissingParameterValue(
                _("Node %s does not have any port associated with it.")
                % node.uuid)

        # Get the boot_mode capability value.
        boot_mode = deploy_utils.get_boot_mode_for_deploy(node)

        if CONF.pxe.ipxe_enabled:
            if (not CONF.deploy.http_url or
                not CONF.deploy.http_root):
                raise exception.MissingParameterValue(_(
                    "iPXE boot is enabled but no HTTP URL or HTTP "
                    "root was specified."))
            # iPXE and UEFI should not be configured together.
            if boot_mode == 'uefi':
                LOG.error(_LE("UEFI boot mode is not supported with "
                              "iPXE boot enabled."))
                raise exception.InvalidParameterValue(_(
                    "Conflict: iPXE is enabled, but cannot be used with node"
                    "%(node_uuid)s configured to use UEFI boot") %
                    {'node_uuid': node.uuid})

        if boot_mode == 'uefi':
            validate_boot_option_for_uefi(node)

        # Check the trusted_boot capabilities value.
        deploy_utils.validate_capabilities(node)
        if deploy_utils.is_trusted_boot_requested(node):
            # Check if 'boot_option' and boot mode is compatible with
            # trusted boot.
            validate_boot_parameters_for_trusted_boot(node)

        _parse_driver_info(node)
        d_info = _parse_instance_info(node)
        if node.driver_internal_info.get('is_whole_disk_image'):
            props = []
        elif service_utils.is_glance_image(d_info['image_source']):
            props = ['kernel_id', 'ramdisk_id']
        else:
            props = ['kernel', 'ramdisk']
        deploy_utils.validate_image_properties(task.context, d_info, props)
Beispiel #20
0
    def prepare_instance(self, task):
        """Prepares the boot of instance.

        This method prepares the boot of the instance after reading
        relevant information from the node's instance_info. In case of netboot,
        it updates the dhcp entries and switches the PXE config. In case of
        localboot, it cleans up the PXE config.

        :param task: a task from TaskManager.
        :returns: None
        """
        node = task.node
        boot_option = deploy_utils.get_boot_option(node)

        if boot_option != "local":
            # Make sure that the instance kernel/ramdisk is cached.
            # This is for the takeover scenario for active nodes.
            instance_image_info = _get_instance_image_info(
                task.node, task.context)
            _cache_ramdisk_kernel(task.context, task.node, instance_image_info)

            # If it's going to PXE boot we need to update the DHCP server
            dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
            provider = dhcp_factory.DHCPFactory()
            provider.update_dhcp(task, dhcp_opts)

            iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
            try:
                root_uuid_or_disk_id = task.node.driver_internal_info[
                    'root_uuid_or_disk_id']
            except KeyError:
                if not iwdi:
                    LOG.warn(
                        _LW("The UUID for the root partition can't be "
                            "found, unable to switch the pxe config from "
                            "deployment mode to service (boot) mode for "
                            "node %(node)s"), {"node": task.node.uuid})
                else:
                    LOG.warn(
                        _LW("The disk id for the whole disk image can't "
                            "be found, unable to switch the pxe config "
                            "from deployment mode to service (boot) mode "
                            "for node %(node)s"), {"node": task.node.uuid})
            else:
                pxe_config_path = pxe_utils.get_pxe_config_file_path(
                    task.node.uuid)
                deploy_utils.switch_pxe_config(
                    pxe_config_path, root_uuid_or_disk_id,
                    deploy_utils.get_boot_mode_for_deploy(node), iwdi,
                    deploy_utils.is_trusted_boot_requested(node))

        else:
            # If it's going to boot from the local disk, we don't need
            # PXE config files. They still need to be generated as part
            # of the prepare() because the deployment does PXE boot the
            # deploy ramdisk
            pxe_utils.clean_up_pxe_config(task)
Beispiel #21
0
    def prepare_instance(self, task):
        """Prepares the boot of instance.

        This method prepares the boot of the instance after reading
        relevant information from the node's instance_info. In case of netboot,
        it updates the dhcp entries and switches the PXE config. In case of
        localboot, it cleans up the PXE config.

        :param task: a task from TaskManager.
        :returns: None
        """
        node = task.node
        boot_option = deploy_utils.get_boot_option(node)

        if boot_option != "local":
            # Make sure that the instance kernel/ramdisk is cached.
            # This is for the takeover scenario for active nodes.
            instance_image_info = _get_instance_image_info(
                task.node, task.context)
            _cache_ramdisk_kernel(task.context, task.node, instance_image_info)

            # If it's going to PXE boot we need to update the DHCP server
            dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
            provider = dhcp_factory.DHCPFactory()
            provider.update_dhcp(task, dhcp_opts)

            iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
            try:
                root_uuid_or_disk_id = task.node.driver_internal_info[
                    'root_uuid_or_disk_id'
                ]
            except KeyError:
                if not iwdi:
                    LOG.warn(_LW("The UUID for the root partition can't be "
                                 "found, unable to switch the pxe config from "
                                 "deployment mode to service (boot) mode for "
                                 "node %(node)s"), {"node": task.node.uuid})
                else:
                    LOG.warn(_LW("The disk id for the whole disk image can't "
                                 "be found, unable to switch the pxe config "
                                 "from deployment mode to service (boot) mode "
                                 "for node %(node)s"),
                             {"node": task.node.uuid})
            else:
                pxe_config_path = pxe_utils.get_pxe_config_file_path(
                    task.node.uuid)
                deploy_utils.switch_pxe_config(
                    pxe_config_path, root_uuid_or_disk_id,
                    deploy_utils.get_boot_mode_for_deploy(node),
                    iwdi, deploy_utils.is_trusted_boot_requested(node))

        else:
            # If it's going to boot from the local disk, we don't need
            # PXE config files. They still need to be generated as part
            # of the prepare() because the deployment does PXE boot the
            # deploy ramdisk
            pxe_utils.clean_up_pxe_config(task)
Beispiel #22
0
    def validate(self, task):
        """Validate the PXE-specific info for booting deploy/instance images.

        This method validates the PXE-specific info for booting the
        ramdisk and instance on the node.  If invalid, raises an
        exception; otherwise returns None.

        :param task: a task from TaskManager.
        :returns: None
        :raises: InvalidParameterValue, if some parameters are invalid.
        :raises: MissingParameterValue, if some required parameters are
            missing.
        """
        node = task.node

        if not driver_utils.get_node_mac_addresses(task):
            raise exception.MissingParameterValue(
                _("Node %s does not have any port associated with it.")
                % node.uuid)

        # Get the boot_mode capability value.
        boot_mode = deploy_utils.get_boot_mode_for_deploy(node)

        if CONF.pxe.ipxe_enabled:
            if (not CONF.deploy.http_url or
                not CONF.deploy.http_root):
                raise exception.MissingParameterValue(_(
                    "iPXE boot is enabled but no HTTP URL or HTTP "
                    "root was specified."))
            # iPXE and UEFI should not be configured together.
            if boot_mode == 'uefi':
                LOG.error(_LE("UEFI boot mode is not supported with "
                              "iPXE boot enabled."))
                raise exception.InvalidParameterValue(_(
                    "Conflict: iPXE is enabled, but cannot be used with node"
                    "%(node_uuid)s configured to use UEFI boot") %
                    {'node_uuid': node.uuid})

        if boot_mode == 'uefi':
            validate_boot_option_for_uefi(node)

        # Check the trusted_boot capabilities value.
        deploy_utils.validate_capabilities(node)
        if deploy_utils.is_trusted_boot_requested(node):
            # Check if 'boot_option' and boot mode is compatible with
            # trusted boot.
            validate_boot_parameters_for_trusted_boot(node)

        _parse_driver_info(node)
        d_info = _parse_instance_info(node)
        if node.driver_internal_info.get('is_whole_disk_image'):
            props = []
        elif service_utils.is_glance_image(d_info['image_source']):
            props = ['kernel_id', 'ramdisk_id']
        else:
            props = ['kernel', 'ramdisk']
        deploy_utils.validate_image_properties(task.context, d_info, props)
Beispiel #23
0
def create_pxe_config(task, pxe_options, template=None):
    """Generate PXE configuration file and MAC address links for it.

    This method will generate the PXE configuration file for the task's
    node under a directory named with the UUID of that node. For each
    MAC address or DHCP IP address (port) of that node, a symlink for
    the configuration file will be created under the PXE configuration
    directory, so regardless of which port boots first they'll get the
    same PXE configuration.
    If elilo is the bootloader in use, then its configuration file will
    be created based on hex form of DHCP IP address.
    If grub2 bootloader is in use, then its configuration will be created
    based on DHCP IP address in the form nn.nn.nn.nn.

    :param task: A TaskManager instance.
    :param pxe_options: A dictionary with the PXE configuration
        parameters.
    :param template: The PXE configuration template. If no template is
        given the CONF.pxe.pxe_config_template will be used.

    """
    LOG.debug("Building PXE config for node %s", task.node.uuid)

    if template is None:
        template = CONF.pxe.pxe_config_template

    _ensure_config_dirs_exist(task.node.uuid)

    pxe_config_file_path = get_pxe_config_file_path(task.node.uuid)
    is_uefi_boot_mode = (deploy_utils.get_boot_mode_for_deploy(task.node) ==
                         'uefi')

    # grub bootloader panics with '{}' around any of its tags in its
    # config file. To overcome that 'ROOT' and 'DISK_IDENTIFIER' are enclosed
    # with '(' and ')' in uefi boot mode.
    # These changes do not have any impact on elilo bootloader.
    hex_form = True
    if is_uefi_boot_mode and utils.is_regex_string_in_file(template,
                                                           '^menuentry'):
        hex_form = False
        pxe_config_root_tag = '(( ROOT ))'
        pxe_config_disk_ident = '(( DISK_IDENTIFIER ))'
    else:
        # TODO(stendulker): We should use '(' ')' as the delimiters for all our
        # config files so that we do not need special handling for each of the
        # bootloaders. Should be removed once the Mitaka release starts.
        pxe_config_root_tag = '{{ ROOT }}'
        pxe_config_disk_ident = '{{ DISK_IDENTIFIER }}'

    pxe_config = _build_pxe_config(pxe_options, template, pxe_config_root_tag,
                                   pxe_config_disk_ident)
    utils.write_to_file(pxe_config_file_path, pxe_config)

    if is_uefi_boot_mode:
        _link_ip_address_pxe_configs(task, hex_form)
    else:
        _link_mac_pxe_configs(task)
def dhcp_options_for_instance(task):
    """Retrieves the DHCP PXE boot options.

    :param task: A TaskManager instance.
    """
    dhcp_opts = []

    if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi':
        boot_file = CONF.pxe.uefi_pxe_bootfile_name
    else:
        boot_file = CONF.pxe.pxe_bootfile_name

    if CONF.pxe.ipxe_enabled:
        script_name = os.path.basename(CONF.pxe.ipxe_boot_script)
        ipxe_script_url = '/'.join([CONF.deploy.http_url, script_name])
        dhcp_provider_name = dhcp_factory.CONF.dhcp.dhcp_provider
        # if the request comes from dumb firmware send them the iPXE
        # boot image.
        if dhcp_provider_name == 'neutron':
            # Neutron use dnsmasq as default DHCP agent, add extra config
            # to neutron "dhcp-match=set:ipxe,175" and use below option
            dhcp_opts.append({
                'opt_name': 'tag:!ipxe,bootfile-name',
                'opt_value': boot_file
            })
            dhcp_opts.append({
                'opt_name': 'tag:ipxe,bootfile-name',
                'opt_value': ipxe_script_url
            })
        else:
            # !175 == non-iPXE.
            # http://ipxe.org/howto/dhcpd#ipxe-specific_options
            dhcp_opts.append({
                'opt_name': '!175,bootfile-name',
                'opt_value': boot_file
            })
            dhcp_opts.append({
                'opt_name': 'bootfile-name',
                'opt_value': ipxe_script_url
            })
    else:
        dhcp_opts.append({'opt_name': 'bootfile-name', 'opt_value': boot_file})

    dhcp_opts.append({
        'opt_name': 'server-ip-address',
        'opt_value': CONF.pxe.tftp_server
    })
    dhcp_opts.append({
        'opt_name': 'tftp-server',
        'opt_value': CONF.pxe.tftp_server
    })

    # Append the IP version for all the configuration options
    for opt in dhcp_opts:
        opt.update({'ip_version': int(CONF.pxe.ip_version)})

    return dhcp_opts
Beispiel #25
0
    def prepare_ramdisk(self, task, ramdisk_params):
        """Prepares the boot of Ironic ramdisk using PXE.

        This method prepares the boot of the deploy kernel/ramdisk after
        reading relevant information from the node's driver_info and
        instance_info.

        :param task: a task from TaskManager.
        :param ramdisk_params: the parameters to be passed to the ramdisk.
            pxe driver passes these parameters as kernel command-line
            arguments.
        :returns: None
        :raises: MissingParameterValue, if some information is missing in
            node's driver_info or instance_info.
        :raises: InvalidParameterValue, if some information provided is
            invalid.
        :raises: IronicException, if some power or set boot boot device
            operation failed on the node.
        """
        node = task.node

        # TODO(deva): optimize this if rerun on existing files
        if CONF.pxe.ipxe_enabled:
            # Copy the iPXE boot script to HTTP root directory
            bootfile_path = os.path.join(
                CONF.deploy.http_root,
                os.path.basename(CONF.pxe.ipxe_boot_script))
            shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path)

        dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
        provider = dhcp_factory.DHCPFactory()
        provider.update_dhcp(task, dhcp_opts)

        pxe_info = _get_deploy_image_info(node)

        # NODE: Try to validate and fetch instance images only
        # if we are in DEPLOYING state.
        if node.provision_state == states.DEPLOYING:
            pxe_info.update(_get_instance_image_info(node, task.context))

        pxe_options = _build_pxe_config_options(task, pxe_info)
        pxe_options.update(ramdisk_params)

        if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
            pxe_config_template = CONF.pxe.uefi_pxe_config_template
        else:
            pxe_config_template = _get_pxe_conf_option(task,
                                                       'pxe_config_template')

        pxe_utils.create_pxe_config(task, pxe_options,
                                    pxe_config_template)
        deploy_utils.try_set_boot_device(task, boot_devices.PXE)

        # FIXME(lucasagomes): If it's local boot we should not cache
        # the image kernel and ramdisk (Or even require it).
        _cache_ramdisk_kernel(task.context, node, pxe_info)
def _get_boot_mode(node):
    """Gets the boot mode.

    :param node: A single Node.
    :returns: A string representing the boot mode type. Defaults to 'bios'.
    """
    boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
    if boot_mode:
        return boot_mode
    return "bios"
Beispiel #27
0
def _get_boot_mode(node):
    """Gets the boot mode.

    :param node: A single Node.
    :returns: A string representing the boot mode type. Defaults to 'bios'.
    """
    boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
    if boot_mode:
        return boot_mode
    return "bios"
Beispiel #28
0
    def continue_deploy(self, task):
        task.process_event('resume')
        node = task.node
        image_source = node.instance_info.get('image_source')
        LOG.debug('Continuing deploy for node %(node)s with image %(img)s', {
            'node': node.uuid,
            'img': image_source
        })

        image_info = {
            'id': image_source.split('/')[-1],
            'urls': [node.instance_info['image_url']],
            'checksum': node.instance_info['image_checksum'],
            # NOTE(comstud): Older versions of ironic do not set
            # 'disk_format' nor 'container_format', so we use .get()
            # to maintain backwards compatibility in case code was
            # upgraded in the middle of a build request.
            'disk_format': node.instance_info.get('image_disk_format'),
            'container_format':
            node.instance_info.get('image_container_format'),
            'stream_raw_images': CONF.agent.stream_raw_images,
        }

        proxies = {}
        for scheme in ('http', 'https'):
            proxy_param = 'image_%s_proxy' % scheme
            proxy = node.driver_info.get(proxy_param)
            if proxy:
                proxies[scheme] = proxy
        if proxies:
            image_info['proxies'] = proxies
            no_proxy = node.driver_info.get('image_no_proxy')
            if no_proxy is not None:
                image_info['no_proxy'] = no_proxy

        image_info['node_uuid'] = node.uuid
        iwdi = node.driver_internal_info.get('is_whole_disk_image')
        if not iwdi:
            for label in PARTITION_IMAGE_LABELS:
                image_info[label] = node.instance_info.get(label)
            boot_option = deploy_utils.get_boot_option(node)
            boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
            if boot_mode:
                image_info['deploy_boot_mode'] = boot_mode
            else:
                image_info['deploy_boot_mode'] = 'bios'
            image_info['boot_option'] = boot_option
            disk_label = deploy_utils.get_disk_label(node)
            if disk_label is not None:
                image_info['disk_label'] = disk_label

        # Tell the client to download and write the image with the given args
        self._client.prepare_image(node, image_info)

        task.process_event('wait')
Beispiel #29
0
def update_boot_mode(task):
    """Update instance_info with boot mode to be used for deploy.

    This method updates instance_info with boot mode to be used for
    deploy if node properties['capabilities'] do not have boot_mode.
    It sets the boot mode on the node.

    :param task: Task object.
    :raises: IloOperationError if setting boot mode failed.
    """

    node = task.node
    boot_mode = deploy_utils.get_boot_mode_for_deploy(node)

    if boot_mode is not None:
        LOG.debug("Node %(uuid)s boot mode is being set to %(boot_mode)s",
                  {'uuid': node.uuid, 'boot_mode': boot_mode})
        set_boot_mode(node, boot_mode)
        return

    LOG.debug("Check pending boot mode for node %s.", node.uuid)
    ilo_object = get_ilo_object(node)

    try:
        boot_mode = ilo_object.get_pending_boot_mode()
    except ilo_error.IloCommandNotSupportedError:
        boot_mode = 'legacy'

    if boot_mode != 'UNKNOWN':
        boot_mode = BOOT_MODE_ILO_TO_GENERIC[boot_mode.lower()]

    if boot_mode == 'UNKNOWN':
        # NOTE(faizan) ILO will return this in remote cases and mostly on
        # the nodes which supports UEFI. Such nodes mostly comes with UEFI
        # as default boot mode. So we will try setting bootmode to UEFI
        # and if it fails then we fall back to BIOS boot mode.
        try:
            boot_mode = 'uefi'
            ilo_object.set_pending_boot_mode(
                BOOT_MODE_GENERIC_TO_ILO[boot_mode].upper())
        except ilo_error.IloError as ilo_exception:
            operation = _("Setting %s as boot mode") % boot_mode
            raise exception.IloOperationError(operation=operation,
                                              error=ilo_exception)

        LOG.debug("Node %(uuid)s boot mode is being set to %(boot_mode)s "
                  "as pending boot mode is unknown.",
                  {'uuid': node.uuid, 'boot_mode': boot_mode})

    instance_info = node.instance_info
    instance_info['deploy_boot_mode'] = boot_mode
    node.instance_info = instance_info
    node.save()
Beispiel #30
0
    def continue_deploy(self, task):
        task.process_event('resume')
        node = task.node
        image_source = node.instance_info.get('image_source')
        LOG.debug('Continuing deploy for node %(node)s with image %(img)s',
                  {'node': node.uuid, 'img': image_source})

        image_info = {
            'id': image_source.split('/')[-1],
            'urls': [node.instance_info['image_url']],
            'checksum': node.instance_info['image_checksum'],
            # NOTE(comstud): Older versions of ironic do not set
            # 'disk_format' nor 'container_format', so we use .get()
            # to maintain backwards compatibility in case code was
            # upgraded in the middle of a build request.
            'disk_format': node.instance_info.get('image_disk_format'),
            'container_format': node.instance_info.get(
                'image_container_format'),
            'stream_raw_images': CONF.agent.stream_raw_images,
        }

        proxies = {}
        for scheme in ('http', 'https'):
            proxy_param = 'image_%s_proxy' % scheme
            proxy = node.driver_info.get(proxy_param)
            if proxy:
                proxies[scheme] = proxy
        if proxies:
            image_info['proxies'] = proxies
            no_proxy = node.driver_info.get('image_no_proxy')
            if no_proxy is not None:
                image_info['no_proxy'] = no_proxy

        image_info['node_uuid'] = node.uuid
        iwdi = node.driver_internal_info.get('is_whole_disk_image')
        if not iwdi:
            for label in PARTITION_IMAGE_LABELS:
                image_info[label] = node.instance_info.get(label)
            boot_option = deploy_utils.get_boot_option(node)
            boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
            if boot_mode:
                image_info['deploy_boot_mode'] = boot_mode
            else:
                image_info['deploy_boot_mode'] = 'bios'
            image_info['boot_option'] = boot_option
            disk_label = deploy_utils.get_disk_label(node)
            if disk_label is not None:
                image_info['disk_label'] = disk_label

        # Tell the client to download and write the image with the given args
        self._client.prepare_image(node, image_info)

        task.process_event('wait')
Beispiel #31
0
    def validate(self, task):
        """Validate the deployment information for the task's node.

        :param task: a TaskManager instance containing the node to act on.
        :raises: InvalidParameterValue.
        :raises: MissingParameterValue
        """
        node = task.node

        # Check the boot_mode and boot_option capabilities values.
        deploy_utils.validate_capabilities(node)

        boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node)

        if CONF.pxe.ipxe_enabled:
            if not CONF.pxe.http_url or not CONF.pxe.http_root:
                raise exception.MissingParameterValue(
                    _("iPXE boot is enabled but no HTTP URL or HTTP " "root was specified.")
                )
            # iPXE and UEFI should not be configured together.
            if boot_mode == "uefi":
                LOG.error(_LE("UEFI boot mode is not supported with " "iPXE boot enabled."))
                raise exception.InvalidParameterValue(
                    _(
                        "Conflict: iPXE is enabled, but cannot be used with node"
                        "%(node_uuid)s configured to use UEFI boot"
                    )
                    % {"node_uuid": node.uuid}
                )

        # Check if 'boot_option' is compatible with 'boot_mode' of uefi and
        # image being deployed
        if boot_mode == "uefi":
            validate_boot_option_for_uefi(task.node)

        if deploy_utils.is_trusted_boot_requested(task.node):
            # Check if 'boot_option' and boot mode is compatible with
            # trusted boot.
            validate_boot_parameters_for_trusted_boot(task.node)

        d_info = _parse_deploy_info(node)

        iscsi_deploy.validate(task)

        if node.driver_internal_info.get("is_whole_disk_image"):
            props = []
        elif service_utils.is_glance_image(d_info["image_source"]):
            props = ["kernel_id", "ramdisk_id"]
        else:
            props = ["kernel", "ramdisk"]

        iscsi_deploy.validate_image_properties(task.context, d_info, props)
Beispiel #32
0
    def validate(self, task):
        """Validate the deployment information for the task's node.

        :param task: a TaskManager instance containing the node to act on.
        :raises: InvalidParameterValue.
        :raises: MissingParameterValue
        """
        node = task.node

        # Check the boot_mode and boot_option capabilities values.
        deploy_utils.validate_capabilities(node)

        boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node)

        if CONF.pxe.ipxe_enabled:
            if not CONF.pxe.http_url or not CONF.pxe.http_root:
                raise exception.MissingParameterValue(
                    _("iPXE boot is enabled but no HTTP URL or HTTP "
                      "root was specified."))
            # iPXE and UEFI should not be configured together.
            if boot_mode == 'uefi':
                LOG.error(
                    _LE("UEFI boot mode is not supported with "
                        "iPXE boot enabled."))
                raise exception.InvalidParameterValue(
                    _("Conflict: iPXE is enabled, but cannot be used with node"
                      "%(node_uuid)s configured to use UEFI boot") %
                    {'node_uuid': node.uuid})

        # Check if 'boot_option' is compatible with 'boot_mode' of uefi and
        # image being deployed
        if boot_mode == 'uefi':
            validate_boot_option_for_uefi(task.node)

        if deploy_utils.is_trusted_boot_requested(task.node):
            # Check if 'boot_option' and boot mode is compatible with
            # trusted boot.
            validate_boot_parameters_for_trusted_boot(task.node)

        d_info = _parse_deploy_info(node)

        iscsi_deploy.validate(task)

        if node.driver_internal_info.get('is_whole_disk_image'):
            props = []
        elif service_utils.is_glance_image(d_info['image_source']):
            props = ['kernel_id', 'ramdisk_id']
        else:
            props = ['kernel', 'ramdisk']

        iscsi_deploy.validate_image_properties(task.context, d_info, props)
Beispiel #33
0
    def continue_deploy(self, task, **kwargs):
        """Method invoked when deployed with the IPA ramdisk.

        This method is invoked during a heartbeat from an agent when
        the node is in wait-call-back state. This deploys the image on
        the node and then configures the node to boot according to the
        desired boot option (netboot or localboot).

        :param task: a TaskManager object containing the node.
        :param kwargs: the kwargs passed from the heartbeat method.
        :raises: InstanceDeployFailure, if it encounters some error during
            the deploy.
        """
        task.process_event('resume')
        node = task.node
        LOG.debug('Continuing the deployment on node %s', node.uuid)

        # NOTE(lucasagomes): We don't use the token file with the agent,
        # but as it's created as part of deploy() we are going to remove
        # it here.
        _destroy_token_file(node)

        uuid_dict = iscsi_deploy.do_agent_iscsi_deploy(task, self._client)

        is_whole_disk_image = node.driver_internal_info['is_whole_disk_image']
        if iscsi_deploy.get_boot_option(node) == "local":
            # Install the boot loader
            root_uuid = uuid_dict.get('root uuid')
            efi_sys_uuid = uuid_dict.get('efi system partition uuid')
            self.configure_local_boot(
                task, root_uuid=root_uuid,
                efi_system_part_uuid=efi_sys_uuid)

            # If it's going to boot from the local disk, get rid of
            # the PXE configuration files used for the deployment
            pxe_utils.clean_up_pxe_config(task)
        else:
            root_uuid_or_disk_id = uuid_dict.get(
                'root uuid', uuid_dict.get('disk identifier'))
            pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
            boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
            deploy_utils.switch_pxe_config(pxe_config_path,
                                           root_uuid_or_disk_id,
                                           boot_mode, is_whole_disk_image)

        self.reboot_and_finish_deploy(task)
Beispiel #34
0
    def continue_deploy(self, task, **kwargs):
        """Method invoked when deployed with the IPA ramdisk.

        This method is invoked during a heartbeat from an agent when
        the node is in wait-call-back state. This deploys the image on
        the node and then configures the node to boot according to the
        desired boot option (netboot or localboot).

        :param task: a TaskManager object containing the node.
        :param kwargs: the kwargs passed from the heartbeat method.
        :raises: InstanceDeployFailure, if it encounters some error during
            the deploy.
        """
        task.process_event('resume')
        node = task.node
        LOG.debug('Continuing the deployment on node %s', node.uuid)

        # NOTE(lucasagomes): We don't use the token file with the agent,
        # but as it's created as part of deploy() we are going to remove
        # it here.
        _destroy_token_file(node)

        uuid_dict = iscsi_deploy.do_agent_iscsi_deploy(task, self._client)

        is_whole_disk_image = node.driver_internal_info['is_whole_disk_image']
        if iscsi_deploy.get_boot_option(node) == "local":
            # Install the boot loader
            root_uuid = uuid_dict.get('root uuid')
            efi_sys_uuid = uuid_dict.get('efi system partition uuid')
            self.configure_local_boot(task,
                                      root_uuid=root_uuid,
                                      efi_system_part_uuid=efi_sys_uuid)

            # If it's going to boot from the local disk, get rid of
            # the PXE configuration files used for the deployment
            pxe_utils.clean_up_pxe_config(task)
        else:
            root_uuid_or_disk_id = uuid_dict.get(
                'root uuid', uuid_dict.get('disk identifier'))
            pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
            boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
            deploy_utils.switch_pxe_config(pxe_config_path,
                                           root_uuid_or_disk_id, boot_mode,
                                           is_whole_disk_image)

        self.reboot_and_finish_deploy(task)
Beispiel #35
0
def dhcp_options_for_instance(task):
    """Retrieves the DHCP PXE boot options.

    :param task: A TaskManager instance.
    """
    dhcp_opts = []

    if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi':
        boot_file = CONF.pxe.uefi_pxe_bootfile_name
    else:
        boot_file = CONF.pxe.pxe_bootfile_name

    if CONF.pxe.ipxe_enabled:
        script_name = os.path.basename(CONF.pxe.ipxe_boot_script)
        ipxe_script_url = '/'.join([CONF.deploy.http_url, script_name])
        dhcp_provider_name = dhcp_factory.CONF.dhcp.dhcp_provider
        # if the request comes from dumb firmware send them the iPXE
        # boot image.
        if dhcp_provider_name == 'neutron':
            # Neutron use dnsmasq as default DHCP agent, add extra config
            # to neutron "dhcp-match=set:ipxe,175" and use below option
            dhcp_opts.append({'opt_name': 'tag:!ipxe,bootfile-name',
                              'opt_value': boot_file})
            dhcp_opts.append({'opt_name': 'tag:ipxe,bootfile-name',
                              'opt_value': ipxe_script_url})
        else:
            # !175 == non-iPXE.
            # http://ipxe.org/howto/dhcpd#ipxe-specific_options
            dhcp_opts.append({'opt_name': '!175,bootfile-name',
                              'opt_value': boot_file})
            dhcp_opts.append({'opt_name': 'bootfile-name',
                              'opt_value': ipxe_script_url})
    else:
        dhcp_opts.append({'opt_name': 'bootfile-name',
                          'opt_value': boot_file})

    dhcp_opts.append({'opt_name': 'server-ip-address',
                      'opt_value': CONF.pxe.tftp_server})
    dhcp_opts.append({'opt_name': 'tftp-server',
                      'opt_value': CONF.pxe.tftp_server})

    # Append the IP version for all the configuration options
    for opt in dhcp_opts:
        opt.update({'ip_version': int(CONF.pxe.ip_version)})

    return dhcp_opts
Beispiel #36
0
def _build_service_pxe_config(task, instance_image_info, root_uuid_or_disk_id):
    node = task.node
    pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
    # NOTE(pas-ha) if it is takeover of ACTIVE node,
    # first ensure that basic PXE configs and links
    # are in place before switching pxe config
    if (node.provision_state == states.ACTIVE
            and not os.path.isfile(pxe_config_path)):
        pxe_options = _build_pxe_config_options(task,
                                                instance_image_info,
                                                service=True)
        pxe_config_template = deploy_utils.get_pxe_config_template(node)
        pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template)
    iwdi = node.driver_internal_info.get('is_whole_disk_image')
    deploy_utils.switch_pxe_config(
        pxe_config_path, root_uuid_or_disk_id,
        deploy_utils.get_boot_mode_for_deploy(node), iwdi,
        deploy_utils.is_trusted_boot_requested(node))
Beispiel #37
0
    def set_boot_device(self, task, device, persistent=False):
        """Set the boot device for the task's node.

        Set the boot device to use on next reboot of the node.

        :param task: a task from TaskManager.
        :param device: the boot device, one of
                       :mod:`ironic.common.boot_devices`.
        :param persistent: Boolean value. True if the boot device will
                           persist to all future boots, False if not.
                           Default: False.
        :raises: InvalidParameterValue if an invalid boot device is specified
                 or required ipmi credentials are missing.
        :raises: MissingParameterValue when required ipmi credentials
                 are missing.
        :raises: IPMIFailure on an error from pyghmi.
        """
        if device not in self.get_supported_boot_devices(task):
            raise exception.InvalidParameterValue(
                _("Invalid boot device %s specified.") % device)

        if task.node.driver_info.get('ipmi_force_boot_device', False):
            driver_utils.force_persistent_boot(task, device, persistent)
            # Reset persistent to False, in case of BMC does not support
            # persistent or we do not have admin rights.
            persistent = False

        boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node)
        driver_info = _parse_driver_info(task.node)
        try:
            ipmicmd = ipmi_command.Command(bmc=driver_info['address'],
                                           userid=driver_info['username'],
                                           password=driver_info['password'])
            bootdev = _BOOT_DEVICES_MAP[device]
            uefiboot = boot_mode == 'uefi'
            ipmicmd.set_bootdev(bootdev, persist=persistent, uefiboot=uefiboot)
        except pyghmi_exception.IpmiException as e:
            LOG.error(
                _LE("IPMI set boot device failed for node %(node_id)s "
                    "with the following error: %(error)s"), {
                        'node_id': driver_info['uuid'],
                        'error': e
                    })
            raise exception.IPMIFailure(cmd=e)
Beispiel #38
0
    def set_boot_device(self, task, device, persistent=False):
        """Set the boot device for the task's node.

        Set the boot device to use on next reboot of the node.

        :param task: a task from TaskManager.
        :param device: the boot device, one of
                       :mod:`ironic.common.boot_devices`.
        :param persistent: Boolean value. True if the boot device will
                           persist to all future boots, False if not.
                           Default: False.
        :raises: InvalidParameterValue if an invalid boot device is specified
                 or required ipmi credentials are missing.
        :raises: MissingParameterValue when required ipmi credentials
                 are missing.
        :raises: IPMIFailure on an error from pyghmi.
        """
        if device not in self.get_supported_boot_devices(task):
            raise exception.InvalidParameterValue(_(
                "Invalid boot device %s specified.") % device)

        if task.node.driver_info.get('ipmi_force_boot_device', False):
            driver_utils.force_persistent_boot(task,
                                               device,
                                               persistent)
            # Reset persistent to False, in case of BMC does not support
            # persistent or we do not have admin rights.
            persistent = False

        boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node)
        driver_info = _parse_driver_info(task.node)
        try:
            ipmicmd = ipmi_command.Command(bmc=driver_info['address'],
                                           userid=driver_info['username'],
                                           password=driver_info['password'])
            bootdev = _BOOT_DEVICES_MAP[device]
            uefiboot = boot_mode == 'uefi'
            ipmicmd.set_bootdev(bootdev, persist=persistent, uefiboot=uefiboot)
        except pyghmi_exception.IpmiException as e:
            LOG.error(_LE("IPMI set boot device failed for node %(node_id)s "
                          "with the following error: %(error)s"),
                      {'node_id': driver_info['uuid'], 'error': e})
            raise exception.IPMIFailure(cmd=e)
Beispiel #39
0
def _build_service_pxe_config(task, instance_image_info,
                              root_uuid_or_disk_id):
    node = task.node
    pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
    # NOTE(pas-ha) if it is takeover of ACTIVE node,
    # first ensure that basic PXE configs and links
    # are in place before switching pxe config
    if (node.provision_state == states.ACTIVE and
            not os.path.isfile(pxe_config_path)):
        pxe_options = _build_pxe_config_options(task, instance_image_info,
                                                service=True)
        pxe_config_template = deploy_utils.get_pxe_config_template(node)
        pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template)
    iwdi = node.driver_internal_info.get('is_whole_disk_image')
    deploy_utils.switch_pxe_config(
        pxe_config_path, root_uuid_or_disk_id,
        deploy_utils.get_boot_mode_for_deploy(node),
        iwdi, deploy_utils.is_trusted_boot_requested(node),
        deploy_utils.is_iscsi_boot(task))
Beispiel #40
0
    def continue_deploy(self, task, **kwargs):
        """Method invoked when deployed with the IPA ramdisk.

        This method is invoked during a heartbeat from an agent when
        the node is in wait-call-back state. This deploys the image on
        the node and then configures the node to boot according to the
        desired boot option (netboot or localboot).

        :param task: a TaskManager object containing the node.
        :param kwargs: the kwargs passed from the heartbeat method.
        :raises: InstanceDeployFailure, if it encounters some error during
            the deploy.
        """
        task.process_event("resume")
        node = task.node
        LOG.debug("Continuing the deployment on node %s", node.uuid)

        uuid_dict = iscsi_deploy.do_agent_iscsi_deploy(task, self._client)

        is_whole_disk_image = node.driver_internal_info["is_whole_disk_image"]
        if iscsi_deploy.get_boot_option(node) == "local":
            # Install the boot loader
            root_uuid = uuid_dict.get("root uuid")
            efi_sys_uuid = uuid_dict.get("efi system partition uuid")
            self.configure_local_boot(task, root_uuid=root_uuid, efi_system_part_uuid=efi_sys_uuid)

            # If it's going to boot from the local disk, get rid of
            # the PXE configuration files used for the deployment
            pxe_utils.clean_up_pxe_config(task)
        else:
            root_uuid_or_disk_id = uuid_dict.get("root uuid", uuid_dict.get("disk identifier"))
            pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
            boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
            deploy_utils.switch_pxe_config(
                pxe_config_path,
                root_uuid_or_disk_id,
                boot_mode,
                is_whole_disk_image,
                deploy_utils.is_trusted_boot_requested(node),
            )

        self.reboot_and_finish_deploy(task)
Beispiel #41
0
    def reboot_to_instance(self, task):
        task.process_event('resume')
        node = task.node
        iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
        error = self.check_deploy_success(node)
        if error is not None:
            # TODO(jimrollenhagen) power off if using neutron dhcp to
            #                      align with pxe driver?
            msg = (_('node %(node)s command status errored: %(error)s') % {
                'node': node.uuid,
                'error': error
            })
            LOG.error(msg)
            deploy_utils.set_failed_state(task, msg)
            return
        if not iwdi:
            root_uuid = self._get_uuid_from_result(task, 'root_uuid')
            if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
                efi_sys_uuid = (self._get_uuid_from_result(
                    task, 'efi_system_partition_uuid'))
            else:
                efi_sys_uuid = None
            driver_internal_info = task.node.driver_internal_info
            driver_internal_info['root_uuid_or_disk_id'] = root_uuid
            task.node.driver_internal_info = driver_internal_info
            task.node.save()
            self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid)
        LOG.info('Image successfully written to node %s', node.uuid)
        LOG.debug('Rebooting node %s to instance', node.uuid)
        if iwdi:
            manager_utils.node_set_boot_device(task, 'disk', persistent=True)

        self.reboot_and_finish_deploy(task)

        # NOTE(TheJulia): If we deployed a whole disk image, we
        # should expect a whole disk image and clean-up the tftp files
        # on-disk incase the node is disregarding the boot preference.
        # TODO(rameshg87): Not all in-tree drivers using reboot_to_instance
        # have a boot interface. So include a check for now. Remove this
        # check once all in-tree drivers have a boot interface.
        if task.driver.boot and iwdi:
            task.driver.boot.clean_up_ramdisk(task)
Beispiel #42
0
    def reboot_to_instance(self, task):
        task.process_event('resume')
        node = task.node
        iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
        error = self.check_deploy_success(node)
        if error is not None:
            # TODO(jimrollenhagen) power off if using neutron dhcp to
            #                      align with pxe driver?
            msg = (_('node %(node)s command status errored: %(error)s') %
                   {'node': node.uuid, 'error': error})
            LOG.error(msg)
            deploy_utils.set_failed_state(task, msg)
            return
        if not iwdi:
            root_uuid = self._get_uuid_from_result(task, 'root_uuid')
            if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
                efi_sys_uuid = (
                    self._get_uuid_from_result(task,
                                               'efi_system_partition_uuid'))
            else:
                efi_sys_uuid = None
            driver_internal_info = task.node.driver_internal_info
            driver_internal_info['root_uuid_or_disk_id'] = root_uuid
            task.node.driver_internal_info = driver_internal_info
            task.node.save()
            self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid)
        LOG.info('Image successfully written to node %s', node.uuid)
        LOG.debug('Rebooting node %s to instance', node.uuid)
        if iwdi:
            manager_utils.node_set_boot_device(task, 'disk', persistent=True)

        self.reboot_and_finish_deploy(task)

        # NOTE(TheJulia): If we deployed a whole disk image, we
        # should expect a whole disk image and clean-up the tftp files
        # on-disk incase the node is disregarding the boot preference.
        # TODO(rameshg87): Not all in-tree drivers using reboot_to_instance
        # have a boot interface. So include a check for now. Remove this
        # check once all in-tree drivers have a boot interface.
        if task.driver.boot and iwdi:
            task.driver.boot.clean_up_ramdisk(task)
Beispiel #43
0
def validate_boot_parameters_for_trusted_boot(node):
    """Check if boot parameters are valid for trusted boot."""
    boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
    boot_option = deploy_utils.get_boot_option(node)
    is_whole_disk_image = node.driver_internal_info.get('is_whole_disk_image')
    # 'is_whole_disk_image' is not supported by trusted boot, because there is
    # no Kernel/Ramdisk to measure at all.
    if (boot_mode != 'bios' or
        is_whole_disk_image or
        boot_option != 'netboot'):
        msg = (_("Trusted boot is only supported in BIOS boot mode with "
                 "netboot and without whole_disk_image, but Node "
                 "%(node_uuid)s was configured with boot_mode: %(boot_mode)s, "
                 "boot_option: %(boot_option)s, is_whole_disk_image: "
                 "%(is_whole_disk_image)s: at least one of them is wrong, and "
                 "this can be caused by enable secure boot.") %
               {'node_uuid': node.uuid, 'boot_mode': boot_mode,
                'boot_option': boot_option,
                'is_whole_disk_image': is_whole_disk_image})
        LOG.error(msg)
        raise exception.InvalidParameterValue(msg)
Beispiel #44
0
def validate_boot_option_for_uefi(node):
    """In uefi boot mode, validate if the boot option is compatible.

    This method raises exception if whole disk image being deployed
    in UEFI boot mode without 'boot_option' being set to 'local'.

    :param node: a single Node.
    :raises: InvalidParameterValue
    """
    boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
    boot_option = deploy_utils.get_boot_option(node)
    if (boot_mode == 'uefi' and
            node.driver_internal_info.get('is_whole_disk_image') and
            boot_option != 'local'):
        LOG.error(_LE("Whole disk image with netboot is not supported in UEFI "
                      "boot mode."))
        raise exception.InvalidParameterValue(_(
            "Conflict: Whole disk image being used for deploy, but "
            "cannot be used with node %(node_uuid)s configured to use "
            "UEFI boot with netboot option") %
            {'node_uuid': node.uuid})
Beispiel #45
0
    def prepare_ramdisk(self, task, ramdisk_params):
        node = task.node

        # TODO(deva): optimize this if rerun on existing files
        if CONF.pxe.ipxe_enabled:
            # Copy the iPXE boot script to HTTP root directory
            bootfile_path = os.path.join(
                CONF.deploy.http_root,
                os.path.basename(CONF.pxe.ipxe_boot_script))
            shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path)

        prov_ip = self._plug_provisioning(task)

        task.ports = objects.Port.list_by_node_id(task.context, node.id)

        pxe_info = pxe._get_deploy_image_info(node)

        # NODE: Try to validate and fetch instance images only
        # if we are in DEPLOYING state.
        if node.provision_state == states.DEPLOYING:
            pxe_info.update(pxe._get_instance_image_info(node, task.context))

        pxe_options = pxe._build_pxe_config_options(task, pxe_info)
        pxe_options.update(ramdisk_params)
        pxe_options['advertise_host'] = prov_ip

        if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
            pxe_config_template = CONF.pxe.uefi_pxe_config_template
        else:
            pxe_config_template = CONF.pxe.pxe_config_template

        pxe_utils.create_pxe_config(task, pxe_options,
                                    pxe_config_template)
        deploy_utils.try_set_boot_device(task, boot_devices.PXE)

        # FIXME(lucasagomes): If it's local boot we should not cache
        # the image kernel and ramdisk (Or even require it).
        pxe._cache_ramdisk_kernel(task.context, node, pxe_info)
Beispiel #46
0
    def prepare_instance(self, task):
        """Prepares the boot of instance.

        This method prepares the boot of the instance after reading
        relevant information from the node's instance_info. In case of netboot,
        it updates the dhcp entries and switches the PXE config. In case of
        localboot, it cleans up the PXE config.
        In case of 'boot from volume', it updates the iSCSI info onto iLO and
        sets the node to boot from 'UefiTarget' boot device.

        :param task: a task from TaskManager.
        :returns: None
        :raises: IloOperationError, if some operation on iLO failed.
        """

        # Set boot mode
        ilo_common.update_boot_mode(task)
        # Need to enable secure boot, if being requested
        ilo_common.update_secure_boot_mode(task, True)

        boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node)

        if deploy_utils.is_iscsi_boot(task) and boot_mode == 'uefi':
            # Need to set 'ilo_uefi_iscsi_boot' param for clean up
            driver_internal_info = task.node.driver_internal_info
            driver_internal_info['ilo_uefi_iscsi_boot'] = True
            task.node.driver_internal_info = driver_internal_info
            task.node.save()
            # It will set iSCSI info onto iLO
            task.driver.management.set_iscsi_boot_target(task)
            manager_utils.node_set_boot_device(task,
                                               boot_devices.ISCSIBOOT,
                                               persistent=True)
        else:
            # Volume boot in BIOS boot mode is handled using
            # PXE boot interface
            super(IloPXEBoot, self).prepare_instance(task)
Beispiel #47
0
    def reboot_to_instance(self, task):
        task.process_event('resume')
        node = task.node
        iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
        error = self.check_deploy_success(node)
        if error is not None:
            # TODO(jimrollenhagen) power off if using neutron dhcp to
            #                      align with pxe driver?
            msg = (_('node %(node)s command status errored: %(error)s') % {
                'node': node.uuid,
                'error': error
            })
            LOG.error(msg)
            deploy_utils.set_failed_state(task, msg)
            return

        # If `boot_option` is set to `netboot`, PXEBoot.prepare_instance()
        # would need root_uuid of the whole disk image to add it into the
        # pxe config to perform chain boot.
        # IPA would have returned us the 'root_uuid_or_disk_id' if image
        # being provisioned is a whole disk image. IPA would also provide us
        # 'efi_system_partition_uuid' if the image being provisioned is a
        # partition image.
        # In case of local boot using partition image, we need both
        # 'root_uuid_or_disk_id' and 'efi_system_partition_uuid' to configure
        # bootloader for local boot.
        driver_internal_info = task.node.driver_internal_info
        root_uuid = self._get_uuid_from_result(task, 'root_uuid')
        if root_uuid:
            driver_internal_info['root_uuid_or_disk_id'] = root_uuid
            task.node.driver_internal_info = driver_internal_info
            task.node.save()
        elif iwdi and CONF.agent.manage_agent_boot:
            # IPA version less than 3.1.0 will not return root_uuid for
            # whole disk image. Also IPA version introduced a requirement
            # for hexdump utility that may not be always available. Need to
            # fall back to older behavior for the same.
            LOG.warning(
                "With the deploy ramdisk based on Ironic Python Agent "
                "version 3.1.0 and beyond, the drivers using "
                "`direct` deploy interface performs `netboot` or "
                "`local` boot for whole disk image based on value "
                "of boot option setting. When you upgrade Ironic "
                "Python Agent in your deploy ramdisk, ensure that "
                "boot option is set appropriately for the node %s. "
                "The boot option can be set using configuration "
                "`[deploy]/default_boot_option` or as a `boot_option` "
                "capability in node's `properties['capabilities']`. "
                "Also please note that this functionality requires "
                "`hexdump` command in the ramdisk.", node.uuid)

        efi_sys_uuid = None
        if not iwdi:
            if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
                efi_sys_uuid = (self._get_uuid_from_result(
                    task, 'efi_system_partition_uuid'))
        LOG.info('Image successfully written to node %s', node.uuid)

        if CONF.agent.manage_agent_boot:
            # It is necessary to invoke prepare_instance() of the node's
            # boot interface, so that the any necessary configurations like
            # setting of the boot mode (e.g. UEFI secure boot) which cannot
            # be done on node during deploy stage can be performed.
            LOG.debug(
                'Executing driver specific tasks before booting up the '
                'instance for node %s', node.uuid)
            self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid)
        else:
            manager_utils.node_set_boot_device(task, 'disk', persistent=True)

        LOG.debug('Rebooting node %s to instance', node.uuid)
        self.reboot_and_finish_deploy(task)
Beispiel #48
0
    def prepare_instance(self, task):
        """Prepares the boot of instance.

        This method prepares the boot of the instance after reading
        relevant information from the node's instance_info. In case of netboot,
        it updates the dhcp entries and switches the PXE config. In case of
        localboot, it cleans up the PXE config.

        :param task: a task from TaskManager.
        :returns: None
        """
        node = task.node
        boot_option = deploy_utils.get_boot_option(node)
        boot_device = None

        if deploy_utils.is_iscsi_boot(task):
            dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
            provider = dhcp_factory.DHCPFactory()
            provider.update_dhcp(task, dhcp_opts)

            # configure iPXE for iscsi boot
            pxe_config_path = pxe_utils.get_pxe_config_file_path(
                task.node.uuid)
            if not os.path.isfile(pxe_config_path):
                pxe_options = _build_pxe_config_options(task, {})
                pxe_config_template = (
                    deploy_utils.get_pxe_config_template(node))
                pxe_utils.create_pxe_config(
                    task, pxe_options, pxe_config_template)
            deploy_utils.switch_pxe_config(
                pxe_config_path, None,
                deploy_utils.get_boot_mode_for_deploy(node), False,
                iscsi_boot=True)
            boot_device = boot_devices.PXE

        elif boot_option != "local":
            if task.driver.storage.should_write_image(task):
                # Make sure that the instance kernel/ramdisk is cached.
                # This is for the takeover scenario for active nodes.
                instance_image_info = _get_instance_image_info(
                    task.node, task.context)
                _cache_ramdisk_kernel(task.context, task.node,
                                      instance_image_info)

            # If it's going to PXE boot we need to update the DHCP server
            dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
            provider = dhcp_factory.DHCPFactory()
            provider.update_dhcp(task, dhcp_opts)

            iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
            try:
                root_uuid_or_disk_id = task.node.driver_internal_info[
                    'root_uuid_or_disk_id'
                ]
            except KeyError:
                if not task.driver.storage.should_write_image(task):
                    pass
                elif not iwdi:
                    LOG.warning("The UUID for the root partition can't be "
                                "found, unable to switch the pxe config from "
                                "deployment mode to service (boot) mode for "
                                "node %(node)s", {"node": task.node.uuid})
                else:
                    LOG.warning("The disk id for the whole disk image can't "
                                "be found, unable to switch the pxe config "
                                "from deployment mode to service (boot) mode "
                                "for node %(node)s", {"node": task.node.uuid})
            else:
                _build_service_pxe_config(task, instance_image_info,
                                          root_uuid_or_disk_id)
                boot_device = boot_devices.PXE
        else:
            # If it's going to boot from the local disk, we don't need
            # PXE config files. They still need to be generated as part
            # of the prepare() because the deployment does PXE boot the
            # deploy ramdisk
            pxe_utils.clean_up_pxe_config(task)
            boot_device = boot_devices.DISK

        # NOTE(pas-ha) do not re-set boot device on ACTIVE nodes
        # during takeover
        if boot_device and task.node.provision_state != states.ACTIVE:
            manager_utils.node_set_boot_device(task, boot_device,
                                               persistent=True)
Beispiel #49
0
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'.
    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.

    :param task: a TaskManager instance containing the node to act on.
    :param root_uuid: the uuid of the root partition.
    :returns: boot ISO URL. Should be either of below:
        * A Swift object - It should be of format 'swift:<object-name>'. It is
          assumed that the image object is present in
          CONF.ilo.swift_ilo_container;
        * A Glance image - It should be format 'glance://<glance-image-uuid>'
          or just <glance-image-uuid>;
        * An HTTP URL.
        On error finding the boot iso, it returns None.
    :raises: MissingParameterValue, if any of the required parameters are
        missing in the node's driver_info or instance_info.
    :raises: InvalidParameterValue, if any of the parameters have invalid
        value in the node's driver_info or instance_info.
    :raises: SwiftOperationError, if operation with Swift fails.
    :raises: ImageCreationFailed, if creation of boot ISO failed.
    :raises: exception.ImageRefValidationFailed if ilo_boot_iso is not
        HTTP(S) URL.
    """
    LOG.debug("Trying to get a boot ISO to boot the baremetal node")

    # 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):
        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):
            try:
                image_service.HttpImageService().validate_href(boot_iso)
            except exception.ImageRefValidationFailed:
                with excutils.save_and_reraise_exception():
                    LOG.error(_LE("Virtual media deploy accepts only Glance "
                                  "images or HTTP(S) URLs as "
                                  "instance_info['ilo_boot_iso']. Either %s "
                                  "is not a valid HTTP(S) URL or is "
                                  "not reachable."), boot_iso)

        return task.node.instance_info['ilo_boot_iso']

    # Option 2 - Check if user has provided a boot_iso in Glance. If boot_iso
    # is a supported non-glance href execution will proceed to option 3.
    deploy_info = _parse_deploy_info(task.node)

    image_href = deploy_info['image_source']
    image_properties = (
        images.get_image_properties(
            task.context, image_href, ['boot_iso', 'kernel_id', 'ramdisk_id']))

    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(_LE("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
    # will require synchronisation across conductor nodes for the shared boot
    # ISO.  Such a synchronisation mechanism doesn't exist in ironic as of now.

    # 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 = deploy_utils.get_boot_mode_for_deploy(task.node)
    boot_iso_object_name = _get_boot_iso_object_name(task.node)
    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_uuid, root_uuid,
                               kernel_params, 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
Beispiel #50
0
    def pass_deploy_info(self, task, **kwargs):
        """Continues the deployment of baremetal node over iSCSI.

        This method continues the deployment of the baremetal node over iSCSI
        from where the deployment ramdisk has left off.

        :param task: a TaskManager instance containing the node to act on.
        :param kwargs: kwargs for performing iscsi deployment.
        :raises: InvalidState
        """
        node = task.node
        task.process_event('resume')
        LOG.debug('Continuing the deployment on node %s', node.uuid)

        _destroy_token_file(node)
        is_whole_disk_image = node.driver_internal_info['is_whole_disk_image']
        uuid_dict = iscsi_deploy.continue_deploy(task, **kwargs)
        root_uuid_or_disk_id = uuid_dict.get('root uuid',
                                             uuid_dict.get('disk identifier'))

        # save the node's root disk UUID so that another conductor could
        # rebuild the PXE config file. Due to a shortcoming in Nova objects,
        # we have to assign to node.driver_internal_info so the node knows it
        # has changed.
        driver_internal_info = node.driver_internal_info
        driver_internal_info['root_uuid_or_disk_id'] = root_uuid_or_disk_id
        node.driver_internal_info = driver_internal_info
        node.save()

        try:
            if iscsi_deploy.get_boot_option(node) == "local":
                deploy_utils.try_set_boot_device(task, boot_devices.DISK)

                # If it's going to boot from the local disk, get rid of
                # the PXE configuration files used for the deployment
                pxe_utils.clean_up_pxe_config(task)

                # Ask the ramdisk to install bootloader and
                # wait for the call-back through the vendor passthru
                # 'pass_bootloader_install_info', if it's not a
                # whole disk image.
                if not is_whole_disk_image:
                    LOG.debug('Installing the bootloader on node %s',
                              node.uuid)
                    deploy_utils.notify_ramdisk_to_proceed(kwargs['address'])
                    task.process_event('wait')
                    return
            else:
                pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
                boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
                deploy_utils.switch_pxe_config(pxe_config_path,
                                               root_uuid_or_disk_id, boot_mode,
                                               is_whole_disk_image)

        except Exception as e:
            LOG.error(
                _LE('Deploy failed for instance %(instance)s. '
                    'Error: %(error)s'), {
                        'instance': node.instance_uuid,
                        'error': e
                    })
            msg = _('Failed to continue iSCSI deployment.')
            deploy_utils.set_failed_state(task, msg)
        else:
            iscsi_deploy.finish_deploy(task, kwargs.get('address'))
Beispiel #51
0
    def prepare_instance(self, task):
        """Prepares the boot of instance.

        This method prepares the boot of the instance after reading
        relevant information from the node's instance_info. In case of netboot,
        it updates the dhcp entries and switches the PXE config. In case of
        localboot, it cleans up the PXE config.

        :param task: a task from TaskManager.
        :returns: None
        """
        node = task.node
        boot_option = deploy_utils.get_boot_option(node)
        boot_device = None

        if deploy_utils.is_iscsi_boot(task):
            dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
            provider = dhcp_factory.DHCPFactory()
            provider.update_dhcp(task, dhcp_opts)

            # configure iPXE for iscsi boot
            pxe_config_path = pxe_utils.get_pxe_config_file_path(
                task.node.uuid)
            if not os.path.isfile(pxe_config_path):
                pxe_options = _build_pxe_config_options(task, {})
                pxe_config_template = (
                    deploy_utils.get_pxe_config_template(node))
                pxe_utils.create_pxe_config(
                    task, pxe_options, pxe_config_template)
            deploy_utils.switch_pxe_config(
                pxe_config_path, None,
                deploy_utils.get_boot_mode_for_deploy(node), False,
                iscsi_boot=True)
            boot_device = boot_devices.PXE

        elif boot_option != "local":
            if task.driver.storage.should_write_image(task):
                # Make sure that the instance kernel/ramdisk is cached.
                # This is for the takeover scenario for active nodes.
                instance_image_info = _get_instance_image_info(
                    task.node, task.context)
                _cache_ramdisk_kernel(task.context, task.node,
                                      instance_image_info)

            # If it's going to PXE boot we need to update the DHCP server
            dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
            provider = dhcp_factory.DHCPFactory()
            provider.update_dhcp(task, dhcp_opts)

            iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
            try:
                root_uuid_or_disk_id = task.node.driver_internal_info[
                    'root_uuid_or_disk_id'
                ]
            except KeyError:
                if not task.driver.storage.should_write_image(task):
                    pass
                elif not iwdi:
                    LOG.warning("The UUID for the root partition can't be "
                                "found, unable to switch the pxe config from "
                                "deployment mode to service (boot) mode for "
                                "node %(node)s", {"node": task.node.uuid})
                else:
                    LOG.warning("The disk id for the whole disk image can't "
                                "be found, unable to switch the pxe config "
                                "from deployment mode to service (boot) mode "
                                "for node %(node)s. Booting the instance "
                                "from disk.", {"node": task.node.uuid})
                    pxe_utils.clean_up_pxe_config(task)
                    boot_device = boot_devices.DISK
            else:
                _build_service_pxe_config(task, instance_image_info,
                                          root_uuid_or_disk_id)
                boot_device = boot_devices.PXE
        else:
            # If it's going to boot from the local disk, we don't need
            # PXE config files. They still need to be generated as part
            # of the prepare() because the deployment does PXE boot the
            # deploy ramdisk
            pxe_utils.clean_up_pxe_config(task)
            boot_device = boot_devices.DISK

        # NOTE(pas-ha) do not re-set boot device on ACTIVE nodes
        # during takeover
        if boot_device and task.node.provision_state != states.ACTIVE:
            manager_utils.node_set_boot_device(task, boot_device,
                                               persistent=True)
Beispiel #52
0
    def prepare_instance(self, task):
        """Prepares the boot of instance.

        This method prepares the boot of the instance after reading
        relevant information from the node's instance_info.
        It does the following depending on boot_option for deploy:

        - If the boot mode is 'uefi' and its booting from volume, then it
          sets the iSCSI target info and node to boot from 'UefiTarget'
          boot device.
        - If not 'boot from volume' and the boot_option requested for
          this deploy is 'local' or image is a whole disk image, then
          it sets the node to boot from disk.
        - Otherwise it finds/creates the boot ISO to boot the instance
          image, attaches the boot ISO to the bare metal and then sets
          the node to boot from CDROM.

        :param task: a task from TaskManager.
        :returns: None
        :raises: IloOperationError, if some operation on iLO failed.
        :raises: InstanceDeployFailure, if its try to boot iSCSI volume in
                 'BIOS' boot mode.
        """

        ilo_common.cleanup_vmedia_boot(task)

        boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node)

        if deploy_utils.is_iscsi_boot(task):
            # It will set iSCSI info onto iLO
            if boot_mode == 'uefi':
                # Need to set 'ilo_uefi_iscsi_boot' param for clean up
                driver_internal_info = task.node.driver_internal_info
                driver_internal_info['ilo_uefi_iscsi_boot'] = True
                task.node.driver_internal_info = driver_internal_info
                task.node.save()
                task.driver.management.set_iscsi_boot_target(task)
                manager_utils.node_set_boot_device(task,
                                                   boot_devices.ISCSIBOOT,
                                                   persistent=True)
            else:
                msg = 'Virtual media can not boot volume in BIOS boot mode.'
                raise exception.InstanceDeployFailure(msg)
        else:
            # For iscsi_ilo driver, we boot from disk every time if the image
            # deployed is a whole disk image.
            node = task.node
            iwdi = node.driver_internal_info.get('is_whole_disk_image')
            if deploy_utils.get_boot_option(node) == "local" or iwdi:
                manager_utils.node_set_boot_device(task,
                                                   boot_devices.DISK,
                                                   persistent=True)
            else:
                drv_int_info = node.driver_internal_info
                root_uuid_or_disk_id = drv_int_info.get('root_uuid_or_disk_id')
                if root_uuid_or_disk_id:
                    self._configure_vmedia_boot(task, root_uuid_or_disk_id)
                else:
                    LOG.warning(
                        "The UUID for the root partition could not "
                        "be found for node %s", node.uuid)
        # Set boot mode
        ilo_common.update_boot_mode(task)
        # Need to enable secure boot, if being requested
        ilo_common.update_secure_boot_mode(task, True)