Example #1
0
def _setup_deploy_iso(task, ramdisk_options):
    """Attaches virtual media and sets it as boot device.

    This method attaches the given deploy ISO as virtual media, prepares the
    arguments for ramdisk in virtual media floppy.

    :param task: a TaskManager instance containing the node to act on.
    :param ramdisk_options: the options to be passed to the ramdisk in virtual
        media floppy.
    :raises: ImageRefValidationFailed if no image service can handle specified
       href.
    :raises: ImageCreationFailed, if it failed while creating the floppy image.
    :raises: IRMCOperationError, if some operation on iRMC failed.
    :raises: InvalidParameterValue if the validation of the
        PowerInterface or ManagementInterface fails.
    """
    d_info = task.node.driver_info

    deploy_iso_href = d_info["irmc_deploy_iso"]
    if service_utils.is_image_href_ordinary_file_name(deploy_iso_href):
        deploy_iso_file = deploy_iso_href
    else:
        deploy_iso_file = _get_deploy_iso_name(task.node)
        deploy_iso_fullpathname = os.path.join(CONF.irmc.remote_image_share_root, deploy_iso_file)
        images.fetch(task.context, deploy_iso_href, deploy_iso_fullpathname)

    _setup_vmedia_for_boot(task, deploy_iso_file, ramdisk_options)
    manager_utils.node_set_boot_device(task, boot_devices.CDROM)
Example #2
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_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.
        """

        ilo_common.cleanup_vmedia_boot(task)

        # 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(_LW("The UUID for the root partition could not "
                                "be found for node %s"), node.uuid)
Example #3
0
File: pxe.py Project: n1zyy/ironic
    def deploy(self, task):
        """Start deployment of the task's node'.

        Fetches instance image, creates a temporary keystone token file,
        updates the Neutron DHCP port options for next boot, and issues a
        reboot request to the power driver.
        This causes the node to boot into the deployment ramdisk and triggers
        the next phase of PXE-based deployment via
        VendorPassthru._continue_deploy().

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYING.
        """
        _cache_instance_image(task.context, task.node)
        _check_image_size(task)

        # TODO(yuriyz): more secure way needed for pass auth token
        #               to deploy ramdisk
        _create_token_file(task)
        dhcp_opts = pxe_utils.dhcp_options_for_instance()
        neutron.update_neutron(task, dhcp_opts)
        manager_utils.node_set_boot_device(task, 'pxe', persistent=True)
        manager_utils.node_power_action(task, states.REBOOT)

        return states.DEPLOYWAIT
Example #4
0
def _setup_vmedia(task, mode, ramdisk_options):
    """Attaches virtual media and sets it as boot device.

    This method attaches the deploy or rescue ISO as virtual media, prepares
    the arguments for ramdisk in virtual media floppy.

    :param task: a TaskManager instance containing the node to act on.
    :param mode: Label indicating a deploy or rescue operation being
                 carried out on the node. Supported values are
                 'deploy' and 'rescue'.
    :param ramdisk_options: the options to be passed to the ramdisk in virtual
        media floppy.
    :raises: ImageRefValidationFailed if no image service can handle specified
       href.
    :raises: ImageCreationFailed, if it failed while creating the floppy image.
    :raises: IRMCOperationError, if some operation on iRMC failed.
    :raises: InvalidParameterValue if the validation of the
        PowerInterface or ManagementInterface fails.
    """

    if mode == 'rescue':
        iso = task.node.driver_info['irmc_rescue_iso']
    else:
        iso = task.node.driver_info['irmc_deploy_iso']

    if _is_image_href_ordinary_file_name(iso):
        iso_file = iso
    else:
        iso_file = _get_iso_name(task.node, label=mode)
        iso_fullpathname = os.path.join(
            CONF.irmc.remote_image_share_root, iso_file)
        images.fetch(task.context, iso, iso_fullpathname)

    _setup_vmedia_for_boot(task, iso_file, ramdisk_options)
    manager_utils.node_set_boot_device(task, boot_devices.CDROM)
Example #5
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 database.

        :param task: a task from TaskManager.
        :returns: None
        """
        if task.node.driver_internal_info.get('boot_from_volume'):
            LOG.debug('Node %(node)s is configured for booting from a remote '
                      'volume.',
                      {'node': task.node.uuid})
            self._configure_boot_from_volume(task)
            return

        _cleanup_vmedia_boot(task)

        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:
            driver_internal_info = node.driver_internal_info
            root_uuid_or_disk_id = driver_internal_info['root_uuid_or_disk_id']
            self._configure_vmedia_boot(task, root_uuid_or_disk_id)

        # Enable secure boot, if being requested
        if deploy_utils.is_secure_boot_requested(node):
            irmc_common.set_secure_boot_mode(node, enable=True)
Example #6
0
    def _configure_vmedia_boot(self, task, root_uuid):
        """Configure vmedia boot for the node.

        :param task: a task from TaskManager.
        :param root_uuid: uuid of the root partition
        :returns: None
        :raises: IloOperationError, if some operation on iLO failed.
        """

        node = task.node
        boot_iso = _get_boot_iso(task, root_uuid)
        if not boot_iso:
            LOG.error("Cannot get boot ISO for node %s", node.uuid)
            return

        # Upon deploy complete, some distros cloud images reboot the system as
        # part of its configuration. Hence boot device should be persistent and
        # not one-time.
        ilo_common.setup_vmedia_for_boot(task, boot_iso)
        manager_utils.node_set_boot_device(task,
                                           boot_devices.CDROM,
                                           persistent=True)

        i_info = node.instance_info
        i_info['ilo_boot_iso'] = boot_iso
        node.instance_info = i_info
        node.save()
Example #7
0
def setup_vmedia(task, iso, ramdisk_options):
    """Attaches virtual media and sets it as boot device.

    This method attaches the given bootable ISO as virtual media, prepares the
    arguments for ramdisk in virtual media floppy.

    :param task: a TaskManager instance containing the node to act on.
    :param iso: a bootable ISO image href to attach to. 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.
    :param ramdisk_options: the options to be passed to the ramdisk in virtual
        media floppy.
    :raises: ImageCreationFailed, if it failed while creating the floppy image.
    :raises: IloOperationError, if some operation on iLO failed.
    """
    setup_vmedia_for_boot(task, iso, ramdisk_options)

    # In UEFI boot mode, upon inserting virtual CDROM, one has to reset the
    # system to see it as a valid boot device in persistent boot devices.
    # But virtual CDROM device is always available for one-time boot.
    # During enable/disable of secure boot settings, iLO internally resets
    # the server twice. But it retains one time boot settings across internal
    # resets. Hence no impact of this change for secure boot deploy.
    manager_utils.node_set_boot_device(task, boot_devices.CDROM)
Example #8
0
    def reboot_to_instance(self, task, **kwargs):
        task.process_event('resume')
        node = task.node
        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

        LOG.info(_LI('Image successfully written to node %s'), node.uuid)
        LOG.debug('Rebooting node %s to instance', node.uuid)

        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:
            task.driver.boot.clean_up_ramdisk(task)
Example #9
0
    def reboot_to_instance(self, task, **kwargs):
        task.process_event('resume')
        node = task.node
        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

        LOG.info(_LI('Image successfully written to node %s'), node.uuid)
        LOG.debug('Rebooting node %s to instance', node.uuid)

        manager_utils.node_set_boot_device(task, 'disk', persistent=True)
        self.reboot_and_finish_deploy(task)
        # NOTE(TheJulia): If we 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): This shouldn't get called for virtual media deploy
        # drivers (iLO and iRMC).  This is just a hack, but it will be taken
        # care in boot/deploy interface separation.
        if (_driver_uses_pxe(task.driver) and
                node.driver_internal_info.get('is_whole_disk_image')):
            _clean_up_pxe(task)
Example #10
0
def try_set_boot_device(task, device, persistent=True):
    """Tries to set the boot device on the node.

    This method tries to set the boot device on the node to the given
    boot device.  Under uefi boot mode, setting of boot device may differ
    between different machines. IPMI does not work for setting boot
    devices in uefi mode for certain machines.  This method ignores the
    expected IPMI failure for uefi boot mode and just logs a message.
    In error cases, it is expected the operator has to manually set the
    node to boot from the correct device.

    :param task: a TaskManager object containing the node
    :param device: the boot device
    :param persistent: Whether to set the boot device persistently
    :raises: Any exception from set_boot_device except IPMIFailure
        (setting of boot device using ipmi is expected to fail).
    """
    try:
        manager_utils.node_set_boot_device(task, device,
                                           persistent=persistent)
    except exception.IPMIFailure:
        if get_boot_mode_for_deploy(task.node) == 'uefi':
            LOG.warning(_LW("ipmitool is unable to set boot device while "
                            "the node %s is in UEFI boot mode. Please set "
                            "the boot device manually.") % task.node.uuid)
        else:
            raise
Example #11
0
    def deploy(self, task):
        """Start deployment of the task's node'.

        Config host file and xcat dhcp, generate image info for xcat
        and issues a  reboot request to the power driver.
        This causes the node to boot into the deployment ramdisk and triggers
        the next phase of PXE-based deployment via
        VendorPassthru._continue_deploy().

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYDONE.
        """

        d_info = _parse_deploy_info(task.node)
        if not task.node.instance_info.get('fixed_ip_address') or not task.node.instance_info.get('image_name'):
            raise exception.InvalidParameterValue
        self._config_host_file(d_info,task.node.instance_info.get('fixed_ip_address'))
        self._make_dhcp()
        self._nodeset_osimage(d_info,task.node.instance_info.get('image_name'))
        manager_utils.node_set_boot_device(task, 'pxe', persistent=True)
        manager_utils.node_power_action(task, states.REBOOT)
        try:
            self._wait_for_node_deploy(task)
        except xcat_exception.xCATDeploymentFailure:
            LOG.info(_("xcat deployment failed"))
            return states.ERROR

        return states.DEPLOYDONE
def _deploy(task, node_address):
    """Internal function for deployment to a node."""
    notags = ['wait'] if CONF.ansible.use_ramdisk_callback else []
    node = task.node
    LOG.debug('IP of node %(node)s is %(ip)s',
              {'node': node.uuid, 'ip': node_address})
    iwdi = node.driver_internal_info.get('is_whole_disk_image')
    variables = _prepare_variables(task)
    if iwdi:
        notags.append('parted')
    else:
        variables.update(_parse_partitioning_info(task.node))
    playbook, user, key = _parse_ansible_driver_info(task.node)
    node_list = [(node.uuid, node_address, user, node.extra)]
    extra_vars = _prepare_extra_vars(node_list, variables=variables)

    LOG.debug('Starting deploy on node %s', node.uuid)
    # any caller should manage exceptions raised from here
    _run_playbook(playbook, extra_vars, key, notags=notags)
    LOG.info(_LI('Ansible complete deploy on node %s'), node.uuid)

    LOG.debug('Rebooting node %s to instance', node.uuid)
    manager_utils.node_set_boot_device(task, 'disk', persistent=True)
    _reboot_and_finish_deploy(task)

    task.driver.boot.clean_up_ramdisk(task)
Example #13
0
    def pass_deploy_info(self, task, **kwargs):
        """Continues the iSCSI deployment from where ramdisk left off.

        This method continues the iSCSI deployment from the conductor node
        and writes the deploy image to the bare metal's disk. After that,
        it does the following depending on boot_option for deploy:

        - If the boot_option requested for this deploy is 'local', then it
          sets the node to boot from disk (ramdisk installs the boot loader
          present within the image to the bare metal's disk).
        - If the boot_option requested is 'netboot' or no boot_option is
          requested, 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 TaskManager instance containing the node to act on.
        :param kwargs: kwargs containing parameters for iSCSI deployment.
        :raises: InvalidState
        """
        node = task.node
        task.process_event('resume')

        iwdi = node.driver_internal_info.get('is_whole_disk_image')
        ilo_common.cleanup_vmedia_boot(task)
        uuid_dict = iscsi_deploy.continue_deploy(task, **kwargs)
        root_uuid_or_disk_id = uuid_dict.get(
            'root uuid', uuid_dict.get('disk identifier'))

        try:
            # Set boot mode
            ilo_common.update_boot_mode(task)

            # Need to enable secure boot, if being requested
            _update_secure_boot_mode(task, True)

            # For iscsi_ilo driver, we boot from disk every time if the image
            # deployed is a whole disk image.
            if iscsi_deploy.get_boot_option(node) == "local" or iwdi:
                manager_utils.node_set_boot_device(task, boot_devices.DISK,
                                                   persistent=True)

                # 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 iwdi:
                    deploy_utils.notify_ramdisk_to_proceed(kwargs['address'])
                    task.process_event('wait')
                    return
            else:
                self._configure_vmedia_boot(task, root_uuid_or_disk_id)
        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'))
Example #14
0
 def _configure_vmedia_boot(self, task, root_uuid_or_disk_id):
     """Configure vmedia boot for the node."""
     node = task.node
     _prepare_boot_iso(task, root_uuid_or_disk_id)
     _setup_vmedia_for_boot(
         task, node.driver_internal_info['irmc_boot_iso'])
     manager_utils.node_set_boot_device(task, boot_devices.CDROM,
                                        persistent=True)
Example #15
0
    def reboot_to_instance(self, task):
        node = task.node
        LOG.info('Ansible complete deploy on node %s', node.uuid)

        LOG.debug('Rebooting node %s to instance', node.uuid)
        manager_utils.node_set_boot_device(task, 'disk', persistent=True)
        self.reboot_and_finish_deploy(task)
        task.driver.boot.clean_up_ramdisk(task)
Example #16
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:
            # 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()

        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)

        pxe_config_template = deploy_utils.get_pxe_config_template(node)

        pxe_utils.create_pxe_config(task, pxe_options,
                                    pxe_config_template)
        persistent = strutils.bool_from_string(
            node.driver_info.get('force_persistent_boot_device',
                                 False))
        manager_utils.node_set_boot_device(task, boot_devices.PXE,
                                           persistent=persistent)

        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)
Example #17
0
    def pass_deploy_info(self, task, **kwargs):
        LOG.debug("Pass deploy info for the deployment on node %s", task.node.uuid)
        manager_utils.node_set_boot_device(task, boot_devices.PXE, persistent=True)
        # Set boot mode
        ilo_common.update_boot_mode(task)
        # Need to enable secure boot, if being requested
        _update_secure_boot_mode(task, True)

        super(IloPXEVendorPassthru, self).pass_deploy_info(task, **kwargs)
Example #18
0
    def inspect_hardware(self, task):
        """Inspect hardware.

        Inspect hardware to obtain the essential hardware properties and
        mac addresses.

        :param task: a task from TaskManager.
        :raises: HardwareInspectionFailure, if hardware inspection failed.
        :returns: states.MANAGEABLE, if hardware inspection succeeded.
        """
        node = task.node
        kwargs = {}
        # Inspect additional capabilities task requires node with power on
        # status
        old_power_state = task.driver.power.get_power_state(task)
        if old_power_state == states.POWER_OFF:
            manager_utils.node_set_boot_device(task, boot_devices.BIOS, False)
            manager_utils.node_power_action(task, states.POWER_ON)

            LOG.info("The Node %(node_uuid)s being powered on for inspection",
                     {'node_uuid': task.node.uuid})

            kwargs['sleep_flag'] = True
        traits_obj = objects.TraitList.get_by_node_id(task.context, node.id)
        existing_traits = traits_obj.get_trait_names()
        props, macs, new_traits = _inspect_hardware(node,
                                                    existing_traits,
                                                    **kwargs)
        node.properties = dict(node.properties, **props)
        if existing_traits != new_traits:
            objects.TraitList.create(task.context, node.id, new_traits)
        node.save()

        for mac in macs:
            try:
                new_port = objects.Port(task.context,
                                        address=mac, node_id=node.id)
                new_port.create()
                LOG.info("Port created for MAC address %(address)s "
                         "for node %(node_uuid)s during inspection",
                         {'address': mac, 'node_uuid': node.uuid})
            except exception.MACAlreadyExists:
                LOG.warning("Port already existed for MAC address "
                            "%(address)s for node %(node_uuid)s "
                            "during inspection",
                            {'address': mac, 'node_uuid': node.uuid})

        LOG.info("Node %s inspected", node.uuid)
        # restore old power state
        if old_power_state == states.POWER_OFF:
            manager_utils.node_power_action(task, states.POWER_OFF)

            LOG.info("The Node %(node_uuid)s being powered off after "
                     "inspection",
                     {'node_uuid': task.node.uuid})

        return states.MANAGEABLE
    def pass_deploy_info(self, task, **kwargs):
        """Continues the deployment of baremetal node."""

        node = task.node
        task.process_event('resume')
        err_msg = _('Failed to continue deployment with Fuel Agent.')

        agent_status = kwargs.get('status')
        if agent_status != 'ready':
            LOG.error(_LE('Deploy failed for node %(node)s. Fuel Agent is not '
                      'in ready state, error: %(error)s'), {'node': node.uuid,
                      'error': kwargs.get('error_message')})
            deploy_utils.set_failed_state(task, err_msg)
            return

        params = _parse_driver_info(node)
        params['host'] = kwargs.get('address')
        cmd = ('%s --data_driver ironic  --config-file '
               '/etc/fuel-agent/fuel-agent.conf' % params.pop('script'))
        if CONF.debug:
            cmd += ' --debug'
        instance_info = node.instance_info

        try:
            deploy_data = _get_deploy_data(task.context,
                                           instance_info['image_source'])

            image_data = {"/": {"uri": instance_info['image_url'],
                                "format": "raw",
                                "container": "raw"}}

            deploy_data['ks_meta']['image_data'] = image_data

            ssh = utils.ssh_connect(params)
            sftp = ssh.open_sftp()
            _sftp_upload(sftp, json.dumps(deploy_data), '/tmp/provision.json')

            # swift configdrive store should be disabled
            configdrive = instance_info.get('configdrive')
            if configdrive is not None:
                _sftp_upload(sftp, configdrive, '/tmp/config-drive.img')

            _ssh_execute(ssh, cmd, params)
            LOG.info(_LI('Fuel Agent pass on node %s'), node.uuid)
            manager_utils.node_set_boot_device(task, boot_devices.DISK,
                                               persistent=True)
            manager_utils.node_power_action(task, states.REBOOT)
        except Exception as e:
            msg = (_('Deploy failed for node %(node)s. Error: %(error)s') %
                   {'node': node.uuid, 'error': e})
            LOG.error(msg)
            deploy_utils.set_failed_state(task, msg)
        else:
            task.process_event('done')
            LOG.info(_LI('Deployment to node %s done'), task.node.uuid)
Example #20
0
    def deploy(self, task):
        """Start deployment of the task's node.

        This method sets the boot device to 'NETWORK' and then calls
        PXEDeploy's deploy method to deploy on the given node.

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYWAIT.
        """
        manager_utils.node_set_boot_device(task, boot_devices.PXE)
        return super(IloPXEDeploy, self).deploy(task)
Example #21
0
def _do_pxe_boot(task, ports=None):
    """Reboot the node into the PXE ramdisk.

    :param task: a TaskManager instance
    :param ports: a list of Neutron port dicts to update DHCP options on. If
        None, will get the list of ports from the Ironic port objects.
    """
    dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
    provider = dhcp_factory.DHCPFactory()
    provider.update_dhcp(task, dhcp_opts, ports)
    manager_utils.node_set_boot_device(task, boot_devices.PXE, persistent=True)
    manager_utils.node_power_action(task, states.REBOOT)
Example #22
0
    def test_node_set_boot_device_valid(self):
        mgr_utils.mock_the_extension_manager(driver="fake_ipmitool")
        self.driver = driver_factory.get_driver("fake_ipmitool")
        ipmi_info = utils.get_test_ipmi_info()
        node = obj_utils.create_test_node(
            self.context, uuid=uuidutils.generate_uuid(), driver="fake_ipmitool", driver_info=ipmi_info
        )
        task = task_manager.TaskManager(self.context, node.uuid)

        with mock.patch.object(self.driver.management, "set_boot_device") as mock_sbd:
            conductor_utils.node_set_boot_device(task, device="pxe")
            mock_sbd.assert_called_once_with(task, device="pxe", persistent=False)
Example #23
0
def _attach_boot_iso(task):
    """Attaches boot ISO for a deployed node.

    This method checks the instance info of the baremetal node for a
    boot iso.  It attaches the boot ISO on the baremetal node, and then
    sets the node to boot from virtual media cdrom.

    :param task: a TaskManager instance containing the node to act on.
    """
    i_info = task.node.instance_info

    if 'ilo_boot_iso' in i_info:
        ilo_common.setup_vmedia_for_boot(task, i_info['ilo_boot_iso'])
        manager_utils.node_set_boot_device(task, boot_devices.CDROM)
Example #24
0
    def test_node_set_boot_device_adopting(self):
        mgr_utils.mock_the_extension_manager(driver="fake_ipmitool")
        self.driver = driver_factory.get_driver("fake_ipmitool")
        ipmi_info = utils.get_test_ipmi_info()
        node = obj_utils.create_test_node(self.context,
                                          uuid=uuidutils.generate_uuid(),
                                          driver='fake_ipmitool',
                                          driver_info=ipmi_info,
                                          provision_state=states.ADOPTING)
        task = task_manager.TaskManager(self.context, node.uuid)

        with mock.patch.object(self.driver.management,
                               'set_boot_device') as mock_sbd:
            conductor_utils.node_set_boot_device(task,
                                                 device='pxe')
            self.assertFalse(mock_sbd.called)
Example #25
0
def try_set_boot_device(task, device, persistent=True):
    # NOTE(faizan): Under UEFI boot mode, setting of boot device may differ
    # between different machines. IPMI does not work for setting boot
    # devices in UEFI mode for certain machines.
    # Expected IPMI failure for uefi boot mode. Logging a message to
    # set the boot device manually and continue with deploy.
    try:
        manager_utils.node_set_boot_device(task, device, persistent=persistent)
    except exception.IPMIFailure:
        if driver_utils.get_node_capability(task.node,
                                            'boot_mode') == 'uefi':
            LOG.warning(_LW("ipmitool is unable to set boot device while "
                            "the node %s is in UEFI boot mode. Please set "
                            "the boot device manually.") % task.node.uuid)
        else:
            raise
Example #26
0
    def _continue_deploy(self, task, **kwargs):
        """Continues the iSCSI deployment from where ramdisk left off.

        Continues the iSCSI deployment from the conductor node, finds the
        boot ISO to boot the node, and sets the node to boot from boot ISO.

        :param task: a TaskManager instance containing the node to act on.
        :param kwargs: kwargs containing parameters for iSCSI deployment.
        """
        node = task.node
        if node.provision_state != states.DEPLOYWAIT:
            LOG.error(_LE('Node %s is not waiting to be deployed.'), node.uuid)
            return

        ilo_common.cleanup_vmedia_boot(task)
        root_uuid = iscsi_deploy.continue_deploy(task, **kwargs)

        if not root_uuid:
            return

        try:
            boot_iso = _get_boot_iso(task, root_uuid)

            if not boot_iso:
                LOG.error(_LE("Cannot get boot ISO for node %s"), node.uuid)
                return

            ilo_common.setup_vmedia_for_boot(task, boot_iso)
            manager_utils.node_set_boot_device(task, boot_devices.CDROM)

            address = kwargs.get('address')
            deploy_utils.notify_deploy_complete(address)

            node.provision_state = states.ACTIVE
            node.target_provision_state = states.NOSTATE

            i_info = node.instance_info
            i_info['ilo_boot_iso'] = boot_iso
            node.instance_info = i_info
            node.save()
            LOG.info(_LI('Deployment to node %s done'), node.uuid)
        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.')
            iscsi_deploy.set_failed_state(task, msg)
Example #27
0
    def reboot_and_finish_deploy(self, task):
        """Helper method to trigger reboot on the node and finish deploy.

        This method initiates a reboot on the node. On success, it
        marks the deploy as complete. On failure, it logs the error
        and marks deploy as failure.

        :param task: a TaskManager object containing the node
        :raises: InstanceDeployFailure, if node reboot failed.
        """
        wait = CONF.agent.post_deploy_get_power_state_retry_interval * 1000
        attempts = CONF.agent.post_deploy_get_power_state_retries + 1

        @retrying.retry(
            stop_max_attempt_number=attempts,
            retry_on_result=lambda state: state != states.POWER_OFF,
            wait_fixed=wait
        )
        def _wait_until_powered_off(task):
            return task.driver.power.get_power_state(task)

        node = task.node

        try:
            try:
                self._client.power_off(node)
                _wait_until_powered_off(task)
            except Exception as e:
                LOG.warning(
                    'Failed to soft power off node %(node_uuid)s '
                    'in at least %(timeout)d seconds. Error: %(error)s',
                    {'node_uuid': node.uuid,
                     'timeout': (wait * (attempts - 1)) / 1000,
                     'error': e})
                manager_utils.node_power_action(task, states.POWER_OFF)

            manager_utils.node_set_boot_device(task, 'disk',
                                               persistent=True)
            manager_utils.node_power_action(task, states.POWER_ON)
        except Exception as e:
            msg = (_('Error rebooting node %(node)s after deploy. '
                     'Error: %(error)s') %
                   {'node': node.uuid, 'error': e})
            agent_base_vendor.log_and_raise_deployment_error(task, msg)

        task.process_event('done')
        LOG.info('Deployment to node %s done', task.node.uuid)
Example #28
0
    def reboot_to_instance(self, task):
        node = task.node
        LOG.info('Ansible complete deploy on node %s', node.uuid)

        LOG.debug('Rebooting node %s to instance', node.uuid)
        manager_utils.node_set_boot_device(task, 'disk', persistent=True)
        self.reboot_and_finish_deploy(task)
        task.driver.boot.clean_up_ramdisk(task)

        if not node.deploy_step:
            # TODO(rloo): delete this 'if' part after deprecation period, when
            # we expect all (out-of-tree) drivers to support deploy steps.
            # After which we will always notify_conductor_resume_deploy().
            task.process_event('done')
            LOG.info('Deployment to node %s done', task.node.uuid)
        else:
            manager_utils.notify_conductor_resume_deploy(task)
Example #29
0
    def deploy(self, task):
        """Perform a deployment to a node.

        Perform the necessary work to deploy an image onto the specified node.
        This method will be called after prepare(), which may have already
        performed any preparatory steps, such as pre-caching some data for the
        node.

        :param task: a TaskManager instance.
        :returns: status of the deploy. One of ironic.common.states.
        """
        dhcp_opts = pxe_utils.dhcp_options_for_instance()
        neutron.update_neutron(task, dhcp_opts)
        manager_utils.node_set_boot_device(task, 'pxe', persistent=True)
        manager_utils.node_power_action(task, states.REBOOT)

        return states.DEPLOYWAIT
Example #30
0
    def reboot_to_instance(self, task, **kwargs):
        node = task.node
        LOG.debug('Preparing to reboot to instance for node %s',
                  node.uuid)
        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

        LOG.debug('Rebooting node %s to disk', node.uuid)

        manager_utils.node_set_boot_device(task, 'disk', persistent=True)
        self.reboot_and_finish_deploy(task)
Example #31
0
    def deploy(self, task, node):
        """Perform start deployment a node.

        Creates a temporary keystone token file, updates the Neutron DHCP port
        options for next boot, and issues a reboot request to the power driver.
        This causes the node to boot into the deployment ramdisk and triggers
        the next phase of PXE-based deployment via
        VendorPassthru._continue_deploy().

        :param task: a TaskManager instance.
        :param node: the Node to act upon.
        :returns: deploy state DEPLOYING.
        """
        # TODO(yuriyz): more secure way needed for pass auth token
        #               to deploy ramdisk
        _create_token_file(task, node)
        _update_neutron(task, node)
        manager_utils.node_set_boot_device(task, node, 'pxe', persistent=True)
        manager_utils.node_power_action(task, node, states.REBOOT)

        return states.DEPLOYWAIT
Example #32
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 database.

        :param task: a task from TaskManager.
        :returns: None
        """
        _cleanup_vmedia_boot(task)

        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:
            driver_internal_info = node.driver_internal_info
            root_uuid_or_disk_id = driver_internal_info['root_uuid_or_disk_id']
            self._configure_vmedia_boot(task, root_uuid_or_disk_id)
Example #33
0
    def reboot_to_instance(self, task, **kwargs):
        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
            task.node.driver_internal_info['root_uuid_or_disk_id'] = root_uuid
            task.node.save()
            self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid)
        LOG.info(_LI('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)
Example #34
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_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.
        """

        ilo_common.cleanup_vmedia_boot(task)

        # 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)
Example #35
0
    def reboot_to_instance(self, task, **kwargs):
        node = task.node
        LOG.debug('Preparing to reboot to instance for node %s', node.uuid)
        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

        LOG.debug('Rebooting node %s to disk', node.uuid)

        manager_utils.node_set_boot_device(task, 'disk', persistent=True)
        manager_utils.node_power_action(task, states.REBOOT)

        task.process_event('done')
Example #36
0
def _attach_boot_iso_if_needed(task):
    """Attaches boot ISO for a deployed node.

    This method checks the instance info of the baremetal node for a
    boot iso. If the instance info has a value of key 'ilo_boot_iso',
    it indicates that 'boot_option' is 'netboot'. Therefore it attaches
    the boot ISO on the baremetal node and then sets the node to boot from
    virtual media cdrom.

    :param task: a TaskManager instance containing the node to act on.
    """
    i_info = task.node.instance_info
    node_state = task.node.provision_state

    # NOTE: On instance rebuild, ilo_boot_iso will be present in
    # instance_info but the node will be in DEPLOYING state.
    # In such a scenario, the ilo_boot_iso shouldn't be
    # attached to the node while powering on the node (the node
    # should boot from deploy ramdisk instead, which will already
    # be attached by the deploy driver).
    if 'ilo_boot_iso' in i_info and node_state == states.ACTIVE:
        ilo_common.setup_vmedia_for_boot(task, i_info['ilo_boot_iso'])
        manager_utils.node_set_boot_device(task, boot_devices.CDROM)
Example #37
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 = boot_mode_utils.get_boot_mode(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(IloiPXEBoot, self).prepare_instance(task)
Example #38
0
    def _check_boot_status(self, task):
        if not isinstance(task.driver.boot, PXEBaseMixin):
            return

        if not _should_retry_boot(task.node):
            return

        task.upgrade_lock(purpose='retrying PXE boot')

        # Retry critical checks after acquiring the exclusive lock.
        if (task.node.maintenance or task.node.provision_state
                not in self._RETRY_ALLOWED_STATES
                or not _should_retry_boot(task.node)):
            return

        LOG.info('Booting the ramdisk on node %(node)s is taking more than '
                 '%(timeout)d seconds, retrying boot',
                 {'node': task.node.uuid,
                  'timeout': CONF.pxe.boot_retry_timeout})

        manager_utils.node_power_action(task, states.POWER_OFF)
        manager_utils.node_set_boot_device(task, boot_devices.PXE,
                                           persistent=False)
        manager_utils.node_power_action(task, states.POWER_ON)
Example #39
0
    def deploy(self, task):
        """Start deployment of the task's node'.

        Fetches instance image, creates a temporary keystone token file,
        updates the Neutron DHCP port options for next boot, and issues a
        reboot request to the power driver.
        This causes the node to boot into the deployment ramdisk and triggers
        the next phase of PXE-based deployment via
        VendorPassthru._continue_deploy().

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYING.
        """
        _cache_instance_image(task.context, task.node)
        _check_image_size(task)

        # TODO(yuriyz): more secure way needed for pass auth token
        #               to deploy ramdisk
        _create_token_file(task)
        _update_neutron(task)
        manager_utils.node_set_boot_device(task, 'pxe', persistent=True)
        manager_utils.node_power_action(task, states.REBOOT)

        return states.DEPLOYWAIT
Example #40
0
    def pass_deploy_info(self, task, **kwargs):
        """Continues the iSCSI deployment from where ramdisk left off.

        This method continues the iSCSI deployment from the conductor node
        and writes the deploy image to the bare metal's disk.  After that,
        it does the following depending on boot_option for deploy:

        - If the boot_option requested for this deploy is 'local', then it
          sets the node to boot from disk (ramdisk installs the boot loader
          present within the image to the bare metal's disk).
        - If the boot_option requested is 'netboot' or no boot_option is
          requested, 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 TaskManager instance containing the node to act on.
        :param kwargs: kwargs containing parameters for iSCSI deployment.
        :raises: InvalidState
        """
        node = task.node
        LOG.warning(_LW("The node %s is using the bash deploy ramdisk for "
                        "its deployment. This deploy ramdisk has been "
                        "deprecated. Please use the ironic-python-agent "
                        "(IPA) ramdisk instead."), node.uuid)
        task.process_event('resume')

        LOG.debug('Continuing iSCSI virtual media deployment on node %s',
                  node.uuid)

        is_whole_disk_image = node.driver_internal_info.get(
            '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'))

        try:
            _cleanup_vmedia_boot(task)
            if (deploy_utils.get_boot_option(node) == "local" or
                is_whole_disk_image):
                manager_utils.node_set_boot_device(task, boot_devices.DISK,
                                                   persistent=True)

                # 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:
                self._configure_vmedia_boot(task, root_uuid_or_disk_id)

        except Exception as e:
            LOG.exception(_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'))
Example #41
0
    def heartbeat(self, task, callback_url):
        """Continues the deployment of baremetal node."""

        node = task.node

        # NOTE(pas-ha) this driver does not support cleaning,
        # so the only valid state to continue on heartbeat is DEPLOYWAIT
        if node.provision_state != states.DEPLOYWAIT:
            LOG.warning(
                _LW('Call back from %(node)s in invalid provision '
                    'state %(state)s'), {
                        'node': node.uuid,
                        'state': node.provision_state
                    })
            return

        task.upgrade_lock(purpose='deploy')
        task.process_event('resume')
        params = _parse_driver_info(node)
        params['host'] = urlparse.urlparse(callback_url).netloc.split(':')[0]
        cmd = ('%s --data_driver ironic  --config-file '
               '/etc/fuel-agent/fuel-agent.conf' % params.pop('script'))
        if CONF.debug:
            cmd += ' --debug'
        instance_info = node.instance_info

        try:
            deploy_data = _get_deploy_data(task.context,
                                           instance_info['image_source'])

            image_data = {
                "/": {
                    "uri": instance_info['image_url'],
                    "format": "raw",
                    "container": "raw"
                }
            }

            deploy_data['ks_meta']['image_data'] = image_data

            ssh = utils.ssh_connect(params)
            sftp = ssh.open_sftp()
            _sftp_upload(sftp, json.dumps(deploy_data), '/tmp/provision.json')

            # swift configdrive store should be disabled
            configdrive = instance_info.get('configdrive')
            if configdrive is not None:
                _sftp_upload(sftp, configdrive, '/tmp/config-drive.img')

            _ssh_execute(ssh, cmd, params)
            LOG.info(_LI('Fuel Agent pass on node %s'), node.uuid)
            manager_utils.node_set_boot_device(task,
                                               boot_devices.DISK,
                                               persistent=True)

            manager_utils.node_power_action(task, states.POWER_OFF)
            task.driver.network.remove_provisioning_network(task)
            task.driver.network.configure_tenant_networks(task)
            manager_utils.node_power_action(task, states.POWER_ON)
        except Exception as e:
            msg = (_('Deploy failed for node %(node)s. Error: %(error)s') % {
                'node': node.uuid,
                'error': e
            })
            LOG.error(msg)
            deploy_utils.set_failed_state(task, msg, collect_logs=False)
        else:
            task.process_event('done')
            LOG.info(_LI('Deployment to node %s done'), task.node.uuid)
Example #42
0
 def _continue_deploy(self, task, **kwargs):
     manager_utils.node_set_boot_device(task, boot_devices.PXE, True)
     super(IloPXEVendorPassthru, self)._continue_deploy(task, **kwargs)
 def _set_deploy_boot_device(self, task):
     """Set the boot device for deployment"""
     manager_utils.node_set_boot_device(task, boot_devices.CDROM)
Example #44
0
 def set_boot_device(self, task):
     manager_utils.node_set_boot_device(task,
                                        boot_devices.CDROM,
                                        persistent=True)
Example #45
0
    def inspect_hardware(self, task):
        """Inspect hardware.

        Inspect hardware to obtain the essential hardware properties and
        mac addresses.

        :param task: a task from TaskManager.
        :raises: HardwareInspectionFailure, if hardware inspection failed.
        :returns: states.MANAGEABLE, if hardware inspection succeeded.
        """
        node = task.node
        kwargs = {}
        # Inspect additional capabilities task requires node with power on
        # status
        old_power_state = task.driver.power.get_power_state(task)
        if old_power_state == states.POWER_OFF:
            manager_utils.node_set_boot_device(task, boot_devices.BIOS, False)
            manager_utils.node_power_action(task, states.POWER_ON)

            LOG.info("The Node %(node_uuid)s being powered on for inspection",
                     {'node_uuid': task.node.uuid})

            kwargs['sleep_flag'] = True
        traits_obj = objects.TraitList.get_by_node_id(task.context, node.id)
        existing_traits = traits_obj.get_trait_names()
        props, macs, new_traits = _inspect_hardware(node, existing_traits,
                                                    **kwargs)
        node.properties = dict(node.properties, **props)
        if existing_traits != new_traits:
            objects.TraitList.create(task.context, node.id, new_traits)
        node.save()

        for mac in macs:
            try:
                new_port = objects.Port(task.context,
                                        address=mac,
                                        node_id=node.id)
                new_port.create()
                LOG.info(
                    "Port created for MAC address %(address)s "
                    "for node %(node_uuid)s during inspection", {
                        'address': mac,
                        'node_uuid': node.uuid
                    })
            except exception.MACAlreadyExists:
                LOG.warning(
                    "Port already existed for MAC address "
                    "%(address)s for node %(node_uuid)s "
                    "during inspection", {
                        'address': mac,
                        'node_uuid': node.uuid
                    })

        LOG.info("Node %s inspected", node.uuid)
        # restore old power state
        if old_power_state == states.POWER_OFF:
            manager_utils.node_power_action(task, states.POWER_OFF)

            LOG.info(
                "The Node %(node_uuid)s being powered off after "
                "inspection", {'node_uuid': task.node.uuid})

        return states.MANAGEABLE
Example #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.
        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 = boot_mode_utils.get_boot_mode_for_deploy(task.node)
        boot_option = deploy_utils.get_boot_option(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)
        elif boot_option == "ramdisk":
            boot_iso = _get_boot_iso(task, None)
            ilo_common.setup_vmedia_for_boot(task, boot_iso)
            manager_utils.node_set_boot_device(task,
                                               boot_devices.CDROM,
                                               persistent=True)
        else:
            # 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)
Example #47
0
    def pass_deploy_info(self, task, **kwargs):
        """Continues the deployment of baremetal node."""

        node = task.node
        task.process_event('resume')
        err_msg = _('Failed to continue deployment with Fuel Agent.')

        agent_status = kwargs.get('status')
        if agent_status != 'ready':
            LOG.error(
                _LE('Deploy failed for node %(node)s. Fuel Agent is not '
                    'in ready state, error: %(error)s'), {
                        'node': node.uuid,
                        'error': kwargs.get('error_message')
                    })
            deploy_utils.set_failed_state(task, err_msg)
            return

        params = _parse_driver_info(node)
        params['host'] = kwargs.get('address')
        cmd = ('%s --data_driver ironic  --config-file '
               '/etc/fuel-agent/fuel-agent.conf' % params.pop('script'))
        if CONF.debug:
            cmd += ' --debug'
        instance_info = node.instance_info

        try:
            deploy_data = _get_deploy_data(task.context,
                                           instance_info['image_source'])

            image_data = {
                "/": {
                    "uri": instance_info['image_url'],
                    "format": "raw",
                    "container": "raw"
                }
            }

            deploy_data['ks_meta']['image_data'] = image_data

            ssh = utils.ssh_connect(params)
            sftp = ssh.open_sftp()
            _sftp_upload(sftp, json.dumps(deploy_data), '/tmp/provision.json')

            # swift configdrive store should be disabled
            configdrive = instance_info.get('configdrive')
            if configdrive is not None:
                _sftp_upload(sftp, configdrive, '/tmp/config-drive.img')

            _ssh_execute(ssh, cmd, params)
            LOG.info(_LI('Fuel Agent pass on node %s'), node.uuid)
            manager_utils.node_set_boot_device(task,
                                               boot_devices.DISK,
                                               persistent=True)
            manager_utils.node_power_action(task, states.REBOOT)
        except Exception as e:
            msg = (_('Deploy failed for node %(node)s. Error: %(error)s') % {
                'node': node.uuid,
                'error': e
            })
            LOG.error(msg)
            deploy_utils.set_failed_state(task, msg)
        else:
            task.process_event('done')
            LOG.info(_LI('Deployment to node %s done'), task.node.uuid)
Example #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
        """
        boot_mode_utils.sync_boot_mode(task)

        node = task.node
        boot_option = deploy_utils.get_boot_option(node)
        boot_device = None
        instance_image_info = {}
        if boot_option == "ramdisk":
            instance_image_info = pxe_utils.get_instance_image_info(
                task, ipxe_enabled=self.ipxe_enabled)
            pxe_utils.cache_ramdisk_kernel(task,
                                           instance_image_info,
                                           ipxe_enabled=self.ipxe_enabled)

        if deploy_utils.is_iscsi_boot(task) or boot_option == "ramdisk":
            pxe_utils.prepare_instance_pxe_config(
                task,
                instance_image_info,
                iscsi_boot=deploy_utils.is_iscsi_boot(task),
                ramdisk_boot=(boot_option == "ramdisk"),
                ipxe_enabled=self.ipxe_enabled)
            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 = pxe_utils.get_instance_image_info(
                    task, ipxe_enabled=self.ipxe_enabled)
                pxe_utils.cache_ramdisk_kernel(task,
                                               instance_image_info,
                                               ipxe_enabled=self.ipxe_enabled)

            # If it's going to PXE boot we need to update the DHCP server
            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)

            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, ipxe_enabled=self.ipxe_enabled)
                    boot_device = boot_devices.DISK
            else:
                pxe_utils.build_service_pxe_config(
                    task,
                    instance_image_info,
                    root_uuid_or_disk_id,
                    ipxe_enabled=self.ipxe_enabled)
                boot_device = boot_devices.PXE
        else:
            # NOTE(dtantsur): create a PXE configuration as a safety net for
            # hardware uncapable of persistent boot. If on a reboot it will try
            # to boot from PXE, this configuration will return it back.
            if CONF.pxe.enable_netboot_fallback:
                pxe_utils.build_service_pxe_config(
                    task,
                    instance_image_info,
                    task.node.driver_internal_info.get('root_uuid_or_disk_id'),
                    ipxe_enabled=self.ipxe_enabled,
                    # PXE config for whole disk images is identical to what
                    # we need to boot from local disk, so use True even
                    # for partition images.
                    is_whole_disk_image=True)
            else:
                # Clean up the deployment configuration
                pxe_utils.clean_up_pxe_config(task,
                                              ipxe_enabled=self.ipxe_enabled)
            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:
            persistent = True
            if node.driver_info.get('force_persistent_boot_device',
                                    'Default') == 'Never':
                persistent = False
            manager_utils.node_set_boot_device(task,
                                               boot_device,
                                               persistent=persistent)
Example #49
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)
        ipxe_enabled = CONF.pxe.ipxe_enabled
        if 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()

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

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

        # 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))
            boot_mode_utils.sync_boot_mode(task)

        pxe_options = pxe_utils.build_pxe_config_options(
            task,
            pxe_info,
            ipxe_enabled=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"]

        pxe_config_template = deploy_utils.get_pxe_config_template(node)

        pxe_utils.create_pxe_config(task,
                                    pxe_options,
                                    pxe_config_template,
                                    ipxe_enabled=CONF.pxe.ipxe_enabled)

        persistent = self._persistent_ramdisk_boot(node)
        manager_utils.node_set_boot_device(task,
                                           boot_devices.PXE,
                                           persistent=persistent)

        if CONF.pxe.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=CONF.pxe.ipxe_enabled)
        LOG.debug(
            'Ramdisk PXE boot for node %(node)s has been prepared '
            'with kernel params %(params)s', {
                'node': node.uuid,
                'params': pxe_options
            })
Example #50
0
 def pass_deploy_info(self, task, **kwargs):
     manager_utils.node_set_boot_device(task, boot_devices.PXE, True)
     super(IloPXEVendorPassthru, self).pass_deploy_info(task, **kwargs)
Example #51
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)
Example #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. 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)
Example #53
0
    def pass_deploy_info(self, task, **kwargs):
        """Continues the iSCSI deployment from where ramdisk left off.

        This method continues the iSCSI deployment from the conductor node
        and writes the deploy image to the bare metal's disk. After that,
        it does the following depending on boot_option for deploy:

        - If the boot_option requested for this deploy is 'local', then it
          sets the node to boot from disk (ramdisk installs the boot loader
          present within the image to the bare metal's disk).
        - If the boot_option requested is 'netboot' or no boot_option is
          requested, 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 TaskManager instance containing the node to act on.
        :param kwargs: kwargs containing parameters for iSCSI deployment.
        :raises: InvalidState
        """
        node = task.node
        task.process_event('resume')

        iwdi = node.driver_internal_info.get('is_whole_disk_image')
        ilo_common.cleanup_vmedia_boot(task)
        uuid_dict = iscsi_deploy.continue_deploy(task, **kwargs)
        root_uuid_or_disk_id = uuid_dict.get('root uuid',
                                             uuid_dict.get('disk identifier'))

        try:
            # Set boot mode
            ilo_common.update_boot_mode(task)

            # Need to enable secure boot, if being requested
            _update_secure_boot_mode(task, True)

            # For iscsi_ilo driver, we boot from disk every time if the image
            # deployed is a whole disk image.
            if iscsi_deploy.get_boot_option(node) == "local" or iwdi:
                manager_utils.node_set_boot_device(task,
                                                   boot_devices.DISK,
                                                   persistent=True)

                # 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 iwdi:
                    deploy_utils.notify_ramdisk_to_proceed(kwargs['address'])
                    task.process_event('wait')
                    return
            else:
                self._configure_vmedia_boot(task, root_uuid_or_disk_id)
        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'))
Example #54
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.
        :param mode: Label indicating a deploy or rescue operation
            being carried out on the node. Supported values are
            'deploy' and 'rescue'. Defaults to 'deploy', indicating
            deploy operation is being carried out.
        :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
        mode = deploy_utils.rescue_or_deploy_mode(node)

        if CONF.pxe.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()

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

        pxe_info = _get_image_info(node, mode=mode)

        # 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)

        pxe_config_template = deploy_utils.get_pxe_config_template(node)

        pxe_utils.create_pxe_config(task, pxe_options,
                                    pxe_config_template)
        persistent = strutils.bool_from_string(
            node.driver_info.get('force_persistent_boot_device',
                                 False))
        manager_utils.node_set_boot_device(task, boot_devices.PXE,
                                           persistent=persistent)

        if CONF.pxe.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:
            _cache_ramdisk_kernel(task.context, node, pxe_info)
Example #55
0
    def prepare_instance_boot(self, task):
        if not task.driver.storage.should_write_image(task):
            task.driver.boot.prepare_instance(task)
            # Move straight to the final steps
            return

        node = task.node
        iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
        cpu_arch = task.node.properties.get('cpu_arch')

        # 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.
        # NOTE(mjturek): In the case of local boot using a partition image on
        # ppc64* hardware we need to provide the 'PReP_Boot_partition_uuid' to
        # direct where the bootloader should be installed.
        driver_internal_info = task.node.driver_internal_info
        try:
            partition_uuids = self._client.get_partition_uuids(node).get(
                'command_result') or {}
            root_uuid = partition_uuids.get('root uuid')
        except exception.AgentAPIError:
            # TODO(dtantsur): remove in W
            LOG.warning('Old ironic-python-agent detected, please update '
                        'to Victoria or newer')
            partition_uuids = None
            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 not iwdi:
            LOG.error(
                'No root UUID returned from the ramdisk for node '
                '%(node)s, the deploy will likely fail. Partition '
                'UUIDs are %(uuids)s', {
                    'node': node.uuid,
                    'uuid': partition_uuids
                })

        efi_sys_uuid = None
        if not iwdi:
            if boot_mode_utils.get_boot_mode(node) == 'uefi':
                # TODO(dtantsur): remove in W
                if partition_uuids is None:
                    efi_sys_uuid = (self._get_uuid_from_result(
                        task, 'efi_system_partition_uuid'))
                else:
                    efi_sys_uuid = partition_uuids.get(
                        'efi system partition uuid')

        prep_boot_part_uuid = None
        if cpu_arch is not None and cpu_arch.startswith('ppc64'):
            # TODO(dtantsur): remove in W
            if partition_uuids is None:
                prep_boot_part_uuid = (self._get_uuid_from_result(
                    task, 'PReP_Boot_partition_uuid'))
            else:
                prep_boot_part_uuid = partition_uuids.get(
                    'PReP Boot 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,
                                          prep_boot_part_uuid)
        else:
            manager_utils.node_set_boot_device(task, 'disk', persistent=True)

        # Remove symbolic link when deploy is done.
        if CONF.agent.image_download_source == 'http':
            deploy_utils.remove_http_instance_symlink(task.node.uuid)