Exemplo n.º 1
0
    def apply_configuration(self, task, settings):
        """Apply the BIOS settings to the node.

        :param task: a TaskManager instance containing the node to act on.
        :param settings: a list of BIOS settings to be updated.
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """

        system = redfish_utils.get_system(task.node)
        try:
            bios = system.bios
        except sushy.exceptions.MissingAttributeError:
            error_msg = (_('Redfish BIOS factory reset failed for node '
                           '%s, because BIOS settings are not supported.') %
                         task.node.uuid)
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)

        # Convert Ironic BIOS settings to Redfish BIOS attributes
        attributes = {s['name']: s['value'] for s in settings}

        info = task.node.driver_internal_info
        reboot_requested = info.get('post_config_reboot_requested')

        if not reboot_requested:
            # Step 1: Apply settings and issue a reboot
            LOG.debug('Apply BIOS configuration for node %(node_uuid)s: '
                      '%(settings)r', {'node_uuid': task.node.uuid,
                                       'settings': settings})

            if bios.supported_apply_times and (
                    sushy.APPLY_TIME_ON_RESET in bios.supported_apply_times):
                apply_time = sushy.APPLY_TIME_ON_RESET
            else:
                apply_time = None

            try:
                bios.set_attributes(attributes, apply_time=apply_time)
            except sushy.exceptions.SushyError as e:
                error_msg = (_('Redfish BIOS apply configuration failed for '
                               'node %(node)s. Error: %(error)s') %
                             {'node': task.node.uuid, 'error': e})
                LOG.error(error_msg)
                raise exception.RedfishError(error=error_msg)

            self.post_configuration(task, settings)
            self._set_reboot_requested(task, attributes)
            return deploy_utils.get_async_step_return_state(task.node)
        else:
            # Step 2: Verify requested BIOS settings applied
            requested_attrs = info.get('requested_bios_attrs')
            current_attrs = bios.attributes
            LOG.debug('Verify BIOS configuration for node %(node_uuid)s: '
                      '%(attrs)r', {'node_uuid': task.node.uuid,
                                    'attrs': requested_attrs})
            self._clear_reboot_requested(task)
            self._check_bios_attrs(task, current_attrs, requested_attrs)
Exemplo n.º 2
0
    def set_secure_boot_state(self, task, state):
        """Set the current secure boot state for the node.

        :param task: A task from TaskManager.
        :param state: A new state as a boolean.
        :raises: MissingParameterValue if a required parameter is missing
        :raises: RedfishError or its derivative in case of a driver
            runtime error.
        :raises: UnsupportedDriverExtension if secure boot is
                 not supported by the hardware.
        """
        system = redfish_utils.get_system(task.node)
        try:
            sb = system.secure_boot
        except sushy.exceptions.MissingAttributeError:
            LOG.error(
                'Secure boot has been requested for node %s but its '
                'Redfish BMC does not have a SecureBoot object',
                task.node.uuid)
            raise exception.UnsupportedDriverExtension(
                driver=task.node.driver, extension='set_secure_boot_state')

        if sb.enabled == state:
            LOG.info(
                'Secure boot state for node %(node)s is already '
                '%(value)s', {
                    'node': task.node.uuid,
                    'value': state
                })
            return

        boot_mode = system.boot.get('mode')
        if boot_mode == sushy.BOOT_SOURCE_MODE_BIOS:
            # NOTE(dtantsur): the case of disabling secure boot when boot mode
            # is legacy should be covered by the check above.
            msg = (_("Configuring secure boot requires UEFI for node %s") %
                   task.node.uuid)
            LOG.error(msg)
            raise exception.RedfishError(error=msg)

        try:
            sb.set_enabled(state)
        except sushy.exceptions.SushyError as exc:
            msg = (_('Failed to set secure boot state on node %(node)s to '
                     '%(value)s: %(exc)s') % {
                         'node': task.node.uuid,
                         'value': state,
                         'exc': exc
                     })
            LOG.error(msg)
            raise exception.RedfishError(error=msg)
        else:
            LOG.info(
                'Secure boot state for node %(node)s has been set to '
                '%(value)s', {
                    'node': task.node.uuid,
                    'value': state
                })
Exemplo n.º 3
0
    def clear_job_queue(self, task):
        """Clear iDRAC job queue.

        :param task: a TaskManager instance containing the node to act
                     on.
        :raises: RedfishError on an error.
        """
        system = redfish_utils.get_system(task.node)
        for manager in system.managers:
            try:
                oem_manager = manager.get_oem_extension('Dell')
            except sushy.exceptions.OEMExtensionNotFoundError as e:
                error_msg = (_("Search for Sushy OEM extension Python package "
                               "'sushy-oem-idrac' failed for node %(node)s. "
                               "Ensure it is installed. Error: %(error)s") % {
                                   'node': task.node.uuid,
                                   'error': e
                               })
                LOG.error(error_msg)
                raise exception.RedfishError(error=error_msg)
            try:
                oem_manager.job_service.delete_jobs(job_ids=['JID_CLEARALL'])
            except sushy.exceptions.SushyError as e:
                error_msg = (
                    'Failed to clear iDRAC job queue with system '
                    '%(system)s manager %(manager)s for node '
                    '%(node)s. Will try next manager, if available. '
                    'Error: %(error)s' % {
                        'system':
                        system.uuid if system.uuid else system.identity,
                        'manager':
                        manager.uuid if manager.uuid else manager.identity,
                        'node': task.node.uuid,
                        'error': e
                    })
                LOG.debug(error_msg)
                continue
            LOG.info('Cleared iDRAC job queue for node %(node)s',
                     {'node': task.node.uuid})
            break
        else:
            error_msg = (
                _('iDRAC Redfish clear job queue failed for node '
                  '%(node)s, because system %(system)s has no '
                  'manager%(no_manager)s.') %
                {
                    'node': task.node.uuid,
                    'system': system.uuid if system.uuid else system.identity,
                    'no_manager': '' if not system.managers else ' which could'
                })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 4
0
def create_virtual_disk(task, raid_controller, physical_disks, raid_level,
                        size_bytes, disk_name=None, span_length=None,
                        span_depth=None, error_handler=None):
    """Create a single virtual disk on a RAID controller.

    :param task: TaskManager object containing the node.
    :param raid_controller: id of the RAID controller.
    :param physical_disks: ids of the physical disks.
    :param raid_level: RAID level of the virtual disk.
    :param size_bytes: size of the virtual disk.
    :param disk_name: name of the virtual disk. (optional)
    :param span_depth: Number of spans in virtual disk. (optional)
    :param span_length: Number of disks per span. (optional)
    :param error_handler: function to call if volume create fails. (optional)
    :returns: Newly created Volume resource or TaskMonitor if async task.
    :raises: RedfishConnectionError when it fails to connect to Redfish.
    :raises: RedfishError if there is an error creating the virtual disk.
    """
    node = task.node
    system = redfish_utils.get_system(node)
    storage = _get_storage_controller(node, system, physical_disks)
    if not storage:
        reason = _('No storage controller found for node %(node_uuid)s' %
                   {'node_uuid': node.uuid})
        raise exception.RedfishError(error=reason)
    volume_collection = storage.volumes

    apply_time = None
    apply_time_support = volume_collection.operation_apply_time_support
    if apply_time_support and apply_time_support.mapped_supported_values:
        supported_values = apply_time_support.mapped_supported_values
        if sushy.APPLY_TIME_IMMEDIATE in supported_values:
            apply_time = sushy.APPLY_TIME_IMMEDIATE
        elif sushy.APPLY_TIME_ON_RESET in supported_values:
            apply_time = sushy.APPLY_TIME_ON_RESET
    payload = _construct_volume_payload(
        node, storage, raid_controller, physical_disks, raid_level, size_bytes,
        disk_name=disk_name, span_length=span_length, span_depth=span_depth)

    try:
        return volume_collection.create(payload, apply_time=apply_time)
    except sushy.exceptions.SushyError as exc:
        msg = ('Redfish driver failed to create virtual disk for node '
               '%(node_uuid)s. Reason: %(error)s.')
        if error_handler:
            try:
                return error_handler(task, exc, volume_collection, payload)
            except sushy.exceptions.SushyError as exc:
                LOG.error(msg, {'node_uuid': node.uuid, 'error': exc})
                raise exception.RedfishError(error=exc)
        LOG.error(msg, {'node_uuid': node.uuid, 'error': exc})
        raise exception.RedfishError(error=exc)
Exemplo n.º 5
0
    def reset_idrac(self, task):
        """Reset the iDRAC.

        :param task: a TaskManager instance containing the node to act
                     on.
        :raises: RedfishError on an error.
        """
        system = redfish_utils.get_system(task.node)
        for manager in system.managers:
            try:
                oem_manager = manager.get_oem_extension('Dell')
            except sushy.exceptions.OEMExtensionNotFoundError as e:
                error_msg = (_("Search for Sushy OEM extension Python package "
                               "'sushy-oem-idrac' failed for node %(node)s. "
                               "Ensure it is installed. Error: %(error)s") % {
                                   'node': task.node.uuid,
                                   'error': e
                               })
                LOG.error(error_msg)
                raise exception.RedfishError(error=error_msg)
            try:
                oem_manager.reset_idrac()
            except sushy.exceptions.SushyError as e:
                error_msg = (
                    'Failed to reset iDRAC with system %(system)s '
                    'manager %(manager)s for node %(node)s. Will try '
                    'next manager, if available. Error: %(error)s' % {
                        'system':
                        system.uuid if system.uuid else system.identity,
                        'manager':
                        manager.uuid if manager.uuid else manager.identity,
                        'node': task.node.uuid,
                        'error': e
                    })
                LOG.debug(error_msg)
                continue
            redfish_utils.wait_until_get_system_ready(task.node)
            LOG.info('Reset iDRAC for node %(node)s', {'node': task.node.uuid})
            break
        else:
            error_msg = (
                _('iDRAC Redfish reset iDRAC failed for node '
                  '%(node)s, because system %(system)s has no '
                  'manager%(no_manager)s.') %
                {
                    'node': task.node.uuid,
                    'system': system.uuid if system.uuid else system.identity,
                    'no_manager': '' if not system.managers else ' which could'
                })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 6
0
    def set_boot_mode(self, task, mode):
        """Set the boot mode for a node.

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

        :param task: A task from TaskManager.
        :param mode: The boot mode, one of
                     :mod:`ironic.common.boot_modes`.
        :raises: InvalidParameterValue if an invalid boot mode is
                 specified.
        :raises: MissingParameterValue if a required parameter is missing
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)

        boot_device = system.boot.get('target')
        if not boot_device:
            error_msg = (_('Cannot change boot mode on node %(node)s '
                           'because its boot device is not set.') % {
                               'node': task.node.uuid
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error_msg)

        boot_override = system.boot.get('enabled')
        if not boot_override:
            error_msg = (_('Cannot change boot mode on node %(node)s '
                           'because its boot source override is not set.') % {
                               'node': task.node.uuid
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error_msg)

        try:
            system.set_system_boot_source(boot_device,
                                          enabled=boot_override,
                                          mode=BOOT_MODE_MAP_REV[mode])

        except sushy.exceptions.SushyError as e:
            error_msg = (_('Setting boot mode to %(mode)s '
                           'failed for node %(node)s. '
                           'Error: %(error)s') % {
                               'node': task.node.uuid,
                               'mode': mode,
                               'error': e
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 7
0
def _max_volume_size_bytes(raid_level,
                           physical_disks,
                           free_space_bytes,
                           spans_count=1,
                           stripe_size_kb=64 * units.Ki):
    # restrict the size to the smallest available space
    free_spaces = [free_space_bytes[disk] for disk in physical_disks]
    size_kb = min(free_spaces) // units.Ki

    # NOTE(ifarkas): using math.floor so we get a volume size that does not
    #                exceed the available space
    stripes_per_disk = int(math.floor(float(size_kb) / stripe_size_kb))

    disks_count = len(physical_disks)
    overhead_disks_count = _raid_level_overhead(raid_level, spans_count)
    if disks_count <= overhead_disks_count:
        reason = _('The number of physical drives (%(drives)s) is too few for '
                   'the required number of overhead drives (%(overhead)s)' % {
                       'drives': disks_count,
                       'overhead': overhead_disks_count
                   })
        raise exception.RedfishError(error=reason)

    max_volume_size_bytes = int(stripes_per_disk * stripe_size_kb *
                                (disks_count - overhead_disks_count) *
                                units.Ki)
    return max_volume_size_bytes
Exemplo n.º 8
0
    def set_power_state(self, task, power_state, timeout=None):
        """Set the power state of the task's node.

        :param task: a TaskManager instance containing the node to act on.
        :param power_state: Any power state from :mod:`ironic.common.states`.
        :param timeout: Time to wait for the node to reach the requested state.
        :raises: MissingParameterValue if a required parameter is missing.
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)

        if (power_state in (states.POWER_ON, states.SOFT_REBOOT, states.REBOOT)
                and isinstance(task.driver.management,
                               redfish_mgmt.RedfishManagement)):
            task.driver.management.restore_boot_device(task, system)

        try:
            _set_power_state(task, system, power_state, timeout=timeout)
        except sushy.exceptions.SushyError as e:
            error_msg = (_('Setting power state to %(state)s failed for node '
                           '%(node)s. Error: %(error)s') % {
                               'node': task.node.uuid,
                               'state': power_state,
                               'error': e
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 9
0
def get_physical_disks(node):
    """Get the physical drives of the node.

    :param node: an ironic node object.
    :returns: a list of Drive objects from sushy
    :raises: RedfishConnectionError when it fails to connect to Redfish
    :raises: RedfishError if there is an error getting the drives via Redfish
    """
    system = redfish_utils.get_system(node)

    disks = []
    disk_to_controller = {}
    try:
        collection = system.storage
        for storage in collection.get_members():
            disks.extend(storage.drives)
            controller = (storage.storage_controllers[0]
                          if storage.storage_controllers else None)
            for drive in storage.drives:
                disk_to_controller[drive] = controller
    except sushy.exceptions.SushyError as exc:
        error_msg = _('Cannot get the list of physical disks for node '
                      '%(node_uuid)s. Reason: %(error)s.' %
                      {'node_uuid': node.uuid, 'error': exc})
        LOG.error(error_msg)
        raise exception.RedfishError(error=exc)
    return disks, disk_to_controller
Exemplo n.º 10
0
    def set_power_state(self, task, power_state, timeout=None):
        """Set the power state of the task's node.

        :param task: a TaskManager instance containing the node to act on.
        :param power_state: Any power state from :mod:`ironic.common.states`.
        :param timeout: Time to wait for the node to reach the requested state.
        :raises: MissingParameterValue if a required parameter is missing.
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)
        try:
            system.reset_system(SET_POWER_STATE_MAP.get(power_state))
        except sushy.exceptions.SushyError as e:
            error_msg = (_('Redfish set power state failed for node '
                           '%(node)s. Error: %(error)s') % {
                               'node': task.node.uuid,
                               'error': e
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)

        target_state = TARGET_STATE_MAP.get(power_state, power_state)
        cond_utils.node_wait_for_power_state(task,
                                             target_state,
                                             timeout=timeout)
Exemplo n.º 11
0
def _raid_level_overhead(raid_level, spans_count=1):
    """Calculate the drive overhead for the given RAID level

    Drive overhead is the number of additional drives required to hold the
    the redundant data needed for mirrored volumes and the parity checksums
    for volumes with parity.

    :param raid_level: RAID level of the virtual disk
    :param spans_count: number of spans for the virtual disk
    :return: the number of drives of overhead
    :raises: RedfishError if RAID level is not supported
    """
    try:
        raid_level_info = RAID_LEVELS[raid_level]
    except KeyError:
        _raise_raid_level_not_supported(raid_level)

    if raid_level_info['type'] == 'spanned':
        if spans_count <= 1:
            reason = _('Spanned RAID volumes cannot contain a single span')
            raise exception.RedfishError(error=reason)

        span_type = raid_level_info['span_type']
        raid_level_info = RAID_LEVELS[span_type]

    return raid_level_info['overhead'] * spans_count
Exemplo n.º 12
0
    def set_boot_device(self, task, device, persistent=False):
        """Set the boot device for a node.

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

        :param task: a task from TaskManager.
        :param device: the boot device, one of
                       :mod:`ironic.common.boot_devices`.
        :param persistent: Boolean value. True if the boot device will
                           persist to all future boots, False if not.
                           Default: False.
        :raises: InvalidParameterValue on malformed parameter(s)
        :raises: MissingParameterValue on missing parameter(s)
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)

        try:
            system.set_system_boot_source(
                BOOT_DEVICE_MAP_REV[device],
                enabled=BOOT_DEVICE_PERSISTENT_MAP_REV[persistent])
        except sushy.exceptions.SushyError as e:
            error_msg = (_('Redfish set boot device failed for node '
                           '%(node)s. Error: %(error)s') % {
                               'node': task.node.uuid,
                               'error': e
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 13
0
 def _get_system():
     try:
         # TODO(lucasagomes): We should look into a mechanism to
         # cache the connections (and maybe even system's instances)
         # to avoid unnecessary requests to the Redfish controller
         conn = sushy.Sushy(address,
                            username=driver_info['username'],
                            password=driver_info['password'],
                            verify=driver_info['verify_ca'])
         return conn.get_system(system_id)
     except sushy.exceptions.ResourceNotFoundError as e:
         LOG.error(
             'The Redfish System "%(system)s" was not found for '
             'node %(node)s. Error %(error)s', {
                 'system': system_id,
                 'node': node.uuid,
                 'error': e
             })
         raise exception.RedfishError(error=e)
     # TODO(lucasagomes): We should look at other types of
     # ConnectionError such as AuthenticationError or SSLError and stop
     # retrying on them
     except sushy.exceptions.ConnectionError as e:
         LOG.warning(
             'For node %(node)s, got a connection error from '
             'Redfish at address "%(address)s" when fetching '
             'System "%(system)s". Error: %(error)s', {
                 'system': system_id,
                 'address': address,
                 'node': node.uuid,
                 'error': e
             })
         raise exception.RedfishConnectionError(node=node.uuid, error=e)
Exemplo n.º 14
0
    def _get_system():
        try:
            with SessionCache(driver_info) as conn:
                return conn.get_system(system_id)

        except sushy.exceptions.ResourceNotFoundError as e:
            LOG.error(
                'The Redfish System "%(system)s" was not found for '
                'node %(node)s. Error %(error)s', {
                    'system': system_id or '<default>',
                    'node': node.uuid,
                    'error': e
                })
            raise exception.RedfishError(error=e)
        # TODO(lucasagomes): We should look at other types of
        # ConnectionError such as AuthenticationError or SSLError and stop
        # retrying on them
        except sushy.exceptions.ConnectionError as e:
            LOG.warning(
                'For node %(node)s, got a connection error from '
                'Redfish at address "%(address)s" using auth type '
                '"%(auth_type)s" when fetching System "%(system)s". '
                'Error: %(error)s', {
                    'system': system_id or '<default>',
                    'address': driver_info['address'],
                    'auth_type': driver_info['auth_type'],
                    'node': node.uuid,
                    'error': e
                })
            raise exception.RedfishConnectionError(node=node.uuid, error=e)
Exemplo n.º 15
0
    def reboot(self, task, timeout=None):
        """Perform a hard reboot of the task's node.

        :param task: a TaskManager instance containing the node to act on.
        :param timeout: Time to wait for the node to become powered on.
        :raises: MissingParameterValue if a required parameter is missing.
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)
        current_power_state = GET_POWER_STATE_MAP.get(system.power_state)

        try:
            if current_power_state == states.POWER_ON:
                next_state = states.POWER_OFF
                _set_power_state(task, system, next_state, timeout=timeout)

            next_state = states.POWER_ON
            _set_power_state(task, system, next_state, timeout=timeout)
        except sushy.exceptions.SushyError as e:
            error_msg = (_('Reboot failed for node %(node)s when setting '
                           'power state to %(state)s. Error: %(error)s') % {
                               'node': task.node.uuid,
                               'state': next_state,
                               'error': e
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 16
0
    def factory_reset(self, task):
        """Reset the BIOS settings of the node to the factory default.

        :param task: a TaskManager instance containing the node to act on.
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)
        try:
            bios = system.bios
        except sushy.exceptions.MissingAttributeError:
            error_msg = (_('Redfish BIOS factory reset failed for node '
                           '%s, because BIOS settings are not supported.') %
                         task.node.uuid)
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)

        node = task.node
        info = node.driver_internal_info
        reboot_requested = info.get('post_factory_reset_reboot_requested')
        if not reboot_requested:
            LOG.debug('Factory reset BIOS configuration for node %(node)s',
                      {'node': node.uuid})
            try:
                bios.reset_bios()
            except sushy.exceptions.SushyError as e:
                error_msg = (_('Redfish BIOS factory reset failed for node '
                               '%(node)s. Error: %(error)s') % {
                                   'node': node.uuid,
                                   'error': e
                               })
                LOG.error(error_msg)
                raise exception.RedfishError(error=error_msg)

            self.post_reset(task)
            self._set_reboot(task)
            return deploy_utils.get_async_step_return_state(task.node)
        else:
            current_attrs = bios.attributes
            LOG.debug(
                'Post factory reset, BIOS configuration for node '
                '%(node_uuid)s: %(attrs)r', {
                    'node_uuid': node.uuid,
                    'attrs': current_attrs
                })
            self._clear_reboot_requested(task)
Exemplo n.º 17
0
    def set_indicator_state(self, task, component, indicator, state):
        """Set indicator on the hardware component to the desired state.

        :param task: A task from TaskManager.
        :param component: The hardware component, one of
            :mod:`ironic.common.components`.
        :param indicator: Indicator ID (as reported by
            `get_supported_indicators`).
        :param state: Desired state of the indicator, one of
            :mod:`ironic.common.indicator_states`.
        :raises: InvalidParameterValue if an invalid component, indicator
                 or state is specified.
        :raises: MissingParameterValue if a required parameter is missing
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)

        try:
            if (component == components.SYSTEM
                    and indicator == system.uuid):
                system.set_indicator_led(INDICATOR_MAP_REV[state])
                return

            elif (component == components.CHASSIS
                    and system.chassis):
                for chassis in system.chassis:
                    if chassis.uuid == indicator:
                        chassis.set_indicator_led(
                            INDICATOR_MAP_REV[state])
                        return

            elif (component == components.DISK
                  and system.simple_storage
                  and system.simple_storage.drives):
                for drive in system.simple_storage.drives:
                    if drive.uuid == indicator:
                        drive.set_indicator_led(
                            INDICATOR_MAP_REV[state])
                        return

        except sushy.exceptions.SushyError as e:
            error_msg = (_('Redfish set %(component)s indicator %(indicator)s '
                           'state %(state)s failed for node %(node)s. Error: '
                           '%(error)s') % {'component': component,
                                           'indicator': indicator,
                                           'state': state,
                                           'node': task.node.uuid,
                                           'error': e})
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)

        raise exception.MissingParameterValue(_(
            "Unknown indicator %(indicator)s for component %(component)s of "
            "node %(uuid)s") % {'indicator': indicator,
                                'component': component,
                                'uuid': task.node.uuid})
Exemplo n.º 18
0
def _raise_raid_level_not_supported(raid_level):
    """Helper function for the 'RAID level is not supported' error

    :param raid_level: RAID level of the virtual disk
    :raises: exception.RedfishError
    """
    reason = (_('RAID level %(raid_level)s is not supported by the '
                'driver. Supported RAID levels: %(supported_raid_levels)s')
              % {'raid_level': raid_level,
                 'supported_raid_levels': ', '.join(RAID_LEVELS)})
    raise exception.RedfishError(error=reason)
Exemplo n.º 19
0
    def get_indicator_state(self, task, component, indicator):
        """Get current state of the indicator of the hardware component.

        :param task: A task from TaskManager.
        :param component: The hardware component, one of
            :mod:`ironic.common.components`.
        :param indicator: Indicator ID (as reported by
            `get_supported_indicators`).
        :raises: MissingParameterValue if a required parameter is missing
        :raises: RedfishError on an error from the Sushy library
        :returns: Current state of the indicator, one of
            :mod:`ironic.common.indicator_states`.
        """
        system = redfish_utils.get_system(task.node)

        try:
            if (component == components.SYSTEM and indicator == system.uuid):
                return INDICATOR_MAP[system.indicator_led]

            if (component == components.CHASSIS and system.chassis):
                for chassis in system.chassis:
                    if chassis.uuid == indicator:
                        return INDICATOR_MAP[chassis.indicator_led]

            if (component == components.DISK and system.simple_storage
                    and system.simple_storage.drives):
                for drive in system.simple_storage.drives:
                    if drive.uuid == indicator:
                        return INDICATOR_MAP[drive.indicator_led]

        except sushy.exceptions.SushyError as e:
            error_msg = (_('Redfish get %(component)s indicator %(indicator)s '
                           'state failed for node %(node)s. Error: '
                           '%(error)s') % {
                               'component': component,
                               'indicator': indicator,
                               'node': task.node.uuid,
                               'error': e
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)

        raise exception.MissingParameterValue(
            _("Unknown indicator %(indicator)s for component %(component)s of "
              "node %(uuid)s") % {
                  'indicator': indicator,
                  'component': component,
                  'uuid': task.node.uuid
              })
Exemplo n.º 20
0
def get_update_service(node):
    """Get a node's update service.

    :param node: an Ironic node object
    :raises: RedfishConnectionError when it fails to connect to Redfish
    :raises: RedfishError when the UpdateService is not registered in Redfish
    """

    try:
        return _get_connection(node, lambda conn: conn.get_update_service())
    except sushy.exceptions.MissingAttributeError as e:
        LOG.error('The Redfish UpdateService was not found for '
                  'node %(node)s. Error %(error)s',
                  {'node': node.uuid, 'error': e})
        raise exception.RedfishError(error=e)
Exemplo n.º 21
0
def _raid_level_max_disks(raid_level, spans_count=1):
    try:
        raid_level_info = RAID_LEVELS[raid_level]
    except KeyError:
        _raise_raid_level_not_supported(raid_level)

    if raid_level_info['type'] == 'spanned':
        if spans_count <= 1:
            reason = _('Spanned RAID volumes cannot contain a single span')
            raise exception.RedfishError(error=reason)

        span_type = raid_level_info['span_type']
        raid_level_info = RAID_LEVELS[span_type]

    return raid_level_info['max_disks'] * spans_count
Exemplo n.º 22
0
def get_task_monitor(node, uri):
    """Get a TaskMonitor for a node.

    :param node: an Ironic node object
    :param uri: the URI of a TaskMonitor
    :raises: RedfishConnectionError when it fails to connect to Redfish
    :raises: RedfishError when the TaskMonitor is not available in Redfish
    """

    try:
        return _get_connection(node, lambda conn: conn.get_task_monitor(uri))
    except sushy.exceptions.ResourceNotFoundError as e:
        LOG.error('The Redfish TaskMonitor "%(uri)s" was not found for '
                  'node %(node)s. Error %(error)s',
                  {'uri': uri, 'node': node.uuid, 'error': e})
        raise exception.RedfishError(error=e)
Exemplo n.º 23
0
def _calculate_spans(raid_level, disks_count):
    """Calculates number of spans for a RAID level given a physical disk count

    :param raid_level: RAID level of the virtual disk.
    :param disks_count: number of physical disks used for the virtual disk.
    :returns: number of spans.
    """
    if raid_level in ['0', '1', '5', '6']:
        return 1
    elif raid_level in ['5+0', '6+0']:
        return 2
    elif raid_level in ['1+0']:
        return disks_count >> 1
    else:
        reason = (_('Cannot calculate spans for RAID level "%s"') % raid_level)
        raise exception.RedfishError(error=reason)
Exemplo n.º 24
0
    def set_boot_mode(self, task, mode):
        """Set the boot mode for a node.

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

        :param task: A task from TaskManager.
        :param mode: The boot mode, one of
                     :mod:`ironic.common.boot_modes`.
        :raises: InvalidParameterValue if an invalid boot mode is
                 specified.
        :raises: MissingParameterValue if a required parameter is missing
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)

        try:
            system.set_system_boot_options(mode=BOOT_MODE_MAP_REV[mode])

        except sushy.exceptions.SushyError as e:
            error_msg = (_('Setting boot mode to %(mode)s '
                           'failed for node %(node)s. '
                           'Error: %(error)s') % {
                               'node': task.node.uuid,
                               'mode': mode,
                               'error': e
                           })
            LOG.error(error_msg)

            # NOTE(sbaker): Some systems such as HPE Gen9 do not support
            # getting or setting the boot mode. When setting failed and the
            # mode attribute is missing from the boot field, raising
            # UnsupportedDriverExtension will allow the deploy to continue.
            if system.boot.get('mode') is None:
                LOG.info(
                    _('Attempt to set boot mode on node %(node)s '
                      'failed to set boot mode as the node does not '
                      'appear to support overriding the boot mode. '
                      'Possibly partial Redfish implementation?'),
                    {'node': task.node.uuid})
                raise exception.UnsupportedDriverExtension(
                    driver=task.node.driver, extension='set_boot_mode')
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 25
0
    def inject_nmi(self, task):
        """Inject NMI, Non Maskable Interrupt.

        Inject NMI (Non Maskable Interrupt) for a node immediately.

        :param task: A TaskManager instance containing the node to act on.
        :raises: InvalidParameterValue on malformed parameter(s)
        :raises: MissingParameterValue on missing parameter(s)
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)
        try:
            system.reset_system(sushy.RESET_NMI)
        except sushy.exceptions.SushyError as e:
            error_msg = (_('Redfish inject NMI failed for node %(node)s. '
                           'Error: %(error)s') % {'node': task.node.uuid,
                                                  'error': e})
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 26
0
    def set_boot_device(self, task, device, persistent=False):
        """Set the boot device for a node.

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

        :param task: a task from TaskManager.
        :param device: the boot device, one of
                       :mod:`ironic.common.boot_devices`.
        :param persistent: Boolean value. True if the boot device will
                           persist to all future boots, False if not.
                           Default: False.
        :raises: InvalidParameterValue on malformed parameter(s)
        :raises: MissingParameterValue on missing parameter(s)
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        utils.pop_node_nested_field(task.node, 'driver_internal_info',
                                    'redfish_boot_device')
        task.node.save()

        system = redfish_utils.get_system(task.node)

        desired_persistence = BOOT_DEVICE_PERSISTENT_MAP_REV[persistent]
        current_persistence = system.boot.get('enabled')

        # NOTE(etingof): this can be racy, esp if BMC is not RESTful
        enabled = (desired_persistence
                   if desired_persistence != current_persistence else None)
        try:
            _set_boot_device(task,
                             system,
                             BOOT_DEVICE_MAP_REV[device],
                             enabled=enabled)
        except sushy.exceptions.SushyError as e:
            error_msg = (_('Redfish set boot device failed for node '
                           '%(node)s. Error: %(error)s') % {
                               'node': task.node.uuid,
                               'error': e
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)
Exemplo n.º 27
0
def get_system(node):
    """Get a Redfish System that represents a node.

    :param node: an Ironic node object
    :raises: RedfishConnectionError when it fails to connect to Redfish
    :raises: RedfishError if the System is not registered in Redfish
    """
    driver_info = parse_driver_info(node)
    system_id = driver_info['system_id']

    try:
        return _get_connection(
            node,
            lambda conn, system_id: conn.get_system(system_id),
            system_id)
    except sushy.exceptions.ResourceNotFoundError as e:
        LOG.error('The Redfish System "%(system)s" was not found for '
                  'node %(node)s. Error %(error)s',
                  {'system': system_id or '<default>',
                   'node': node.uuid, 'error': e})
        raise exception.RedfishError(error=e)
Exemplo n.º 28
0
    def factory_reset(self, task):
        """Reset the BIOS settings of the node to the factory default.

        :param task: a TaskManager instance containing the node to act on.
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        system = redfish_utils.get_system(task.node)
        LOG.debug('Factory reset BIOS settings for node %(node_uuid)s',
                  {'node_uuid': task.node.uuid})
        try:
            system.bios.reset_bios()
        except sushy.exceptions.SushyError as e:
            error_msg = (_('Redfish BIOS factory reset failed for node '
                           '%(node)s. Error: %(error)s') %
                         {'node': task.node.uuid, 'error': e})
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)

        self.post_reset(task)
        self._set_cleaning_reboot(task)
Exemplo n.º 29
0
    def set_boot_device(self, task, device, persistent=False):
        """Set the boot device for a node.

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

        :param task: a task from TaskManager.
        :param device: the boot device, one of
                       :mod:`ironic.common.boot_devices`.
        :param persistent: Boolean value. True if the boot device will
                           persist to all future boots, False if not.
                           Default: False.
        :raises: InvalidParameterValue on malformed parameter(s)
        :raises: MissingParameterValue on missing parameter(s)
        :raises: RedfishConnectionError when it fails to connect to Redfish
        :raises: RedfishError on an error from the Sushy library
        """
        utils.pop_node_nested_field(task.node, 'driver_internal_info',
                                    'redfish_boot_device')
        task.node.save()

        system = redfish_utils.get_system(task.node)

        try:
            _set_boot_device(task,
                             system,
                             BOOT_DEVICE_MAP_REV[device],
                             persistent=persistent)
        except sushy.exceptions.SushyError as e:
            error_msg = (_('Redfish set boot device failed for node '
                           '%(node)s. Error: %(error)s') % {
                               'node': task.node.uuid,
                               'error': e
                           })
            LOG.error(error_msg)
            raise exception.RedfishError(error=error_msg)

        # Ensure that boot mode is synced with what is set.
        # Some BMCs reset it to default (BIOS) when changing the boot device.
        boot_mode_utils.sync_boot_mode(task)
Exemplo n.º 30
0
    def _reset_keys(self, task, reset_type):
        system = redfish_utils.get_system(task.node)
        try:
            sb = system.secure_boot
        except sushy.exceptions.MissingAttributeError:
            LOG.error(
                'Resetting secure boot keys has been requested for node '
                '%s but its Redfish BMC does not have a SecureBoot '
                'object', task.node.uuid)
            raise exception.UnsupportedDriverExtension(driver=task.node.driver,
                                                       extension='reset_keys')

        try:
            sb.reset_keys(reset_type)
        except sushy.exceptions.SushyError as exc:
            msg = (_('Failed to reset secure boot keys on node %(node)s: '
                     '%(exc)s') % {
                         'node': task.node.uuid,
                         'exc': exc
                     })
            LOG.error(msg)
            raise exception.RedfishError(error=msg)