コード例 #1
0
ファイル: iscsi_deploy.py プロジェクト: ponymwt/ironic
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')
コード例 #2
0
    def test_continue_deploy_fail(self, deploy_mock, power_mock,
                                  mock_image_cache, mock_disk_layout,
                                  mock_collect_logs):
        kwargs = {'address': '123456', 'iqn': 'aaa-bbb'}
        deploy_mock.side_effect = exception.InstanceDeployFailure(
            "test deploy error")
        self.node.provision_state = states.DEPLOYWAIT
        self.node.target_provision_state = states.ACTIVE
        self.node.save()

        with task_manager.acquire(self.context, self.node.uuid,
                                  shared=False) as task:
            params = iscsi_deploy.get_deploy_info(task.node, **kwargs)
            self.assertRaises(exception.InstanceDeployFailure,
                              iscsi_deploy.continue_deploy, task, **kwargs)
            self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
            self.assertEqual(states.ACTIVE, task.node.target_provision_state)
            self.assertIsNotNone(task.node.last_error)
            deploy_mock.assert_called_once_with(**params)
            power_mock.assert_called_once_with(task, states.POWER_OFF)
            mock_image_cache.assert_called_once_with()
            mock_image_cache.return_value.clean_up.assert_called_once_with()
            self.assertFalse(mock_disk_layout.called)
            mock_collect_logs.assert_called_once_with(task.node)
コード例 #3
0
def validate_bootloader_install_status(task, input_params):
    """Validate if bootloader was installed.

    This method first validates if deploy key sent in vendor passthru
    was correct one, and then validates whether bootloader installation
    was successful or not.

    :param task: A TaskManager object.
    :param input_params: A dictionary of params sent as input to passthru.
    :raises: InstanceDeployFailure, if bootloader installation was
        reported from ramdisk as failure.
    """
    node = task.node
    if input_params['status'] != 'SUCCEEDED':
        msg = (_('Failed to install bootloader on node %(node)s. '
                 'Error: %(error)s.') % {
                     'node': node.uuid,
                     'error': input_params.get('error')
                 })
        LOG.error(msg)
        deploy_utils.set_failed_state(task, msg)
        raise exception.InstanceDeployFailure(msg)

    LOG.info(_LI('Bootloader successfully installed on node %s'), node.uuid)
コード例 #4
0
ファイル: management.py プロジェクト: krmartin/ironic
    def update_firmware(self, task, **kwargs):
        """Updates the firmware.

        :param task: a TaskManager object.
        :raises: InvalidParameterValue if update firmware mode is not 'ilo'.
                 Even applicable for invalid input cases.
        :raises: NodeCleaningFailure, on failure to execute of clean step.
        :raises: InstanceDeployFailure, on failure to execute of deploy step.
        """
        node = task.node
        fw_location_objs_n_components = []
        firmware_images = kwargs['firmware_images']
        # Note(deray): Processing of firmware images happens here. As part
        # of processing checksum validation is also done for the firmware file.
        # Processing of firmware file essentially means downloading the file
        # on the conductor, validating the checksum of the downloaded content,
        # extracting the raw firmware file from its compact format, if it is,
        # and hosting the file on a web server or a swift store based on the
        # need of the baremetal server iLO firmware update method.
        try:
            for firmware_image_info in firmware_images:
                url, checksum, component = (
                    firmware_processor.get_and_validate_firmware_image_info(
                        firmware_image_info, kwargs['firmware_update_mode']))
                LOG.debug("Processing of firmware file: %(firmware_file)s on "
                          "node: %(node)s ... in progress",
                          {'firmware_file': url, 'node': node.uuid})

                fw_processor = firmware_processor.FirmwareProcessor(url)
                fw_location_obj = fw_processor.process_fw_on(node, checksum)
                fw_location_objs_n_components.append(
                    (fw_location_obj, component))

                LOG.debug("Processing of firmware file: %(firmware_file)s on "
                          "node: %(node)s ... done",
                          {'firmware_file': url, 'node': node.uuid})
        except exception.IronicException as ilo_exc:
            # delete all the files extracted so far from the extracted list
            # and re-raise the exception
            for fw_loc_obj_n_comp_tup in fw_location_objs_n_components:
                fw_loc_obj_n_comp_tup[0].remove()
            LOG.error("Processing of firmware image: %(firmware_image)s "
                      "on node: %(node)s ... failed",
                      {'firmware_image': firmware_image_info,
                       'node': node.uuid})
            if node.clean_step:
                raise exception.NodeCleaningFailure(node=node.uuid,
                                                    reason=ilo_exc)
            raise exception.InstanceDeployFailure(reason=ilo_exc)

        # Updating of firmware images happen here.
        try:
            for fw_location_obj, component in fw_location_objs_n_components:
                fw_location = fw_location_obj.fw_image_location
                LOG.debug("Firmware update for %(firmware_file)s on "
                          "node: %(node)s ... in progress",
                          {'firmware_file': fw_location, 'node': node.uuid})

                _execute_ilo_step(
                    node, 'update_firmware', fw_location, component)

                LOG.debug("Firmware update for %(firmware_file)s on "
                          "node: %(node)s ... done",
                          {'firmware_file': fw_location, 'node': node.uuid})
        except (exception.NodeCleaningFailure,
                exception.InstanceDeployFailure):
            with excutils.save_and_reraise_exception():
                LOG.error("Firmware update for %(firmware_file)s on "
                          "node: %(node)s failed.",
                          {'firmware_file': fw_location, 'node': node.uuid})
        finally:
            for fw_loc_obj_n_comp_tup in fw_location_objs_n_components:
                fw_loc_obj_n_comp_tup[0].remove()

        # Firmware might have ejected the virtual media, if it was used.
        # Re-create the environment for agent boot, if required
        task.driver.boot.clean_up_ramdisk(task)
        deploy_opts = deploy_utils.build_agent_options(node)
        task.driver.boot.prepare_ramdisk(task, deploy_opts)

        LOG.info("All Firmware update operations completed successfully "
                 "for node: %s.", node.uuid)
コード例 #5
0
 def _log_and_raise_deployment_error(self, task, msg):
     """Helper method to log the error and raise exception."""
     LOG.error(msg)
     deploy_utils.set_failed_state(task, msg)
     raise exception.InstanceDeployFailure(msg)
コード例 #6
0
def do_agent_iscsi_deploy(task, agent_client):
    """Method invoked when deployed with the agent ramdisk.

    This method is invoked by drivers for doing iSCSI deploy
    using agent ramdisk.  This method assumes that the agent
    is booted up on the node and is heartbeating.

    :param task: a TaskManager object containing the node.
    :param agent_client: an instance of agent_client.AgentClient
                         which will be used during iscsi deploy
                         (for exposing node's target disk via iSCSI,
                         for install boot loader, etc).
    :returns: a dictionary containing the following keys:

              For partition image:

              * 'root uuid': UUID of root partition
              * 'efi system partition uuid': UUID of the uefi system partition
                (if boot mode is uefi).

                .. note:: If key exists but value is None, it means partition
                          doesn't exist.

              For whole disk image:

              * 'disk identifier': ID of the disk to which image was deployed.
    :raises: InstanceDeployFailure if it encounters some error
             during the deploy.
    """
    node = task.node
    i_info = deploy_utils.parse_instance_info(node)
    wipe_disk_metadata = not i_info['preserve_ephemeral']

    iqn = 'iqn.2008-10.org.openstack:%s' % node.uuid
    portal_port = CONF.iscsi.portal_port
    conv_flags = CONF.iscsi.conv_flags
    result = agent_client.start_iscsi_target(
        node, iqn,
        portal_port,
        wipe_disk_metadata=wipe_disk_metadata)
    if result['command_status'] == 'FAILED':
        msg = (_("Failed to start the iSCSI target to deploy the "
                 "node %(node)s. Error: %(error)s") %
               {'node': node.uuid, 'error': result['command_error']})
        deploy_utils.set_failed_state(task, msg)
        raise exception.InstanceDeployFailure(reason=msg)

    address = parse.urlparse(node.driver_internal_info['agent_url'])
    address = address.hostname

    uuid_dict_returned = continue_deploy(task, iqn=iqn, address=address,
                                         conv_flags=conv_flags)
    root_uuid_or_disk_id = uuid_dict_returned.get(
        'root uuid', uuid_dict_returned.get('disk identifier'))

    # TODO(lucasagomes): Move this bit saving the root_uuid to
    # continue_deploy()
    driver_internal_info = node.driver_internal_info
    driver_internal_info['root_uuid_or_disk_id'] = root_uuid_or_disk_id
    node.driver_internal_info = driver_internal_info
    node.save()

    return uuid_dict_returned
コード例 #7
0
def start_deploy(task, manager, configdrive=None, event='deploy'):
    """Start deployment or rebuilding on a node.

    This function does not check the node suitability for deployment, it's left
    up to the caller.

    :param task: a TaskManager instance.
    :param manager: a ConductorManager to run tasks on.
    :param configdrive: a configdrive, if requested.
    :param event: event to process: deploy or rebuild.
    """
    node = task.node
    # Record of any pre-existing agent_url should be removed
    # except when we are in fast track conditions.
    if not utils.is_fast_track(task):
        utils.remove_agent_url(node)

    if event == 'rebuild':
        # Note(gilliard) Clear these to force the driver to
        # check whether they have been changed in glance
        # NOTE(vdrok): If image_source is not from Glance we should
        # not clear kernel and ramdisk as they're input manually
        if glance_utils.is_glance_image(
                node.instance_info.get('image_source')):
            instance_info = node.instance_info
            instance_info.pop('kernel', None)
            instance_info.pop('ramdisk', None)
            node.instance_info = instance_info

    driver_internal_info = node.driver_internal_info
    # Infer the image type to make sure the deploy driver
    # validates only the necessary variables for different
    # image types.
    # NOTE(sirushtim): The iwdi variable can be None. It's up to
    # the deploy driver to validate this.
    iwdi = images.is_whole_disk_image(task.context, node.instance_info)
    driver_internal_info['is_whole_disk_image'] = iwdi
    node.driver_internal_info = driver_internal_info
    node.save()

    try:
        task.driver.power.validate(task)
        task.driver.deploy.validate(task)
        utils.validate_instance_info_traits(task.node)
        conductor_steps.validate_deploy_templates(task)
    except exception.InvalidParameterValue as e:
        raise exception.InstanceDeployFailure(
            _("Failed to validate deploy or power info for node "
              "%(node_uuid)s. Error: %(msg)s") % {
                  'node_uuid': node.uuid,
                  'msg': e
              },
            code=e.code)

    try:
        task.process_event(event,
                           callback=manager._spawn_worker,
                           call_args=(do_node_deploy, task,
                                      manager.conductor.id, configdrive),
                           err_handler=utils.provisioning_error_handler)
    except exception.InvalidState:
        raise exception.InvalidStateRequested(action=event,
                                              node=task.node.uuid,
                                              state=task.node.provision_state)
コード例 #8
0
    def prepare_instance(self, task):
        """Prepares the boot of instance over virtual media.

        This method prepares the boot of the instance after reading
        relevant information from the node's instance_info.

        The internal logic is as follows:

        - If `boot_option` requested for this deploy is 'local', then set the
          node to boot from disk.
        - Unless `boot_option` requested for this deploy is 'ramdisk', pass
          root disk/partition ID to virtual media boot image
        - Otherwise build boot image, insert it into virtual media device
          and set node to boot from CD.

        :param task: a task from TaskManager.
        :returns: None
        :raises: InstanceDeployFailure, if its try to boot iSCSI volume in
                 'BIOS' boot mode.
        """
        node = task.node

        boot_mode_utils.sync_boot_mode(task)

        boot_option = deploy_utils.get_boot_option(node)
        self.clean_up_instance(task)
        iwdi = node.driver_internal_info.get('is_whole_disk_image')
        if boot_option == "local" or iwdi:
            self._set_boot_device(task, boot_devices.DISK, persistent=True)

            LOG.debug(
                "Node %(node)s is set to permanently boot from local "
                "%(device)s", {
                    'node': task.node.uuid,
                    'device': boot_devices.DISK
                })
            return

        params = {}

        if boot_option != 'ramdisk':
            root_uuid = node.driver_internal_info.get('root_uuid_or_disk_id')
            if not root_uuid and task.driver.storage.should_write_image(task):
                LOG.warning(
                    "The UUID of the root partition could not be found for "
                    "node %s. Booting instance from disk anyway.", node.uuid)

                self._set_boot_device(task, boot_devices.DISK, persistent=True)

                return

            params.update(root_uuid=root_uuid)

        managers = redfish_utils.get_system(task.node).managers

        deploy_info = _parse_deploy_info(node)
        configdrive = node.instance_info.get('configdrive')
        iso_ref = image_utils.prepare_boot_iso(task, deploy_info, **params)
        _eject_vmedia(task, managers, sushy.VIRTUAL_MEDIA_CD)
        _insert_vmedia(task, managers, iso_ref, sushy.VIRTUAL_MEDIA_CD)

        if configdrive and boot_option == 'ramdisk':
            _eject_vmedia(task, managers, sushy.VIRTUAL_MEDIA_USBSTICK)
            cd_ref = image_utils.prepare_configdrive_image(task, configdrive)
            try:
                _insert_vmedia(task, managers, cd_ref,
                               sushy.VIRTUAL_MEDIA_USBSTICK)
            except exception.InvalidParameterValue:
                raise exception.InstanceDeployFailure(
                    _('Cannot attach configdrive for node %s: no suitable '
                      'virtual USB slot has been found') % node.uuid)

        del managers

        self._set_boot_device(task, boot_devices.CDROM, persistent=True)

        LOG.debug(
            "Node %(node)s is set to permanently boot from "
            "%(device)s", {
                'node': task.node.uuid,
                'device': boot_devices.CDROM
            })
コード例 #9
0
 def test__do_node_deploy_driver_ironic_exception(self):
     self._test__do_node_deploy_driver_exception(
         exception.InstanceDeployFailure('test'))
コード例 #10
0
ファイル: deploy_utils.py プロジェクト: Codixis/ironic
def work_on_disk(dev,
                 root_mb,
                 swap_mb,
                 ephemeral_mb,
                 ephemeral_format,
                 image_path,
                 node_uuid,
                 preserve_ephemeral=False,
                 configdrive=None,
                 boot_option="netboot",
                 boot_mode="bios"):
    """Create partitions and copy an image to the root partition.

    :param dev: Path for the device to work on.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param image_path: Path for the instance's disk image.
    :param node_uuid: node's uuid. Used for logging.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).
    :param configdrive: Optional. Base64 encoded Gzipped configdrive content
                        or configdrive HTTP URL.
    :param boot_option: Can be "local" or "netboot". "netboot" by default.
    :param boot_mode: Can be "bios" or "uefi". "bios" by default.
    :returns: a dictionary containing the following keys:
        'root uuid': UUID of root partition
        'efi system partition uuid': UUID of the uefi system partition
                                     (if boot mode is uefi).
        NOTE: If key exists but value is None, it means partition doesn't
              exist.
    """
    # the only way for preserve_ephemeral to be set to true is if we are
    # rebuilding an instance with --preserve_ephemeral.
    commit = not preserve_ephemeral
    # now if we are committing the changes to disk clean first.
    if commit:
        destroy_disk_metadata(dev, node_uuid)

    try:
        # If requested, get the configdrive file and determine the size
        # of the configdrive partition
        configdrive_mb = 0
        configdrive_file = None
        if configdrive:
            configdrive_mb, configdrive_file = _get_configdrive(
                configdrive, node_uuid)

        part_dict = make_partitions(dev,
                                    root_mb,
                                    swap_mb,
                                    ephemeral_mb,
                                    configdrive_mb,
                                    commit=commit,
                                    boot_option=boot_option,
                                    boot_mode=boot_mode)

        ephemeral_part = part_dict.get('ephemeral')
        swap_part = part_dict.get('swap')
        configdrive_part = part_dict.get('configdrive')
        root_part = part_dict.get('root')

        if not is_block_device(root_part):
            raise exception.InstanceDeployFailure(
                _("Root device '%s' not found") % root_part)

        for part in ('swap', 'ephemeral', 'configdrive',
                     'efi system partition'):
            part_device = part_dict.get(part)
            LOG.debug(
                "Checking for %(part)s device (%(dev)s) on node "
                "%(node)s.", {
                    'part': part,
                    'dev': part_device,
                    'node': node_uuid
                })
            if part_device and not is_block_device(part_device):
                raise exception.InstanceDeployFailure(
                    _("'%(partition)s' device '%(part_device)s' not found") % {
                        'partition': part,
                        'part_device': part_device
                    })

        # If it's a uefi localboot, then we have created the efi system
        # partition.  Create a fat filesystem on it.
        if boot_mode == "uefi" and boot_option == "local":
            efi_system_part = part_dict.get('efi system partition')
            mkfs(dev=efi_system_part, fs='vfat', label='efi-part')

        if configdrive_part:
            # Copy the configdrive content to the configdrive partition
            dd(configdrive_file, configdrive_part)

    finally:
        # If the configdrive was requested make sure we delete the file
        # after copying the content to the partition
        if configdrive_file:
            utils.unlink_without_raise(configdrive_file)

    populate_image(image_path, root_part)

    if swap_part:
        mkfs(dev=swap_part, fs='swap', label='swap1')

    if ephemeral_part and not preserve_ephemeral:
        mkfs(dev=ephemeral_part, fs=ephemeral_format, label="ephemeral0")

    uuids_to_return = {
        'root uuid': root_part,
        'efi system partition uuid': part_dict.get('efi system partition')
    }

    try:
        for part, part_dev in six.iteritems(uuids_to_return):
            if part_dev:
                uuids_to_return[part] = block_uuid(part_dev)

    except processutils.ProcessExecutionError:
        with excutils.save_and_reraise_exception():
            LOG.error(_LE("Failed to detect %s"), part)

    return uuids_to_return
コード例 #11
0
ファイル: raid.py プロジェクト: Ahmedrazaidrisi/ironic
    def delete_configuration(self, task):
        """Delete the RAID configuration.

        :param task: a TaskManager instance  containing the node to act on.
        :raises: NodeCleaningFailure, on failure to execute clean step.
        :raises: InstanceDeployFailure, on failure to execute deploy step.
        """
        node = task.node
        LOG.debug("OOB RAID delete_configuration invoked for node %s.",
                  node.uuid)
        driver_internal_info = node.driver_internal_info
        ilo_object = ilo_common.get_ilo_object(node)

        try:
            # Raid configuration in progress, checking status
            if not driver_internal_info.get('ilo_raid_delete_in_progress'):
                ilo_object.delete_raid_configuration()
                self._prepare_for_read_raid(task, 'delete_raid')
                return deploy_utils.get_async_step_return_state(node)
            else:
                # Raid configuration is done, updating raid_config
                raid_conf = ilo_object.read_raid_configuration()
                fields = ['ilo_raid_delete_in_progress']
                if node.clean_step:
                    fields.append('skip_current_clean_step')
                else:
                    fields.append('skip_current_deploy_step')
                self._pop_driver_internal_values(task, *fields)
                if not len(raid_conf['logical_disks']):
                    node.raid_config = {}
                    LOG.debug("Node %(uuid)s raid delete clean step is done.",
                              {'uuid': node.uuid})
                else:
                    # Raid configuration failed
                    err_msg = (_("Step delete_configuration failed "
                                 "on node %(node)s with error: "
                                 "Unable to delete these logical disks: "
                                 "%(disks)s") % {
                                     'node': node.uuid,
                                     'disks': raid_conf['logical_disks']
                                 })
                    if node.clean_step:
                        raise exception.NodeCleaningFailure(err_msg)
                    else:
                        raise exception.InstanceDeployFailure(reason=err_msg)
        except ilo_error.IloLogicalDriveNotFoundError:
            LOG.info("No logical drive found to delete on node %(node)s",
                     {'node': node.uuid})
        except ilo_error.IloError as ilo_exception:
            operation = (_("Failed to delete raid configuration on node %s") %
                         node.uuid)
            self._pop_driver_internal_values(task,
                                             'ilo_raid_delete_in_progress',
                                             'skip_current_clean_step')
            fields = ['ilo_raid_delete_in_progress']
            if node.clean_step:
                fields.append('skip_current_clean_step')
            else:
                fields.append('skip_current_deploy_step')
            self._pop_driver_internal_values(task, *fields)
            self._set_step_failed(task, operation, ilo_exception)
コード例 #12
0
ファイル: raid.py プロジェクト: Ahmedrazaidrisi/ironic
    def create_configuration(self,
                             task,
                             create_root_volume=True,
                             create_nonroot_volumes=True):
        """Create a RAID configuration on a bare metal using agent ramdisk.

        This method creates a RAID configuration on the given node.

        :param task: a TaskManager instance.
        :param create_root_volume: If True, a root volume is created
            during RAID configuration. Otherwise, no root volume is
            created. Default is True.
        :param create_nonroot_volumes: If True, non-root volumes are
            created. If False, no non-root volumes are created. Default
            is True.
        :raises: MissingParameterValue, if node.target_raid_config is missing
            or was found to be empty after skipping root volume and/or non-root
            volumes.
        :raises: NodeCleaningFailure, on failure to execute clean step.
        :raises: InstanceDeployFailure, on failure to execute deploy step.
        """
        node = task.node
        target_raid_config = raid.filter_target_raid_config(
            node,
            create_root_volume=create_root_volume,
            create_nonroot_volumes=create_nonroot_volumes)
        driver_internal_info = node.driver_internal_info
        driver_internal_info['target_raid_config'] = target_raid_config
        node.driver_internal_info = driver_internal_info
        node.save()
        LOG.debug(
            "Calling OOB RAID create_configuration for node %(node)s "
            "with the following target RAID configuration: %(target)s", {
                'node': node.uuid,
                'target': target_raid_config
            })
        ilo_object = ilo_common.get_ilo_object(node)

        try:
            # Raid configuration in progress, checking status
            if not driver_internal_info.get('ilo_raid_create_in_progress'):
                ilo_object.create_raid_configuration(target_raid_config)
                self._prepare_for_read_raid(task, 'create_raid')
                return deploy_utils.get_async_step_return_state(node)
            else:
                # Raid configuration is done, updating raid_config
                raid_conf = (ilo_object.read_raid_configuration(
                    raid_config=target_raid_config))
                fields = ['ilo_raid_create_in_progress']
                if node.clean_step:
                    fields.append('skip_current_clean_step')
                else:
                    fields.append('skip_current_deploy_step')
                self._pop_driver_internal_values(task, *fields)
                if len(raid_conf['logical_disks']):
                    raid.update_raid_info(node, raid_conf)
                    LOG.debug("Node %(uuid)s raid create clean step is done.",
                              {'uuid': node.uuid})
                else:
                    # Raid configuration failed
                    msg = (_("Step create_configuration failed "
                             "on node %(node)s with error: "
                             "Unable to create raid") % {
                                 'node': node.uuid
                             })
                    if node.clean_step:
                        raise exception.NodeCleaningFailure(msg)
                    else:
                        raise exception.InstanceDeployFailure(reason=msg)
        except ilo_error.IloError as ilo_exception:
            operation = (_("Failed to create raid configuration on node %s") %
                         node.uuid)
            fields = ['ilo_raid_create_in_progress']
            if node.clean_step:
                fields.append('skip_current_clean_step')
            else:
                fields.append('skip_current_deploy_step')
            self._pop_driver_internal_values(task, *fields)
            self._set_step_failed(task, operation, ilo_exception)
コード例 #13
0
def do_agent_iscsi_deploy(task, agent_client):
    """Method invoked when deployed with the agent ramdisk.

    This method is invoked by drivers for doing iSCSI deploy
    using agent ramdisk.  This method assumes that the agent
    is booted up on the node and is heartbeating.

    :param task: a TaskManager object containing the node.
    :param agent_client: an instance of agent_client.AgentClient
        which will be used during iscsi deploy (for exposing node's
        target disk via iSCSI, for install boot loader, etc).
    :returns: a dictionary containing the following keys:
        For partition image:
            'root uuid': UUID of root partition
            'efi system partition uuid': UUID of the uefi system partition
                                         (if boot mode is uefi).
            NOTE: If key exists but value is None, it means partition doesn't
                  exist.
        For whole disk image:
            'disk identifier': ID of the disk to which image was deployed.
    :raises: InstanceDeployFailure, if it encounters some error
        during the deploy.
    """
    node = task.node
    iscsi_options = build_deploy_ramdisk_options(node)

    iqn = iscsi_options['iscsi_target_iqn']
    result = agent_client.start_iscsi_target(node, iqn)
    if result['command_status'] == 'FAILED':
        msg = (_("Failed to start the iSCSI target to deploy the "
                 "node %(node)s. Error: %(error)s") % {
                     'node': node.uuid,
                     'error': result['command_error']
                 })
        deploy_utils.set_failed_state(task, msg)
        raise exception.InstanceDeployFailure(reason=msg)

    address = parse.urlparse(node.driver_internal_info['agent_url'])
    address = address.hostname

    # TODO(lucasagomes): The 'error' and 'key' parameters in the
    # dictionary below are just being passed because it's needed for
    # the iscsi_deploy.continue_deploy() method, we are fooling it
    # for now. The agent driver doesn't use/need those. So we need to
    # refactor this bits here later.
    iscsi_params = {
        'error': result['command_error'],
        'iqn': iqn,
        'key': iscsi_options['deployment_key'],
        'address': address
    }

    uuid_dict_returned = continue_deploy(task, **iscsi_params)
    root_uuid_or_disk_id = uuid_dict_returned.get(
        'root uuid', uuid_dict_returned.get('disk identifier'))

    # TODO(lucasagomes): Move this bit saving the root_uuid to
    # iscsi_deploy.continue_deploy()
    driver_internal_info = node.driver_internal_info
    driver_internal_info['root_uuid_or_disk_id'] = root_uuid_or_disk_id
    node.driver_internal_info = driver_internal_info
    node.save()

    return uuid_dict_returned
コード例 #14
0
def work_on_disk(dev,
                 root_mb,
                 swap_mb,
                 ephemeral_mb,
                 ephemeral_format,
                 image_path,
                 node_uuid,
                 preserve_ephemeral=False):
    """Create partitions and copy an image to the root partition.

    :param dev: Path for the device to work on.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param image_path: Path for the instance's disk image.
    :param node_uuid: node's uuid. Used for logging.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).

    """
    if not is_block_device(dev):
        raise exception.InstanceDeployFailure(
            _("Parent device '%s' not found") % dev)

    # the only way for preserve_ephemeral to be set to true is if we are
    # rebuilding an instance with --preserve_ephemeral.
    commit = not preserve_ephemeral
    # now if we are committing the changes to disk clean first.
    if commit:
        destroy_disk_metadata(dev, node_uuid)
    part_dict = make_partitions(dev,
                                root_mb,
                                swap_mb,
                                ephemeral_mb,
                                commit=commit)

    ephemeral_part = part_dict.get('ephemeral')
    swap_part = part_dict.get('swap')
    root_part = part_dict.get('root')

    if not is_block_device(root_part):
        raise exception.InstanceDeployFailure(
            _("Root device '%s' not found") % root_part)
    if swap_part and not is_block_device(swap_part):
        raise exception.InstanceDeployFailure(
            _("Swap device '%s' not found") % swap_part)
    if ephemeral_part and not is_block_device(ephemeral_part):
        raise exception.InstanceDeployFailure(
            _("Ephemeral device '%s' not found") % ephemeral_part)

    dd(image_path, root_part)

    if swap_part:
        mkswap(swap_part)

    if ephemeral_part and not preserve_ephemeral:
        mkfs_ephemeral(ephemeral_part, ephemeral_format)

    try:
        root_uuid = block_uuid(root_part)
    except processutils.ProcessExecutionError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Failed to detect root device UUID."))
    return root_uuid
コード例 #15
0
ファイル: deployments.py プロジェクト: andornotlee/ironic
def do_node_deploy(task,
                   conductor_id=None,
                   configdrive=None,
                   deploy_steps=None):
    """Prepare the environment and deploy a node."""
    node = task.node
    utils.wipe_deploy_internal_info(task)
    try:
        if configdrive:
            if isinstance(configdrive, dict):
                configdrive = utils.build_configdrive(node, configdrive)
            _store_configdrive(node, configdrive)
    except (exception.SwiftOperationError, exception.ConfigInvalid) as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task,
                ('Error while uploading the configdrive for %(node)s '
                 'to Swift') % {'node': node.uuid},
                _('Failed to upload the configdrive to Swift. '
                  'Error: %s') % e,
                clean_up=False)
    except db_exception.DBDataError as e:
        with excutils.save_and_reraise_exception():
            # NOTE(hshiina): This error happens when the configdrive is
            #                too large. Remove the configdrive from the
            #                object to update DB successfully in handling
            #                the failure.
            node.obj_reset_changes()
            utils.deploying_error_handler(
                task,
                ('Error while storing the configdrive for %(node)s into '
                 'the database: %(err)s') % {
                     'node': node.uuid,
                     'err': e
                 },
                _("Failed to store the configdrive in the database. "
                  "%s") % e,
                clean_up=False)
    except Exception as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task,
                ('Unexpected error while preparing the configdrive for '
                 'node %(node)s') % {'node': node.uuid},
                _("Failed to prepare the configdrive. Exception: %s") % e,
                traceback=True,
                clean_up=False)

    try:
        task.driver.deploy.prepare(task)
    except exception.IronicException as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task, ('Error while preparing to deploy to node %(node)s: '
                       '%(err)s') % {
                           'node': node.uuid,
                           'err': e
                       },
                _("Failed to prepare to deploy: %s") % e,
                clean_up=False)
    except Exception as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task,
                ('Unexpected error while preparing to deploy to node '
                 '%(node)s') % {'node': node.uuid},
                _("Failed to prepare to deploy. Exception: %s") % e,
                traceback=True,
                clean_up=False)

    try:
        # If any deploy steps provided by user, save them to node. They will be
        # validated & processed later together with driver and deploy template
        # steps.
        if deploy_steps:
            info = node.driver_internal_info
            info['user_deploy_steps'] = deploy_steps
            node.driver_internal_info = info
            node.save()
        # This gets the deploy steps (if any) from driver, deploy template and
        # deploy_steps argument and updates them in the node's
        # driver_internal_info['deploy_steps']. In-band steps are skipped since
        # we know that an agent is not running yet.
        conductor_steps.set_node_deployment_steps(task, skip_missing=True)
    except exception.InstanceDeployFailure as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task,
                'Error while getting deploy steps; cannot deploy to node '
                '%(node)s. Error: %(err)s' % {
                    'node': node.uuid,
                    'err': e
                },
                _("Cannot get deploy steps; failed to deploy: %s") % e)

    if not node.driver_internal_info.get('deploy_steps'):
        msg = _('Error while getting deploy steps: no steps returned for '
                'node %s') % node.uuid
        utils.deploying_error_handler(
            task, msg, _("No deploy steps returned by the driver"))
        raise exception.InstanceDeployFailure(msg)

    if conductor_id is not None:
        # Update conductor_affinity to reference this conductor's ID
        # since there may be local persistent state
        node.conductor_affinity = conductor_id
        node.save()

    do_next_deploy_step(task, 0)
コード例 #16
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)
コード例 #17
0
ファイル: deploy_utils.py プロジェクト: Codixis/ironic
def _get_configdrive(configdrive, node_uuid):
    """Get the information about size and location of the configdrive.

    :param configdrive: Base64 encoded Gzipped configdrive content or
        configdrive HTTP URL.
    :param node_uuid: Node's uuid. Used for logging.
    :raises: InstanceDeployFailure if it can't download or decode the
       config drive.
    :returns: A tuple with the size in MiB and path to the uncompressed
        configdrive file.

    """
    # Check if the configdrive option is a HTTP URL or the content directly
    is_url = utils.is_http_url(configdrive)
    if is_url:
        try:
            data = requests.get(configdrive).content
        except requests.exceptions.RequestException as e:
            raise exception.InstanceDeployFailure(
                _("Can't download the configdrive content for node %(node)s "
                  "from '%(url)s'. Reason: %(reason)s") % {
                      'node': node_uuid,
                      'url': configdrive,
                      'reason': e
                  })
    else:
        data = configdrive

    try:
        data = six.BytesIO(base64.b64decode(data))
    except TypeError:
        error_msg = (_('Config drive for node %s is not base64 encoded '
                       'or the content is malformed.') % node_uuid)
        if is_url:
            error_msg += _(' Downloaded from "%s".') % configdrive
        raise exception.InstanceDeployFailure(error_msg)

    configdrive_file = tempfile.NamedTemporaryFile(delete=False,
                                                   prefix='configdrive',
                                                   dir=CONF.tempdir)
    configdrive_mb = 0
    with gzip.GzipFile('configdrive', 'rb', fileobj=data) as gunzipped:
        try:
            shutil.copyfileobj(gunzipped, configdrive_file)
        except EnvironmentError as e:
            # Delete the created file
            utils.unlink_without_raise(configdrive_file.name)
            raise exception.InstanceDeployFailure(
                _('Encountered error while decompressing and writing '
                  'config drive for node %(node)s. Error: %(exc)s') % {
                      'node': node_uuid,
                      'exc': e
                  })
        else:
            # Get the file size and convert to MiB
            configdrive_file.seek(0, os.SEEK_END)
            bytes_ = configdrive_file.tell()
            configdrive_mb = int(math.ceil(float(bytes_) / units.Mi))
        finally:
            configdrive_file.close()

        return (configdrive_mb, configdrive_file.name)
コード例 #18
0
 def _fail_deploy(task, msg):
     """Fail the deploy after logging and setting error states."""
     LOG.error(msg)
     deploy_utils.set_failed_state(task, msg)
     destroy_images(task.node.uuid)
     raise exception.InstanceDeployFailure(msg)
コード例 #19
0
ファイル: deploy_utils.py プロジェクト: Codixis/ironic
def deploy_partition_image(address,
                           port,
                           iqn,
                           lun,
                           image_path,
                           root_mb,
                           swap_mb,
                           ephemeral_mb,
                           ephemeral_format,
                           node_uuid,
                           preserve_ephemeral=False,
                           configdrive=None,
                           boot_option="netboot",
                           boot_mode="bios"):
    """All-in-one function to deploy a partition image to a node.

    :param address: The iSCSI IP address.
    :param port: The iSCSI port number.
    :param iqn: The iSCSI qualified name.
    :param lun: The iSCSI logical unit number.
    :param image_path: Path for the instance's disk image.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param node_uuid: node's uuid. Used for logging.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).
    :param configdrive: Optional. Base64 encoded Gzipped configdrive content
                        or configdrive HTTP URL.
    :param boot_option: Can be "local" or "netboot". "netboot" by default.
    :param boot_mode: Can be "bios" or "uefi". "bios" by default.
    :raises: InstanceDeployFailure if image virtual size is bigger than root
        partition size.
    :returns: a dictionary containing the following keys:
        'root uuid': UUID of root partition
        'efi system partition uuid': UUID of the uefi system partition
                                     (if boot mode is uefi).
        NOTE: If key exists but value is None, it means partition doesn't
              exist.
    """
    image_mb = get_image_mb(image_path)
    if image_mb > root_mb:
        msg = (_('Root partition is too small for requested image. Image '
                 'virtual size: %(image_mb)d MB, Root size: %(root_mb)d MB') %
               {
                   'image_mb': image_mb,
                   'root_mb': root_mb
               })
        raise exception.InstanceDeployFailure(msg)

    with _iscsi_setup_and_handle_errors(address, port, iqn, lun) as dev:
        uuid_dict_returned = work_on_disk(
            dev,
            root_mb,
            swap_mb,
            ephemeral_mb,
            ephemeral_format,
            image_path,
            node_uuid,
            preserve_ephemeral=preserve_ephemeral,
            configdrive=configdrive,
            boot_option=boot_option,
            boot_mode=boot_mode)

    return uuid_dict_returned
コード例 #20
0
ファイル: deploy_utils.py プロジェクト: jmcabandara/ironic
def work_on_disk(dev,
                 root_mb,
                 swap_mb,
                 ephemeral_mb,
                 ephemeral_format,
                 image_path,
                 node_uuid,
                 preserve_ephemeral=False,
                 configdrive=None):
    """Create partitions and copy an image to the root partition.

    :param dev: Path for the device to work on.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param image_path: Path for the instance's disk image.
    :param node_uuid: node's uuid. Used for logging.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).
    :param configdrive: Optional. Base64 encoded Gzipped configdrive content
                        or configdrive HTTP URL.
    :returns: the UUID of the root partition.
    """
    if not is_block_device(dev):
        raise exception.InstanceDeployFailure(
            _("Parent device '%s' not found") % dev)

    # the only way for preserve_ephemeral to be set to true is if we are
    # rebuilding an instance with --preserve_ephemeral.
    commit = not preserve_ephemeral
    # now if we are committing the changes to disk clean first.
    if commit:
        destroy_disk_metadata(dev, node_uuid)

    try:
        # If requested, get the configdrive file and determine the size
        # of the configdrive partition
        configdrive_mb = 0
        configdrive_file = None
        if configdrive:
            configdrive_mb, configdrive_file = _get_configdrive(
                configdrive, node_uuid)

        part_dict = make_partitions(dev,
                                    root_mb,
                                    swap_mb,
                                    ephemeral_mb,
                                    configdrive_mb,
                                    commit=commit)

        ephemeral_part = part_dict.get('ephemeral')
        swap_part = part_dict.get('swap')
        configdrive_part = part_dict.get('configdrive')
        root_part = part_dict.get('root')

        if not is_block_device(root_part):
            raise exception.InstanceDeployFailure(
                _("Root device '%s' not found") % root_part)

        for part in ('swap', 'ephemeral', 'configdrive'):
            part_device = part_dict.get(part)
            if part_device and not is_block_device(part_device):
                raise exception.InstanceDeployFailure(
                    _("'%(partition)s' device '%(part_device)s' not found") % {
                        'partition': part,
                        'part_device': part_device
                    })

        if configdrive_part:
            # Copy the configdrive content to the configdrive partition
            dd(configdrive_file, configdrive_part)

    finally:
        # If the configdrive was requested make sure we delete the file
        # after copying the content to the partition
        if configdrive_file:
            utils.unlink_without_raise(configdrive_file)

    populate_image(image_path, root_part)

    if swap_part:
        mkswap(swap_part)

    if ephemeral_part and not preserve_ephemeral:
        mkfs_ephemeral(ephemeral_part, ephemeral_format)

    try:
        root_uuid = block_uuid(root_part)
    except processutils.ProcessExecutionError:
        with excutils.save_and_reraise_exception():
            LOG.error(_LE("Failed to detect root device UUID."))

    return root_uuid
コード例 #21
0
ファイル: test_pxe.py プロジェクト: nkaul/ironic
 def fake_deploy(**kwargs):
     raise exception.InstanceDeployFailure("test deploy error")
コード例 #22
0
def do_node_deploy(task, conductor_id=None, configdrive=None):
    """Prepare the environment and deploy a node."""
    node = task.node
    utils.del_secret_token(node)
    try:
        if configdrive:
            if isinstance(configdrive, dict):
                configdrive = utils.build_configdrive(node, configdrive)
            _store_configdrive(node, configdrive)
    except (exception.SwiftOperationError, exception.ConfigInvalid) as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task,
                ('Error while uploading the configdrive for %(node)s '
                 'to Swift') % {'node': node.uuid},
                _('Failed to upload the configdrive to Swift. '
                  'Error: %s') % e,
                clean_up=False)
    except db_exception.DBDataError as e:
        with excutils.save_and_reraise_exception():
            # NOTE(hshiina): This error happens when the configdrive is
            #                too large. Remove the configdrive from the
            #                object to update DB successfully in handling
            #                the failure.
            node.obj_reset_changes()
            utils.deploying_error_handler(
                task,
                ('Error while storing the configdrive for %(node)s into '
                 'the database: %(err)s') % {
                     'node': node.uuid,
                     'err': e
                 },
                _("Failed to store the configdrive in the database. "
                  "%s") % e,
                clean_up=False)
    except Exception as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task,
                ('Unexpected error while preparing the configdrive for '
                 'node %(node)s') % {'node': node.uuid},
                _("Failed to prepare the configdrive. Exception: %s") % e,
                traceback=True,
                clean_up=False)

    try:
        task.driver.deploy.prepare(task)
    except exception.IronicException as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task, ('Error while preparing to deploy to node %(node)s: '
                       '%(err)s') % {
                           'node': node.uuid,
                           'err': e
                       },
                _("Failed to prepare to deploy: %s") % e,
                clean_up=False)
    except Exception as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task,
                ('Unexpected error while preparing to deploy to node '
                 '%(node)s') % {'node': node.uuid},
                _("Failed to prepare to deploy. Exception: %s") % e,
                traceback=True,
                clean_up=False)

    try:
        # This gets the deploy steps and puts them in the node's
        # driver_internal_info['deploy_steps'].
        conductor_steps.set_node_deployment_steps(task)
    except exception.InstanceDeployFailure as e:
        with excutils.save_and_reraise_exception():
            utils.deploying_error_handler(
                task,
                'Error while getting deploy steps; cannot deploy to node '
                '%(node)s. Error: %(err)s' % {
                    'node': node.uuid,
                    'err': e
                },
                _("Cannot get deploy steps; failed to deploy: %s") % e)

    if not node.driver_internal_info.get('deploy_steps'):
        msg = _('Error while getting deploy steps: no steps returned for '
                'node %s') % node.uuid
        utils.deploying_error_handler(
            task, msg, _("No deploy steps returned by the driver"))
        raise exception.InstanceDeployFailure(msg)

    do_next_deploy_step(task, 0, conductor_id)