Пример #1
0
    def prepare(self, task):
        node = task.node
        # Log a warning if the boot_option is wrong... and
        # otherwise reset it.
        boot_option = deploy_utils.get_boot_option(node)
        if boot_option != 'ramdisk':
            LOG.warning('Incorrect "boot_option" set for node %(node)s '
                        'and will be overridden to "ramdisk" as to '
                        'match the deploy interface. Found: %(boot_opt)s.',
                        {'node': node.uuid,
                         'boot_opt': boot_option})
            i_info = task.node.instance_info
            i_info.update({'capabilities': {'boot_option': 'ramdisk'}})
            node.instance_info = i_info
            node.save()

        deploy_utils.populate_storage_driver_internal_info(task)
        if node.provision_state == states.DEPLOYING:
            # Ask the network interface to validate itself so
            # we can ensure we are able to proceed.
            task.driver.network.validate(task)

            manager_utils.node_power_action(task, states.POWER_OFF)
            # NOTE(TheJulia): If this was any other interface, we would
            # unconfigure tenant networks, add provisioning networks, etc.
            task.driver.storage.attach_volumes(task)
        if node.provision_state in (states.ACTIVE, states.UNRESCUING):
            # In the event of takeover or unrescue.
            task.driver.boot.prepare_instance(task)
Пример #2
0
    def _plug_provisioning(self, task, **kwargs):
        LOG.debug("Plugging the provisioning!")
        if task.node.power_state != states.POWER_ON:
            manager_utils.node_power_action(task, states.REBOOT)

        client = neutron._build_client(task.context.auth_token)
        port = client.create_port({
            'port': {
                "network_id":
                    CONF.neutron.cleaning_network_uuid,
                "extra_dhcp_opts":
                    pxe_utils.dhcp_options_for_instance(task),
            }
        })

        name = port['port']['id']
        network = client.show_network(port['port']['network_id'])
        seg_id = network['network']['provider:segmentation_id']

        try:
            common.add_vnic(
                task, name, port['port']['mac_address'], seg_id, True)
        except imcsdk.ImcException:
            client.delete_port(name)
            raise

        new_port = objects.Port(
            task.context, node_id=task.node.id,
            address=port['port']['mac_address'],
            extra={"vif_port_id": port['port']['id'],
                   "type": "deploy", "state": "ACTIVE"})
        new_port.create()
        return port['port']['fixed_ips'][0]['ip_address']
Пример #3
0
    def deploy(self, task):
        if 'configdrive' in task.node.instance_info:
            LOG.warning('A configuration drive is present with '
                        'in the deployment request of node %(node)s. '
                        'The configuration drive will be ignored for '
                        'this deployment.',
                        {'node': task.node})
        manager_utils.node_power_action(task, states.POWER_OFF)
        # Tenant neworks must enable connectivity to the boot
        # location, as reboot() can otherwise be very problematic.
        # IDEA(TheJulia): Maybe a "trusted environment" mode flag
        # that we otherwise fail validation on for drivers that
        # require explicit security postures.
        power_state_to_restore = manager_utils.power_on_node_if_needed(task)
        task.driver.network.configure_tenant_networks(task)
        manager_utils.restore_power_state_if_needed(
            task, power_state_to_restore)

        # calling boot.prepare_instance will also set the node
        # to PXE boot, and update PXE templates accordingly
        task.driver.boot.prepare_instance(task)

        # Power-on the instance, with PXE prepared, we're done.
        manager_utils.node_power_action(task, states.POWER_ON)
        LOG.info('Deployment setup for node %s done', task.node.uuid)
        return None
Пример #4
0
def _prepare_node_for_deploy(task):
    """Common preparatory steps for all iLO drivers.

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

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

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

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

    if change_boot_mode:
        ilo_common.update_boot_mode(task)
    else:
        # Need to update boot mode that will be used during deploy, if one is
        # not provided.
        # Since secure boot was disabled, we are in 'uefi' boot mode.
        if deploy_utils.get_boot_mode_for_deploy(task.node) is None:
            instance_info = task.node.instance_info
            instance_info['deploy_boot_mode'] = 'uefi'
            task.node.instance_info = instance_info
            task.node.save()
Пример #5
0
def _reboot_and_finish_deploy(task):
    wait = CONF.ansible.post_deploy_get_power_state_retry_interval * 1000
    attempts = CONF.ansible.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)

    try:
        _wait_until_powered_off(task)
    except Exception as e:
        LOG.warning(_LW('Failed to soft power off node %(node_uuid)s '
                    'in at least %(timeout)d seconds. Error: %(error)s'),
                    {'node_uuid': task.node.uuid,
                     'timeout': (wait * (attempts - 1)) / 1000,
                     'error': e})
        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)
Пример #6
0
    def prepare(self, task):
        """Prepare the deployment environment for this node.

        :param task: a TaskManager instance.
        :raises: NetworkError: if the previous cleaning ports cannot be removed
            or if new cleaning ports cannot be created.
        :raises: InvalidParameterValue when the wrong power state is specified
             or the wrong driver info is specified for power management.
        :raises: other exceptions by the node's power driver if something
             wrong occurred during the power action.
        :raises: exception.ImageRefValidationFailed if image_source is not
            Glance href and is not HTTP(S) URL.
        :raises: any boot interface's prepare_ramdisk exceptions.
        """
        # Nodes deployed by AgentDeploy always boot from disk now. So there
        # is nothing to be done in prepare() when it's called during
        # take over.
        node = task.node
        if node.provision_state == states.DEPLOYING:
            # Adding the node to provisioning network so that the dhcp
            # options get added for the provisioning port.
            manager_utils.node_power_action(task, states.POWER_OFF)
            task.driver.network.add_provisioning_network(task)
        if node.provision_state != states.ACTIVE:
            node.instance_info = build_instance_info_for_deploy(task)
            node.save()
            if CONF.agent.manage_agent_boot:
                deploy_opts = deploy_utils.build_agent_options(node)
                task.driver.boot.prepare_ramdisk(task, deploy_opts)
Пример #7
0
    def _cleaning_reboot(self, task):
        """Reboots a node out of band after a clean step that requires it.

        If an agent clean step has 'reboot_requested': True, reboots the
        node when the step is completed. Will put the node in CLEANFAIL
        if the node cannot be rebooted.

        :param task: a TaskManager instance
        """
        try:
            manager_utils.node_power_action(task, states.REBOOT)
        except Exception as e:
            msg = (_('Reboot requested by clean step %(step)s failed for '
                     'node %(node)s: %(err)s') %
                   {'step': task.node.clean_step,
                    'node': task.node.uuid,
                    'err': e})
            LOG.error(msg)
            # do not set cleaning_reboot if we didn't reboot
            manager_utils.cleaning_error_handler(task, msg)
            return

        # Signify that we've rebooted
        driver_internal_info = task.node.driver_internal_info
        driver_internal_info['cleaning_reboot'] = True
        task.node.driver_internal_info = driver_internal_info
        task.node.save()
Пример #8
0
def _reboot_into(task, iso, ramdisk_options):
    """Reboots the node into a given boot ISO.

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

    :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.
    """
    ilo_common.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)
    manager_utils.node_power_action(task, states.REBOOT)
Пример #9
0
 def tear_down_cleaning(self, task):
     """Clean up the PXE and DHCP files after cleaning."""
     manager_utils.node_power_action(task, states.POWER_OFF)
     # If we created cleaning ports, delete them
     provider = dhcp_factory.DHCPFactory().provider
     if getattr(provider, 'delete_cleaning_ports', None):
         provider.delete_cleaning_ports(task)
Пример #10
0
def set_failed_state(task, msg):
    """Sets the deploy status as failed with relevant messages.

    This method sets the deployment as fail with the given message.
    It sets node's provision_state to DEPLOYFAIL and updates last_error
    with the given error message. It also powers off the baremetal node.

    :param task: a TaskManager instance containing the node to act on.
    :param msg: the message to set in last_error of the node.
    """
    node = task.node
    node.provision_state = states.DEPLOYFAIL
    node.target_provision_state = states.NOSTATE
    node.save()
    try:
        manager_utils.node_power_action(task, states.POWER_OFF)
    except Exception:
        msg2 = (_LE('Node %s failed to power off while handling deploy '
                    'failure. This may be a serious condition. Node '
                    'should be removed from Ironic or put in maintenance '
                    'mode until the problem is resolved.') % node.uuid)
        LOG.exception(msg2)
    finally:
        # NOTE(deva): node_power_action() erases node.last_error
        #             so we need to set it again here.
        node.last_error = msg
        node.save()
Пример #11
0
    def deploy(self, task):
        """Start deployment of the task's node.

        Fetches the instance image, prepares the options for the deployment
        ramdisk, sets the node to boot from virtual media cdrom, and reboots
        the given node.

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYWAIT.
        :raises: InstanceDeployFailure, if image size if greater than root
            partition.
        :raises: ImageCreationFailed, if it failed while creating the floppy
            image.
        :raises: IloOperationError, if some operation on iLO fails.
        """
        node = task.node
        manager_utils.node_power_action(task, states.POWER_OFF)

        iscsi_deploy.cache_instance_image(task.context, node)
        iscsi_deploy.check_image_size(task)

        deploy_ramdisk_opts = iscsi_deploy.build_deploy_ramdisk_options(node)
        deploy_nic_mac = deploy_utils.get_single_nic_with_vif_port_id(task)
        deploy_ramdisk_opts['BOOTIF'] = deploy_nic_mac
        deploy_iso_uuid = node.driver_info['ilo_deploy_iso']
        deploy_iso = 'glance:' + deploy_iso_uuid

        _reboot_into(task, deploy_iso, deploy_ramdisk_opts)

        return states.DEPLOYWAIT
Пример #12
0
    def test_node_power_action_in_same_state(self):
        """Test setting node state to its present state.

        Test that we don't try to set the power state if the requested
        state is the same as the current state.
        """
        node = obj_utils.create_test_node(self.context,
                                          uuid=uuidutils.generate_uuid(),
                                          driver='fake',
                                          last_error='anything but None',
                                          power_state=states.POWER_ON)
        task = task_manager.TaskManager(self.context, node.uuid)

        with mock.patch.object(self.driver.power,
                               'get_power_state') as get_power_mock:
            get_power_mock.return_value = states.POWER_ON

            with mock.patch.object(self.driver.power,
                                   'set_power_state') as set_power_mock:
                conductor_utils.node_power_action(task, states.POWER_ON)

                node.refresh()
                get_power_mock.assert_called_once_with(mock.ANY)
                self.assertFalse(set_power_mock.called,
                                 "set_power_state unexpectedly called")
                self.assertEqual(states.POWER_ON, node['power_state'])
                self.assertIsNone(node['target_power_state'])
                self.assertIsNone(node['last_error'])
Пример #13
0
def prepare_inband_cleaning(task, manage_boot=True):
    """Prepares the node to boot into agent for in-band cleaning.

    This method does the following:
    1. Prepares the cleaning ports for the bare metal
       node and updates the clean parameters in node's driver_internal_info.
    2. If 'manage_boot' parameter is set to true, it also calls the
       'prepare_ramdisk' method of boot interface to boot the agent ramdisk.
    3. Reboots the bare metal node.

    :param task: a TaskManager object containing the node
    :param manage_boot: If this is set to True, this method calls the
        'prepare_ramdisk' method of boot interface to boot the agent
        ramdisk. If False, it skips preparing the boot agent ramdisk using
        boot interface, and assumes that the environment is setup to
        automatically boot agent ramdisk every time bare metal node is
        rebooted.
    :returns: states.CLEANWAIT to signify an asynchronous prepare.
    :raises NodeCleaningFailure: if the previous cleaning ports cannot
        be removed or if new cleaning ports cannot be created
    """
    prepare_cleaning_ports(task)

    # Append required config parameters to node's driver_internal_info
    # to pass to IPA.
    agent_add_clean_params(task)

    if manage_boot:
        ramdisk_opts = build_agent_options(task.node)
        task.driver.boot.prepare_ramdisk(task, ramdisk_opts)

    manager_utils.node_power_action(task, states.REBOOT)

    # Tell the conductor we are waiting for the agent to boot.
    return states.CLEANWAIT
Пример #14
0
    def test_node_power_action_in_same_state_db_not_in_sync(self):
        """Test setting node state to its present state if DB is out of sync.

        Under rare conditions (see bug #1403106) database might contain stale
        information, make sure we fix it.
        """
        node = obj_utils.create_test_node(self.context,
                                          uuid=uuidutils.generate_uuid(),
                                          driver='fake',
                                          last_error='anything but None',
                                          power_state=states.POWER_ON)
        task = task_manager.TaskManager(self.context, node.uuid)

        with mock.patch.object(self.driver.power,
                               'get_power_state') as get_power_mock:
            get_power_mock.return_value = states.POWER_OFF

            with mock.patch.object(self.driver.power,
                                   'set_power_state') as set_power_mock:
                conductor_utils.node_power_action(task, states.POWER_OFF)

                node.refresh()
                get_power_mock.assert_called_once_with(mock.ANY)
                self.assertFalse(set_power_mock.called,
                                 "set_power_state unexpectedly called")
                self.assertEqual(states.POWER_OFF, node['power_state'])
                self.assertIsNone(node['target_power_state'])
                self.assertIsNone(node['last_error'])
Пример #15
0
    def deploy(self, task):
        """Start deployment of the task's node'.

        Fetches instance image, creates a temporary keystone token file,
        updates the 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.pass_deploy_info().

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYWAIT.
        """
        iscsi_deploy.cache_instance_image(task.context, task.node)
        iscsi_deploy.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(task)
        provider = dhcp_factory.DHCPFactory()
        provider.update_dhcp(task, dhcp_opts)

        deploy_utils.try_set_boot_device(task, boot_devices.PXE)
        manager_utils.node_power_action(task, states.REBOOT)

        return states.DEPLOYWAIT
Пример #16
0
    def clean_up_instance(self, task):
        """Cleans up the boot of instance.

        This method cleans up the PXE environment that was setup for booting
        the instance. It unlinks the instance kernel/ramdisk in the node's
        directory in tftproot and removes it's PXE config.
        In case of UEFI iSCSI booting, it cleans up iSCSI target information
        from the node.

        :param task: a task from TaskManager.
        :returns: None
        :raises: IloOperationError, if some operation on iLO failed.
        """
        manager_utils.node_power_action(task, states.POWER_OFF)
        disable_secure_boot_if_supported(task)
        driver_internal_info = task.node.driver_internal_info

        if (deploy_utils.is_iscsi_boot(task)
            and task.node.driver_internal_info.get('ilo_uefi_iscsi_boot')):
            # It will clear iSCSI info from iLO in case of booting from
            # volume in UEFI boot mode
            task.driver.management.clear_iscsi_boot_target(task)
            driver_internal_info.pop('ilo_uefi_iscsi_boot', None)
            task.node.driver_internal_info = driver_internal_info
            task.node.save()
        else:
            # Volume boot in BIOS boot mode is handled using
            # PXE boot interface
            super(IloPXEBoot, self).clean_up_instance(task)
Пример #17
0
    def prepare(self, task):
        """Prepare the deployment environment for this task's node.

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

        :param task: a TaskManager instance containing the node to act on.
        :raises: NetworkError: if the previous cleaning ports cannot be removed
            or if new cleaning ports cannot be created.
        :raises: InvalidParameterValue when the wrong power state is specified
            or the wrong driver info is specified for power management.
        :raises: StorageError If the storage driver is unable to attach the
            configured volumes.
        :raises: other exceptions by the node's power driver if something
            wrong occurred during the power action.
        :raises: any boot interface's prepare_ramdisk exceptions.
        """
        node = task.node
        deploy_utils.populate_storage_driver_internal_info(task)
        if node.provision_state in [states.ACTIVE, states.ADOPTING]:
            task.driver.boot.prepare_instance(task)
        else:
            if node.provision_state == states.DEPLOYING:
                fast_track_deploy = manager_utils.is_fast_track(task)
                if fast_track_deploy:
                    # The agent has already recently checked in and we are
                    # configured to take that as an indicator that we can
                    # skip ahead.
                    LOG.debug('The agent for node %(node)s has recently '
                              'checked in, and the node power will remain '
                              'unmodified.',
                              {'node': task.node.uuid})
                else:
                    # Adding the node to provisioning network so that the dhcp
                    # options get added for the provisioning port.
                    manager_utils.node_power_action(task, states.POWER_OFF)
                # NOTE(vdrok): in case of rebuild, we have tenant network
                # already configured, unbind tenant ports if present
                if task.driver.storage.should_write_image(task):
                    if not fast_track_deploy:
                        power_state_to_restore = (
                            manager_utils.power_on_node_if_needed(task))
                    task.driver.network.unconfigure_tenant_networks(task)
                    task.driver.network.add_provisioning_network(task)
                    if not fast_track_deploy:
                        manager_utils.restore_power_state_if_needed(
                            task, power_state_to_restore)
                task.driver.storage.attach_volumes(task)
                if (not task.driver.storage.should_write_image(task)
                    or fast_track_deploy):
                    # We have nothing else to do as this is handled in the
                    # backend storage system, and we can return to the caller
                    # as we do not need to boot the agent to deploy.
                    # Alternatively, we are in a fast track deployment
                    # and have nothing else to do.
                    return

            deploy_opts = deploy_utils.build_agent_options(node)
            task.driver.boot.prepare_ramdisk(task, deploy_opts)
Пример #18
0
    def prepare(self, task):
        """Prepare the deployment environment for this task's node.

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

        :param task: a TaskManager instance containing the node to act on.
        :raises: NetworkError: if the previous cleaning ports cannot be removed
            or if new cleaning ports cannot be created.
        :raises: InvalidParameterValue when the wrong power state is specified
             or the wrong driver info is specified for power management.
        :raises: other exceptions by the node's power driver if something
             wrong occurred during the power action.
        :raises: any boot interface's prepare_ramdisk exceptions.
        """
        node = task.node
        if node.provision_state in [states.ACTIVE, states.ADOPTING]:
            task.driver.boot.prepare_instance(task)
        else:
            if node.provision_state == states.DEPLOYING:
                # Adding the node to provisioning network so that the dhcp
                # options get added for the provisioning port.
                manager_utils.node_power_action(task, states.POWER_OFF)
                task.driver.network.add_provisioning_network(task)

            deploy_opts = deploy_utils.build_agent_options(node)
            task.driver.boot.prepare_ramdisk(task, deploy_opts)
Пример #19
0
    def tear_down(self, task):
        """Tear down a previous deployment on the task's node.

        Power off the node. All actual clean-up is done in the clean_up()
        method which should be called separately.

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DELETED.
        :raises: NetworkError if the cleaning ports cannot be removed.
        :raises: InvalidParameterValue when the wrong state is specified
             or the wrong driver info is specified.
        :raises: StorageError when volume detachment fails.
        :raises: other exceptions by the node's power driver if something
             wrong occurred during the power action.
        """
        manager_utils.node_power_action(task, states.POWER_OFF)
        task.driver.storage.detach_volumes(task)
        deploy_utils.tear_down_storage_configuration(task)
        power_state_to_restore = manager_utils.power_on_node_if_needed(task)
        task.driver.network.unconfigure_tenant_networks(task)
        # NOTE(mgoddard): If the deployment was unsuccessful the node may have
        # ports on the provisioning network which were not deleted.
        task.driver.network.remove_provisioning_network(task)
        manager_utils.restore_power_state_if_needed(
            task, power_state_to_restore)
        return states.DELETED
Пример #20
0
    def tear_down(self, task, node):
        """Tear down a previous deployment.

        Given a node that has been previously deployed to,
        do all cleanup and tear down necessary to "un-deploy" that node.

        :param task: a TaskManager instance.
        :param node: the Node to act upon.
        :returns: deploy state DELETED.
        """
        #FIXME(ghe): Possible error to get image info if eliminated from glance
        # Retrieve image info and store in db
        # If we keep master images, no need to get the info, we may ignore this
        pxe_info = _get_tftp_image_info(node)
        d_info = _parse_driver_info(node)
        for label in pxe_info:
            (uuid, path) = pxe_info[label]
            master_path = os.path.join(CONF.pxe.tftp_master_path, uuid)
            utils.unlink_without_raise(path)
            _unlink_master_image(master_path)

        utils.unlink_without_raise(_get_pxe_config_file_path(
                node['instance_uuid']))
        for port in _get_node_mac_addresses(task, node):
            mac_path = _get_pxe_mac_path(port)
            utils.unlink_without_raise(mac_path)

        utils.rmtree_without_raise(
                os.path.join(CONF.pxe.tftp_root, node['instance_uuid']))

        _destroy_images(d_info)

        manager_utils.node_power_action(task, node, states.POWER_OFF)

        return states.DELETED
Пример #21
0
def _cleaning_reboot(task):
    """Reboots a node out of band after a clean step that requires it.

    If an agent clean step has 'reboot_requested': True, reboots the
    node when the step is completed. Will put the node in CLEANFAIL
    if the node cannot be rebooted.

    :param task: a TaskManager instance
    """
    try:
        # NOTE(fellypefca): Call prepare_ramdisk on ensure that the
        # baremetal node boots back into the ramdisk after reboot.
        deploy_opts = deploy_utils.build_agent_options(task.node)
        task.driver.boot.prepare_ramdisk(task, deploy_opts)
        manager_utils.node_power_action(task, states.REBOOT)
    except Exception as e:
        msg = (_('Reboot requested by clean step %(step)s failed for '
                 'node %(node)s: %(err)s') %
               {'step': task.node.clean_step,
                'node': task.node.uuid,
                'err': e})
        LOG.error(msg, exc_info=not isinstance(e, exception.IronicException))
        # do not set cleaning_reboot if we didn't reboot
        manager_utils.cleaning_error_handler(task, msg)
        return

    # Signify that we've rebooted
    driver_internal_info = task.node.driver_internal_info
    driver_internal_info['cleaning_reboot'] = True
    task.node.driver_internal_info = driver_internal_info
    task.node.save()
Пример #22
0
def finish_deploy(task, address):
    """Notifies the ramdisk to reboot the node and makes the instance active.

    This method notifies the ramdisk to proceed to reboot and then
    makes the instance active.

    :param task: a TaskManager object.
    :param address: The IP address of the bare metal node.
    :raises: InstanceDeployFailure, if notifying ramdisk failed.
    """
    node = task.node
    try:
        deploy_utils.notify_ramdisk_to_proceed(address)
    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 notify ramdisk to reboot after bootloader " "installation. Error: %s") % e
        deploy_utils.set_failed_state(task, msg)
        raise exception.InstanceDeployFailure(msg)

    # TODO(lucasagomes): When deploying a node with the DIB ramdisk
    # Ironic will not power control the node at the end of the deployment,
    # it's the DIB ramdisk that reboots the node. But, for the SSH driver
    # some changes like setting the boot device only gets applied when the
    # machine is powered off and on again. So the code below is enforcing
    # it. For Liberty we need to change the DIB ramdisk so that Ironic
    # always controls the power state of the node for all drivers.
    if deploy_utils.get_boot_option(node) == "local" and "ssh" in node.driver:
        manager_utils.node_power_action(task, states.REBOOT)

    LOG.info(_LI("Deployment to node %s done"), node.uuid)
    task.process_event("done")
Пример #23
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
Пример #24
0
def _set_failed_state(task, msg):
    """Set a node's error state and provision state to signal Nova.

    When deploy steps aren't called by explicitly the conductor, but are
    the result of callbacks, we need to set the node's state explicitly.
    This tells Nova to change the instance's status so the user can see
    their deploy/tear down had an issue and makes debugging/deleting Nova
    instances easier.
    """
    node = task.node
    node.provision_state = states.DEPLOYFAIL
    node.target_provision_state = states.NOSTATE
    node.save(task.context)
    try:
        manager_utils.node_power_action(task, states.POWER_OFF)
    except Exception:
        msg = (_('Node %s failed to power off while handling deploy '
                 'failure. This may be a serious condition. Node '
                 'should be removed from Ironic or put in maintenance '
                 'mode until the problem is resolved.') % node.uuid)
        LOG.error(msg)
    finally:
        # NOTE(deva): node_power_action() erases node.last_error
        #             so we need to set it again here.
        node.last_error = msg
        node.save(task.context)
Пример #25
0
def _reboot_into_deploy_iso(task, ramdisk_options):
    """Reboots the node into a given deploy ISO.

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

    :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)
    manager_utils.node_power_action(task, states.REBOOT)
Пример #26
0
    def clean_up_instance(self, task):
        """Cleans up the boot of instance.

        This method cleans up the environment that was setup for booting
        the instance. It ejects virtual media.
        In case of UEFI iSCSI booting, it cleans up iSCSI target information
        from the node.

        :param task: a task from TaskManager.
        :returns: None
        :raises: IloOperationError, if some operation on iLO failed.
        """
        LOG.debug("Cleaning up the instance.")
        manager_utils.node_power_action(task, states.POWER_OFF)
        disable_secure_boot_if_supported(task)
        driver_internal_info = task.node.driver_internal_info

        if (deploy_utils.is_iscsi_boot(task)
            and task.node.driver_internal_info.get('ilo_uefi_iscsi_boot')):
            # It will clear iSCSI info from iLO
            task.driver.management.clear_iscsi_boot_target(task)
            driver_internal_info.pop('ilo_uefi_iscsi_boot', None)
        else:
            _clean_up_boot_iso_for_instance(task.node)
            driver_internal_info.pop('boot_iso_created_in_web_server', None)
            ilo_common.cleanup_vmedia_boot(task)
        task.node.driver_internal_info = driver_internal_info
        task.node.save()
Пример #27
0
def set_failed_state(task, msg):
    """Sets the deploy status as failed with relevant messages.

    This method sets the deployment as fail with the given message.
    It sets node's provision_state to DEPLOYFAIL and updates last_error
    with the given error message. It also powers off the baremetal node.

    :param task: a TaskManager instance containing the node to act on.
    :param msg: the message to set in last_error of the node.
    """
    node = task.node
    try:
        task.process_event('fail')
    except exception.InvalidState:
        msg2 = (_LE('Internal error. Node %(node)s in provision state '
                    '"%(state)s" could not transition to a failed state.')
                % {'node': node.uuid, 'state': node.provision_state})
        LOG.exception(msg2)

    try:
        manager_utils.node_power_action(task, states.POWER_OFF)
    except Exception:
        msg2 = (_LE('Node %s failed to power off while handling deploy '
                    'failure. This may be a serious condition. Node '
                    'should be removed from Ironic or put in maintenance '
                    'mode until the problem is resolved.') % node.uuid)
        LOG.exception(msg2)

    # NOTE(deva): node_power_action() erases node.last_error
    #             so we need to set it here.
    node.last_error = msg
    node.save()
Пример #28
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)
        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
Пример #29
0
    def test_node_power_action_invalid_state(self):
        """Test for exception when changing to an invalid power state."""
        node = obj_utils.create_test_node(self.context,
                                          uuid=uuidutils.generate_uuid(),
                                          driver='fake',
                                          power_state=states.POWER_ON)
        task = task_manager.TaskManager(self.context, node.uuid)

        with mock.patch.object(self.driver.power,
                               'get_power_state') as get_power_mock:
            get_power_mock.return_value = states.POWER_ON

            self.assertRaises(exception.InvalidParameterValue,
                              conductor_utils.node_power_action,
                              task,
                              "INVALID_POWER_STATE")

            node.refresh()
            get_power_mock.assert_called_once_with(mock.ANY)
            self.assertEqual(states.POWER_ON, node['power_state'])
            self.assertIsNone(node['target_power_state'])
            self.assertIsNotNone(node['last_error'])

            # last_error is cleared when a new transaction happens
            conductor_utils.node_power_action(task, states.POWER_OFF)
            node.refresh()
            self.assertEqual(states.POWER_OFF, node['power_state'])
            self.assertIsNone(node['target_power_state'])
            self.assertIsNone(node['last_error'])
Пример #30
0
    def tear_down(self, task):
        """Tear down a previous deployment on the task's node.

        :param task: a TaskManager instance.
        :returns: status of the deploy. One of ironic.common.states.
        """
        manager_utils.node_power_action(task, states.POWER_OFF)
        return states.DELETED
Пример #31
0
    def deploy(self, task):
        """Start deployment of the task's node'.

        Fetches instance image, creates a temporary keystone token file,
        updates the 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 DEPLOYWAIT.
        """
        iscsi_deploy.cache_instance_image(task.context, task.node)
        iscsi_deploy.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(task)
        provider = dhcp_factory.DHCPFactory()
        provider.update_dhcp(task, dhcp_opts)

        # 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, 'pxe', persistent=True)
        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 is in UEFI boot mode."
                        "Please set the boot device manually."))
            else:
                raise

        manager_utils.node_power_action(task, states.REBOOT)

        return states.DEPLOYWAIT
Пример #32
0
    def tear_down(self, task, node):
        """Tear down a previous deployment.

        Power off the node. All actual clean-up is done in the clean_up()
        method which should be called separately.

        :param task: a TaskManager instance.
        :param node: the Node to act upon.
        :returns: deploy state DELETED.
        """
        manager_utils.node_power_action(task, node, states.POWER_OFF)

        # Remove the internal pxe_deploy_key attribute
        driver_info = node.driver_info
        if driver_info.pop('pxe_deploy_key', None):
            node.driver_info = driver_info
            node.save(task.context)

        return states.DELETED
Пример #33
0
    def tear_down(self, task):
        """Tear down a previous deployment on the task's node.

        :param task: a TaskManager instance.
        :returns: status of the deploy. One of ironic.common.states.
        :raises: NetworkError if the cleaning ports cannot be removed.
        :raises: InvalidParameterValue when the wrong power state is specified
             or the wrong driver info is specified for power management.
        :raises: StorageError when the storage interface attached volumes fail
             to detach.
        :raises: other exceptions by the node's power driver if something
             wrong occurred during the power action.
        """
        manager_utils.node_power_action(task, states.POWER_OFF)
        task.driver.storage.detach_volumes(task)
        deploy_utils.tear_down_storage_configuration(task)
        task.driver.network.unconfigure_tenant_networks(task)

        return states.DELETED
Пример #34
0
def set_failed_state(task, msg, collect_logs=True):
    """Sets the deploy status as failed with relevant messages.

    This method sets the deployment as fail with the given message.
    It sets node's provision_state to DEPLOYFAIL and updates last_error
    with the given error message. It also powers off the baremetal node.

    :param task: a TaskManager instance containing the node to act on.
    :param msg: the message to set in logs and last_error of the node.
    :param collect_logs: Boolean indicating whether to attempt to collect
                         logs from IPA-based ramdisk. Defaults to True.
                         Actual log collection is also affected by
                         CONF.agent.deploy_logs_collect config option.
    """
    node = task.node

    if (collect_logs
            and CONF.agent.deploy_logs_collect in ('on_failure', 'always')):
        driver_utils.collect_ramdisk_logs(node)

    try:
        manager_utils.deploying_error_handler(task, msg, msg, clean_up=False)
    except exception.InvalidState:
        msg2 = ('Internal error. Node %(node)s in provision state '
                '"%(state)s" could not transition to a failed state.' % {
                    'node': node.uuid,
                    'state': node.provision_state
                })
        LOG.exception(msg2)

    if CONF.deploy.power_off_after_deploy_failure:
        try:
            manager_utils.node_power_action(task, states.POWER_OFF)
        except Exception:
            msg2 = ('Node %s failed to power off while handling deploy '
                    'failure. This may be a serious condition. Node '
                    'should be removed from Ironic or put in maintenance '
                    'mode until the problem is resolved.' % node.uuid)
            LOG.exception(msg2)
    # NOTE(tenbrae): node_power_action() erases node.last_error
    #             so we need to set it here.
    node.last_error = msg
    node.save()
Пример #35
0
    def boot_into_iso(self, task, **kwargs):
        """Attaches an ISO image in glance and reboots bare metal.

        This method accepts an ISO image href (a Glance UUID or an HTTP(S) URL)
        attaches it as virtual media and then reboots the node.  This is
        useful for debugging purposes.  This can be invoked only when the node
        is in manage state.

        :param task: A TaskManager object.
        :param kwargs: The arguments sent with vendor passthru. The expected
            kwargs are::

                'boot_iso_href': href of the image to be booted. This can be
                    a Glance UUID or an HTTP(S) URL.
        """
        ilo_common.setup_vmedia(task,
                                kwargs['boot_iso_href'],
                                ramdisk_options=None)
        manager_utils.node_power_action(task, states.REBOOT)
Пример #36
0
def _start_managed_inspection(task):
    """Start inspection managed by ironic."""
    try:
        client = _get_client(task.context)
        endpoint = _get_callback_endpoint(client)
        params = dict(_parse_kernel_params(),
                      **{'ipa-inspection-callback-url': endpoint})

        cond_utils.node_power_action(task, states.POWER_OFF)
        with cond_utils.power_state_for_network_configuration(task):
            task.driver.network.add_inspection_network(task)
        task.driver.boot.prepare_ramdisk(task, ramdisk_params=params)
        client.start_introspection(task.node.uuid, manage_boot=False)
        cond_utils.node_power_action(task, states.POWER_ON)
    except Exception as exc:
        LOG.exception('Unable to start managed inspection for node %(uuid)s: '
                      '%(err)s', {'uuid': task.node.uuid, 'err': exc})
        error = _('unable to start inspection: %s') % exc
        _inspection_error_handler(task, error, raise_exc=True)
Пример #37
0
    def test_node_power_action_power_off(self):
        """Test node_power_action to turn node power off."""
        node = obj_utils.create_test_node(self.context,
                                          uuid=cmn_utils.generate_uuid(),
                                          driver='fake',
                                          power_state=states.POWER_ON)
        task = task_manager.TaskManager(self.context, node.uuid)

        with mock.patch.object(self.driver.power,
                               'get_power_state') as get_power_mock:
            get_power_mock.return_value = states.POWER_ON

            conductor_utils.node_power_action(task, states.POWER_OFF)

            node.refresh()
            get_power_mock.assert_called_once_with(mock.ANY)
            self.assertEqual(states.POWER_OFF, node['power_state'])
            self.assertIsNone(node['target_power_state'])
            self.assertIsNone(node['last_error'])
Пример #38
0
    def unrescue(self, task):
        """Attempt to move a rescued node back to active state.

        :param task: a TaskManager instance.
        :raises: NetworkError if the rescue ports cannot be removed.
        :raises: InvalidParameterValue when the wrong power state is specified
             or the wrong driver info is specified for power management.
        :raises: other exceptions by the node's power driver if something
             wrong occurred during the power action.
        :raises: any boot interface's prepare_instance exceptions.
        :returns: Returns states.ACTIVE
        """
        manager_utils.node_power_action(task, states.POWER_OFF)
        self.clean_up(task)
        task.driver.network.configure_tenant_networks(task)
        task.driver.boot.prepare_instance(task)
        manager_utils.node_power_action(task, states.POWER_ON)

        return states.ACTIVE
Пример #39
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.
        """
        try:
            manager_utils.node_power_action(task, states.REBOOT)
        except Exception as e:
            msg = (_('Error rebooting node %(node)s. Error: %(error)s') %
                   {'node': task.node.uuid, 'error': e})
            self._log_and_raise_deployment_error(task, msg)

        task.process_event('done')
        LOG.info(_LI('Deployment to node %s done'), task.node.uuid)
Пример #40
0
    def test_node_power_action_already_being_processed(self):
        """The target_power_state is expected to be None so it isn't
        checked in the code. This is what happens if it is not None.
        (Eg, if a conductor had died during a previous power-off
        attempt and left the target_power_state set to states.POWER_OFF,
        and the user is attempting to power-off again.)
        """
        node = obj_utils.create_test_node(self.context,
                                          uuid=cmn_utils.generate_uuid(),
                                          driver='fake',
                                          power_state=states.POWER_ON,
                                          target_power_state=states.POWER_OFF)
        task = task_manager.TaskManager(self.context, node.uuid)

        conductor_utils.node_power_action(task, states.POWER_OFF)

        node.refresh()
        self.assertEqual(states.POWER_OFF, node['power_state'])
        self.assertEqual(states.NOSTATE, node['target_power_state'])
        self.assertIsNone(node['last_error'])
Пример #41
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')
Пример #42
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_power_action(task, node, states.REBOOT)

        return states.DEPLOYWAIT
Пример #43
0
    def deploy(self, task):
        """Start deployment of the task's node.

        Fetches instance image, creates a temporary keystone token file,
        updates the 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.pass_deploy_info().

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYWAIT.
        """
        node = task.node
        cache_instance_image(task.context, node)
        check_image_size(task)

        manager_utils.node_power_action(task, states.REBOOT)

        return states.DEPLOYWAIT
Пример #44
0
    def tear_down(self, task):
        """Tear down a previous deployment on the task's node.

        Power off the node. All actual clean-up is done in the clean_up()
        method which should be called separately.

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DELETED.
        :raises: NetworkError if the cleaning ports cannot be removed.
        :raises: InvalidParameterValue when the wrong state is specified
             or the wrong driver info is specified.
        :raises: StorageError when volume detachment fails.
        :raises: other exceptions by the node's power driver if something
             wrong occurred during the power action.
        """
        manager_utils.node_power_action(task, states.POWER_OFF)
        task.driver.storage.detach_volumes(task)
        deploy_utils.tear_down_storage_configuration(task)
        task.driver.network.unconfigure_tenant_networks(task)
        return states.DELETED
Пример #45
0
def _reboot_into(task, iso, ramdisk_options):
    """Reboots the node into a given boot ISO.

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

    :param task: a TaskManager instance containing the node to act on.
    :param iso: a bootable ISO image to attach to.  The boot iso
        should be present in either Glance or in Swift. If present in
        Glance, it should be of format 'glance:<glance-image-uuid>'.
        If present in Swift, it should be of format 'swift:<object-name>'.
        It is assumed that object is present in CONF.ilo.swift_ilo_container.
    :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.
    """
    ilo_common.setup_vmedia_for_boot(task, iso, ramdisk_options)
    manager_utils.node_set_boot_device(task, boot_devices.CDROM)
    manager_utils.node_power_action(task, states.REBOOT)
Пример #46
0
    def prepare(self, task):
        """Prepare the deployment environment for this task's node.

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

        :param task: a TaskManager instance containing the node to act on.
        :raises: NetworkError: if the previous cleaning ports cannot be removed
            or if new cleaning ports cannot be created.
        :raises: InvalidParameterValue when the wrong power state is specified
            or the wrong driver info is specified for power management.
        :raises: StorageError If the storage driver is unable to attach the
            configured volumes.
        :raises: other exceptions by the node's power driver if something
            wrong occurred during the power action.
        :raises: any boot interface's prepare_ramdisk exceptions.
        """
        node = task.node
        deploy_utils.populate_storage_driver_internal_info(task)
        if node.provision_state in [states.ACTIVE, states.ADOPTING]:
            task.driver.boot.prepare_instance(task)
        else:
            if node.provision_state == states.DEPLOYING:
                # Adding the node to provisioning network so that the dhcp
                # options get added for the provisioning port.
                manager_utils.node_power_action(task, states.POWER_OFF)
                # NOTE(vdrok): in case of rebuild, we have tenant network
                # already configured, unbind tenant ports if present
                if task.driver.storage.should_write_image(task):
                    task.driver.network.unconfigure_tenant_networks(task)
                    task.driver.network.add_provisioning_network(task)
                task.driver.storage.attach_volumes(task)
                if not task.driver.storage.should_write_image(task):
                    # We have nothing else to do as this is handled in the
                    # backend storage system, and we can return to the caller
                    # as we do not need to boot the agent to deploy.
                    return

            deploy_opts = deploy_utils.build_agent_options(node)
            task.driver.boot.prepare_ramdisk(task, deploy_opts)
Пример #47
0
    def test_node_power_action_power_soft_reboot_timeout(self):
        """Test for soft reboot a node."""
        node = obj_utils.create_test_node(self.context,
                                          uuid=uuidutils.generate_uuid(),
                                          driver='fake_soft_power',
                                          power_state=states.POWER_ON)
        task = task_manager.TaskManager(self.context, node.uuid)

        with mock.patch.object(self.driver.power,
                               'get_power_state') as get_power_mock:
            get_power_mock.return_value = states.POWER_ON

            conductor_utils.node_power_action(task,
                                              states.SOFT_REBOOT,
                                              timeout=2)

            node.refresh()
            get_power_mock.assert_called_once_with(mock.ANY)
            self.assertEqual(states.POWER_ON, node['power_state'])
            self.assertIsNone(node['target_power_state'])
            self.assertIsNone(node['last_error'])
Пример #48
0
 def prepare(self, task):
     """Prepare the deployment environment for this node."""
     node = task.node
     # TODO(pas-ha) investigate takeover scenario
     if node.provision_state == states.DEPLOYING:
         # adding network-driver dependent provisioning ports
         fast_track = manager_utils.is_fast_track(task)
         power_state_to_restore = None
         if not fast_track:
             manager_utils.node_power_action(task, states.POWER_OFF)
             power_state_to_restore = (
                 manager_utils.power_on_node_if_needed(task))
         task.driver.network.add_provisioning_network(task)
         manager_utils.restore_power_state_if_needed(
             task, power_state_to_restore)
     if node.provision_state not in [states.ACTIVE, states.ADOPTING]:
         node.instance_info = deploy_utils.build_instance_info_for_deploy(
             task)
         node.save()
         boot_opt = deploy_utils.build_agent_options(node)
         task.driver.boot.prepare_ramdisk(task, boot_opt)
Пример #49
0
    def tear_down(self, task):
        """Tear down a previous deployment on the task's node.

        Power off the node. All actual clean-up is done in the clean_up()
        method which should be called separately.

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DELETED.
        """
        manager_utils.node_power_action(task, states.POWER_OFF)
        try:
            _update_secure_boot_mode(task, False)
        # We need to handle IloOperationNotSupported exception so that if
        # the user has incorrectly specified the Node capability
        # 'secure_boot' to a node that does not have that capability and
        # attempted deploy. Handling this exception here, will help the
        # user to tear down such a Node.
        except exception.IloOperationNotSupported:
            LOG.warn(_LW('Secure boot mode is not supported for node %s'),
                     task.node.uuid)
        return states.DELETED
Пример #50
0
    def deploy(self, task):
        """Perform a deployment to a node."""
        manager_utils.node_power_action(task, states.REBOOT)
        if CONF.ansible.use_ramdisk_callback:
            return states.DEPLOYWAIT
        node = task.node
        ip_addr = _get_node_ip(task)
        try:
            _deploy(task, ip_addr)
        except Exception as e:
            error = _('Deploy failed for node %(node)s: '
                      'Error: %(exc)s') % {
                          'node': node.uuid,
                          'exc': six.text_type(e)
                      }
            LOG.exception(error)
            self._set_failed_state(task, error)

        else:
            LOG.info(_LI('Deployment to node %s done'), node.uuid)
            return states.DEPLOYDONE
Пример #51
0
    def prepare_cleaning(self, task):
        """Boot into the ramdisk to prepare for cleaning.

        :param task: a TaskManager object containing the node
        :raises NodeCleaningFailure: if the previous cleaning ports cannot
                be removed or if new cleaning ports cannot be created
        :returns: None or states.CLEANWAIT for async prepare.
        """
        node = task.node
        conductor_steps.set_node_cleaning_steps(task)
        if not node.driver_internal_info['clean_steps']:
            # no clean steps configured, nothing to do.
            return
        power_state_to_restore = manager_utils.power_on_node_if_needed(task)
        task.driver.network.add_cleaning_network(task)
        manager_utils.restore_power_state_if_needed(task,
                                                    power_state_to_restore)
        boot_opt = deploy_utils.build_agent_options(node)
        task.driver.boot.prepare_ramdisk(task, boot_opt)
        manager_utils.node_power_action(task, states.REBOOT)
        return states.CLEANWAIT
Пример #52
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.
        """
        if task.driver.storage.should_write_image(task):
            manager_utils.node_power_action(task, states.REBOOT)
            return states.DEPLOYWAIT
        else:
            # TODO(TheJulia): At some point, we should de-dupe this code
            # as it is nearly identical to the iscsi deploy interface.
            # This is not being done now as it is expected to be
            # refactored in the near future.
            manager_utils.node_power_action(task, states.POWER_OFF)
            task.driver.network.remove_provisioning_network(task)
            task.driver.network.configure_tenant_networks(task)
            task.driver.boot.prepare_instance(task)
            manager_utils.node_power_action(task, states.POWER_ON)
            LOG.info('Deployment to node %s done', task.node.uuid)
            return states.DEPLOYDONE
Пример #53
0
    def deploy(self, task):
        """Start deployment of the task's node.

        Fetches instance image, updates the 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 agent heartbeats.

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYWAIT.
        """
        node = task.node
        if task.driver.storage.should_write_image(task):
            deploy_utils.cache_instance_image(task.context, node)
            check_image_size(task)
            manager_utils.node_power_action(task, states.REBOOT)

            return states.DEPLOYWAIT
        else:
            # TODO(TheJulia): At some point, we should de-dupe this code
            # as it is nearly identical to the agent deploy interface.
            # This is not being done now as it is expected to be
            # refactored in the near future.
            manager_utils.node_power_action(task, states.POWER_OFF)
            task.driver.network.remove_provisioning_network(task)
            task.driver.network.configure_tenant_networks(task)
            task.driver.boot.prepare_instance(task)
            manager_utils.node_power_action(task, states.POWER_ON)

            return None
Пример #54
0
    def prepare_cleaning(self, task):
        """Boot into the ramdisk to prepare for cleaning.

        :param task: a TaskManager object containing the node
        :raises NodeCleaningFailure: if the previous cleaning ports cannot
                be removed or if new cleaning ports cannot be created
        :returns: None or states.CLEANWAIT for async prepare.
        """
        node = task.node
        use_callback = CONF.ansible.use_ramdisk_callback
        if use_callback:
            manager_utils.set_node_cleaning_steps(task)
            if not node.driver_internal_info['clean_steps']:
                # no clean steps configured, nothing to do.
                return
        task.driver.network.add_cleaning_network(task)
        boot_opt = deploy_utils.build_agent_options(node)
        task.driver.boot.prepare_ramdisk(task, boot_opt)
        manager_utils.node_power_action(task, states.REBOOT)
        if use_callback:
            return states.CLEANWAIT

        ip_addr = _get_node_ip(task)
        LOG.debug('IP of node %(node)s is %(ip)s', {
            'node': node.uuid,
            'ip': ip_addr
        })
        driver_internal_info = node.driver_internal_info
        driver_internal_info['ansible_cleaning_ip'] = ip_addr
        node.driver_internal_info = driver_internal_info
        node.save()
        playbook, user, key = _parse_ansible_driver_info(task.node,
                                                         action='clean')
        node_list = [(node.uuid, ip_addr, user, node.extra)]
        extra_vars = _prepare_extra_vars(node_list)

        LOG.debug('Waiting ramdisk on node %s for cleaning', node.uuid)
        _run_playbook(playbook, extra_vars, key, tags=['wait'])
        LOG.info(_LI('Node %s is ready for cleaning'), node.uuid)
Пример #55
0
    def test_node_power_action_power_on_notify(self, mock_notif):
        """Test node_power_action to power on node and send notification."""
        self.config(notification_level='info')
        self.config(host='my-host')
        # Required for exception handling
        mock_notif.__name__ = 'NodeSetPowerStateNotification'
        node = obj_utils.create_test_node(self.context,
                                          uuid=uuidutils.generate_uuid(),
                                          driver='fake',
                                          power_state=states.POWER_OFF)
        task = task_manager.TaskManager(self.context, node.uuid)

        with mock.patch.object(self.driver.power,
                               'get_power_state') as get_power_mock:
            get_power_mock.return_value = states.POWER_OFF

            conductor_utils.node_power_action(task, states.POWER_ON)

            node.refresh()
            get_power_mock.assert_called_once_with(mock.ANY)
            self.assertEqual(states.POWER_ON, node.power_state)
            self.assertIsNone(node.target_power_state)
            self.assertIsNone(node.last_error)

            # 2 notifications should be sent: 1 .start and 1 .end
            self.assertEqual(2, mock_notif.call_count)
            self.assertEqual(2, mock_notif.return_value.emit.call_count)

            first_notif_args = mock_notif.call_args_list[0][1]
            second_notif_args = mock_notif.call_args_list[1][1]

            self.assertNotificationEqual(first_notif_args, 'ironic-conductor',
                                         CONF.host,
                                         'baremetal.node.power_set.start',
                                         obj_fields.NotificationLevel.INFO)
            self.assertNotificationEqual(second_notif_args, 'ironic-conductor',
                                         CONF.host,
                                         'baremetal.node.power_set.end',
                                         obj_fields.NotificationLevel.INFO)
Пример #56
0
    def one_button_secure_erase(self, task):
        """Erase the whole system securely.

        The One-button secure erase process resets iLO and deletes all licenses
        stored there, resets BIOS settings, and deletes all Active Health
        System (AHS) and warranty data stored on the system. It also erases
        supported non-volatile storage data and deletes any deployment setting
        profiles.

        :param task: a TaskManager instance.
        :raises: IloError on an error from iLO.
        """
        node = task.node
        LOG.info("Calling one button secure erase for node %(node)s",
                 {'node': node.uuid})
        try:
            ilo_object = ilo_common.get_ilo_object(node)
            ilo_object.do_one_button_secure_erase()
            manager_utils.node_power_action(task, states.REBOOT)
            node.maintenance = True
            node.maintenance_reason = (
                "One Button Secure erase clean step has begun, it will wipe "
                "data from drives and any non-volatile/persistent storage, "
                "reset iLO and delete all licenses stored there, reset BIOS "
                "settings, delete  Active Health System (AHS) and warranty "
                "data stored in the system and delete any deployment settings "
                "profiles.")
            node.save()
            return states.CLEANWAIT
        except ilo_error.IloError as ilo_exception:
            log_msg = ("One button secure erase job failed for node "
                       "%(node)s. Message: '%(message)s'." % {
                           'node': task.node.uuid,
                           'message': ilo_exception
                       })
            manager_utils.cleaning_error_handler(task,
                                                 log_msg,
                                                 errmsg=ilo_exception)
Пример #57
0
    def deploy(self, task):
        """Start deployment of the task's node.

        Fetches instance image, updates the 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 agent heartbeats.

        :param task: a TaskManager instance containing the node to act on.
        :returns: deploy state DEPLOYWAIT.
        """
        node = task.node
        if manager_utils.is_fast_track(task):
            # NOTE(mgoddard): For fast track we can mostly skip this step and
            # proceed to the next step (i.e. write_image).
            LOG.debug('Performing a fast track deployment for %(node)s.',
                      {'node': task.node.uuid})
            deploy_utils.cache_instance_image(task.context, node)
            check_image_size(task)
            # NOTE(dtantsur): while the node is up and heartbeating, we don't
            # necessary have the deploy steps cached. Force a refresh here.
            self.refresh_steps(task, 'deploy')
        elif task.driver.storage.should_write_image(task):
            # Standard deploy process
            deploy_utils.cache_instance_image(task.context, node)
            check_image_size(task)
            # Check if the driver has already performed a reboot in a previous
            # deploy step.
            if not task.node.driver_internal_info.get('deployment_reboot',
                                                      False):
                manager_utils.node_power_action(task, states.REBOOT)
            info = task.node.driver_internal_info
            info.pop('deployment_reboot', None)
            info.pop('deployment_uuids', None)
            task.node.driver_internal_info = info
            task.node.save()

            return states.DEPLOYWAIT
Пример #58
0
    def deploy(self, task):
        if 'configdrive' in task.node.instance_info:
            LOG.warning('A configuration drive is present with '
                        'in the deployment request of node %(node)s. '
                        'The configuration drive will be ignored for '
                        'this deployment.',
                        {'node': task.node})
        manager_utils.node_power_action(task, states.POWER_OFF)
        # Tenant neworks must enable connectivity to the boot
        # location, as reboot() can otherwise be very problematic.
        # IDEA(TheJulia): Maybe a "trusted environment" mode flag
        # that we otherwise fail validation on for drivers that
        # require explicit security postures.
        task.driver.network.configure_tenant_networks(task)

        # calling boot.prepare_instance will also set the node
        # to PXE boot, and update PXE templates accordingly
        task.driver.boot.prepare_instance(task)

        # Power-on the instance, with PXE prepared, we're done.
        manager_utils.node_power_action(task, states.POWER_ON)
        LOG.info('Deployment setup for node %s done', task.node.uuid)
        return None
Пример #59
0
    def rescue(self, task):
        """Boot a rescue ramdisk on the node.

        :param task: a TaskManager instance.
        :raises: NetworkError if the tenant ports cannot be removed.
        :raises: InvalidParameterValue when the wrong power state is specified
             or the wrong driver info is specified for power management.
        :raises: other exceptions by the node's power driver if something
             wrong occurred during the power action.
        :raises: any boot interface's prepare_ramdisk exceptions.
        :returns: Returns states.RESCUEWAIT
        """
        manager_utils.node_power_action(task, states.POWER_OFF)
        task.driver.boot.clean_up_instance(task)
        task.driver.network.unconfigure_tenant_networks(task)
        task.driver.network.add_rescuing_network(task)
        if CONF.agent.manage_agent_boot:
            ramdisk_opts = deploy_utils.build_agent_options(task.node)
            # prepare_ramdisk will set the boot device
            task.driver.boot.prepare_ramdisk(task, ramdisk_opts)
        manager_utils.node_power_action(task, states.POWER_ON)

        return states.RESCUEWAIT
Пример #60
0
def tear_down_inband_cleaning(task, manage_boot=True):
    """Tears down the environment setup for in-band cleaning.

    This method does the following:
    1. Powers off the bare metal node.
    2. If 'manage_boot' parameter is set to true, it also
    calls the 'clean_up_ramdisk' method of boot interface to clean up
    the environment that was set for booting agent ramdisk.
    3. Deletes the cleaning ports which were setup as part
    of cleaning.

    :param task: a TaskManager object containing the node
    :param manage_boot: If this is set to True, this method calls the
        'clean_up_ramdisk' method of boot interface to boot the agent
        ramdisk. If False, it skips this step.
    :raises: NetworkError, NodeCleaningFailure if the cleaning ports cannot be
        removed.
    """
    manager_utils.node_power_action(task, states.POWER_OFF)
    if manage_boot:
        task.driver.boot.clean_up_ramdisk(task)

    task.driver.network.remove_cleaning_network(task)