Пример #1
0
def prepare_instance_pxe_config(task,
                                image_info,
                                iscsi_boot=False,
                                ramdisk_boot=False,
                                ipxe_enabled=False):
    """Prepares the config file for PXE boot

    :param task: a task from TaskManager.
    :param image_info: a dict of values of instance image
                       metadata to set on the configuration file.
    :param iscsi_boot: if boot is from an iSCSI volume or not.
    :param ramdisk_boot: if the boot is to a ramdisk configuration.
    :param ipxe_enabled: Default false boolean to indicate if ipxe
                         is in use by the caller.
    :returns: None
    """
    node = task.node
    # Generate options for both IPv4 and IPv6, and they can be
    # filtered down later based upon the port options.
    # TODO(TheJulia): This should be re-tooled during the Victoria
    # development cycle so that we call a single method and return
    # combined options. The method we currently call is relied upon
    # by two eternal projects, to changing the behavior is not ideal.
    dhcp_opts = dhcp_options_for_instance(task, ipxe_enabled, ip_version=4)
    dhcp_opts += dhcp_options_for_instance(task, ipxe_enabled, ip_version=6)
    provider = dhcp_factory.DHCPFactory()
    provider.update_dhcp(task, dhcp_opts)
    pxe_config_path = get_pxe_config_file_path(node.uuid,
                                               ipxe_enabled=ipxe_enabled)
    if not os.path.isfile(pxe_config_path):
        pxe_options = build_pxe_config_options(task,
                                               image_info,
                                               service=ramdisk_boot,
                                               ipxe_enabled=ipxe_enabled)
        if ipxe_enabled:
            pxe_config_template = (deploy_utils.get_ipxe_config_template(node))
        else:
            pxe_config_template = (deploy_utils.get_pxe_config_template(node))
        create_pxe_config(task,
                          pxe_options,
                          pxe_config_template,
                          ipxe_enabled=ipxe_enabled)
    deploy_utils.switch_pxe_config(pxe_config_path,
                                   None,
                                   boot_mode_utils.get_boot_mode(node),
                                   False,
                                   iscsi_boot=iscsi_boot,
                                   ramdisk_boot=ramdisk_boot,
                                   ipxe_enabled=ipxe_enabled)
Пример #2
0
def build_service_pxe_config(task,
                             instance_image_info,
                             root_uuid_or_disk_id,
                             ramdisk_boot=False,
                             ipxe_enabled=False,
                             is_whole_disk_image=None):
    node = task.node
    pxe_config_path = get_pxe_config_file_path(node.uuid,
                                               ipxe_enabled=ipxe_enabled)
    # NOTE(pas-ha) if it is takeover of ACTIVE node or node performing
    # unrescue operation, first ensure that basic PXE configs and links
    # are in place before switching pxe config
    # NOTE(TheJulia): Also consider deploying a valid state to go ahead
    # and check things before continuing, as otherwise deployments can
    # fail if the agent was booted outside the direct actions of the
    # boot interface.
    if (node.provision_state
            in [states.ACTIVE, states.UNRESCUING, states.DEPLOYING]
            and not os.path.isfile(pxe_config_path)):
        pxe_options = build_pxe_config_options(task,
                                               instance_image_info,
                                               service=True,
                                               ipxe_enabled=ipxe_enabled)
        if ipxe_enabled:
            pxe_config_template = deploy_utils.get_ipxe_config_template(node)
        else:
            pxe_config_template = deploy_utils.get_pxe_config_template(node)
        create_pxe_config(task,
                          pxe_options,
                          pxe_config_template,
                          ipxe_enabled=ipxe_enabled)

    if is_whole_disk_image is None:
        is_whole_disk_image = node.driver_internal_info.get(
            'is_whole_disk_image')

    deploy_utils.switch_pxe_config(
        pxe_config_path,
        root_uuid_or_disk_id,
        boot_mode_utils.get_boot_mode(node),
        is_whole_disk_image,
        deploy_utils.is_trusted_boot_requested(node),
        deploy_utils.is_iscsi_boot(task),
        ramdisk_boot,
        ipxe_enabled=ipxe_enabled)
Пример #3
0
def create_pxe_config(task, pxe_options, template=None, ipxe_enabled=False):
    """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 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:
        if ipxe_enabled:
            template = deploy_utils.get_ipxe_config_template(task.node)
        else:
            template = deploy_utils.get_pxe_config_template(task.node)

    _ensure_config_dirs_exist(task, ipxe_enabled)

    pxe_config_file_path = get_pxe_config_file_path(task.node.uuid,
                                                    ipxe_enabled=ipxe_enabled)
    is_uefi_boot_mode = (boot_mode_utils.get_boot_mode(task.node) == 'uefi')
    uefi_with_grub = is_uefi_boot_mode and not ipxe_enabled

    # 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.
    if uefi_with_grub:
        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)

    # Always write the mac addresses
    _link_mac_pxe_configs(task, ipxe_enabled=ipxe_enabled)
    if uefi_with_grub:
        try:
            _link_ip_address_pxe_configs(task, ipxe_enabled)
        # NOTE(TheJulia): The IP address support will fail if the
        # dhcp_provider interface is set to none. This will result
        # in the MAC addresses and DHCP files being written, and
        # we can remove IP address creation for the grub use.
        except exception.FailedToGetIPAddressOnPort as e:
            if CONF.dhcp.dhcp_provider != 'none':
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        'Unable to create boot config, IP address '
                        'was unable to be retrieved. %(error)s', {'error': e})
Пример #4
0
    def prepare_ramdisk(self, task, ramdisk_params):
        """Prepares the boot of Ironic ramdisk using PXE.

        This method prepares the boot of the deploy or rescue 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

        # Label indicating a deploy or rescue operation being carried out on
        # the node, 'deploy' or 'rescue'. Unless the node is in a rescue like
        # state, the mode is set to 'deploy', indicating deploy operation is
        # being carried out.
        mode = deploy_utils.rescue_or_deploy_mode(node)

        if self.ipxe_enabled:
            # NOTE(mjturek): At this point, the ipxe boot script should
            # already exist as it is created at startup time. However, we
            # call the boot script create method here to assert its
            # existence and handle the unlikely case that it wasn't created
            # or was deleted.
            pxe_utils.create_ipxe_boot_script()

        # Generate options for both IPv4 and IPv6, and they can be
        # filtered down later based upon the port options.
        # TODO(TheJulia): This should be re-tooled during the Victoria
        # development cycle so that we call a single method and return
        # combined options. The method we currently call is relied upon
        # by two eternal projects, to changing the behavior is not ideal.
        dhcp_opts = pxe_utils.dhcp_options_for_instance(
            task, ipxe_enabled=self.ipxe_enabled, ip_version=4)
        dhcp_opts += pxe_utils.dhcp_options_for_instance(
            task, ipxe_enabled=self.ipxe_enabled, ip_version=6)
        provider = dhcp_factory.DHCPFactory()
        provider.update_dhcp(task, dhcp_opts)

        pxe_info = pxe_utils.get_image_info(node,
                                            mode=mode,
                                            ipxe_enabled=self.ipxe_enabled)

        # 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_utils.get_instance_image_info(
                    task, ipxe_enabled=self.ipxe_enabled))

        boot_mode_utils.sync_boot_mode(task)

        pxe_options = pxe_utils.build_pxe_config_options(
            task,
            pxe_info,
            ipxe_enabled=self.ipxe_enabled,
            ramdisk_params=ramdisk_params)
        # TODO(dtantsur): backwards compability hack, remove in the V release
        if ramdisk_params.get("ipa-api-url"):
            pxe_options["ipa-api-url"] = ramdisk_params["ipa-api-url"]

        if self.ipxe_enabled:
            pxe_config_template = deploy_utils.get_ipxe_config_template(node)
        else:
            pxe_config_template = deploy_utils.get_pxe_config_template(node)

        pxe_utils.create_pxe_config(task,
                                    pxe_options,
                                    pxe_config_template,
                                    ipxe_enabled=self.ipxe_enabled)
        persistent = self._persistent_ramdisk_boot(node)
        manager_utils.node_set_boot_device(task,
                                           boot_devices.PXE,
                                           persistent=persistent)

        if self.ipxe_enabled and CONF.pxe.ipxe_use_swift:
            kernel_label = '%s_kernel' % mode
            ramdisk_label = '%s_ramdisk' % mode
            pxe_info.pop(kernel_label, None)
            pxe_info.pop(ramdisk_label, None)

        if pxe_info:
            pxe_utils.cache_ramdisk_kernel(task,
                                           pxe_info,
                                           ipxe_enabled=self.ipxe_enabled)

        LOG.debug(
            'Ramdisk (i)PXE boot for node %(node)s has been prepared '
            'with kernel params %(params)s', {
                'node': node.uuid,
                'params': pxe_options
            })