Esempio n. 1
0
    def delete_virtual_disk(self, virtual_disk):
        """Deletes a virtual disk

        The deleted virtual disk will be in pending state. For the changes to
        be applied, a config job must be created and the node must be rebooted.

        :param virtual_disk: id of the virtual disk
        :returns: a dictionary containing:
                 - The is_commit_required key with the value always set to
                   True indicating that a config job must be created to
                   complete virtual disk deletion.
                 - The is_reboot_required key with a RebootRequired enumerated
                   value indicating whether the server must be rebooted to
                   complete virtual disk deletion.
        :raises: WSManRequestFailure on request failures
        :raises: WSManInvalidResponse when receiving invalid response
        :raises: DRACOperationFailed on error reported back by the DRAC
                 interface
        :raises: DRACUnexpectedReturnValue on return value mismatch
        """

        selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
                     'CreationClassName': 'DCIM_RAIDService',
                     'SystemName': 'DCIM:ComputerSystem',
                     'Name': 'DCIM:RAIDService'}
        properties = {'Target': virtual_disk}

        doc = self.client.invoke(uris.DCIM_RAIDService, 'DeleteVirtualDisk',
                                 selectors, properties,
                                 expected_return_value=utils.RET_SUCCESS)

        return utils.build_return_dict(doc, uris.DCIM_RAIDService,
                                       is_commit_required_value=True)
Esempio n. 2
0
    def convert_physical_disks(self, physical_disks, raid_enable):
        """Converts a list of physical disks into or out of RAID mode.

        Disks can be enabled or disabled for RAID mode.

        :param physical_disks: list of FQDD ID strings of the physical disks
                               to update
        :param raid_enable: boolean flag, set to True if the disk is to
                            become part of the RAID.  The same flag is applied
                            to all listed disks
        :returns: a dictionary containing:
                 - The is_commit_required key with the value always set to
                   True indicating that a config job must be created to
                   complete disk conversion.
                 - The is_reboot_required key with a RebootRequired enumerated
                   value indicating whether the server must be rebooted to
                   complete disk conversion.
        """
        invocation = 'ConvertToRAID' if raid_enable else 'ConvertToNonRAID'

        selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
                     'CreationClassName': 'DCIM_RAIDService',
                     'SystemName': 'DCIM:ComputerSystem',
                     'Name': 'DCIM:RAIDService'}

        properties = {'PDArray': physical_disks}

        doc = self.client.invoke(uris.DCIM_RAIDService, invocation,
                                 selectors, properties,
                                 expected_return_value=utils.RET_SUCCESS)

        return utils.build_return_dict(doc, uris.DCIM_RAIDService,
                                       is_commit_required_value=True)
Esempio n. 3
0
    def reset_raid_config(self, raid_controller):
        """Delete all virtual disk and unassign all hotspares

        The job to reset the RAID controller config will be in pending state.
        For the changes to be applied, a config job must be created.

        :param raid_controller: id of the RAID controller
        :returns: a dictionary containing:
                 - The is_commit_required key with the value always set to
                   True indicating that a config job must be created to
                   reset configuration.
                 - The is_reboot_required key with a RebootRequired enumerated
                   value indicating whether the server must be rebooted to
                   reset configuration.
        :raises: WSManRequestFailure on request failures
        :raises: WSManInvalidResponse when receiving invalid response
        :raises: DRACOperationFailed on error reported back by the DRAC
                 interface
        :raises: DRACUnexpectedReturnValue on return value mismatch
        """

        selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
                     'CreationClassName': 'DCIM_RAIDService',
                     'SystemName': 'DCIM:ComputerSystem',
                     'Name': 'DCIM:RAIDService'}
        properties = {'Target': raid_controller}

        doc = self.client.invoke(uris.DCIM_RAIDService, 'ResetConfig',
                                 selectors, properties,
                                 expected_return_value=utils.RET_SUCCESS)

        return utils.build_return_dict(doc, uris.DCIM_RAIDService,
                                       is_commit_required_value=True)
Esempio n. 4
0
    def clear_foreign_config(self, raid_controller):
        """Free up foreign drives

        The job to clear foreign config will be in pending state.
        For the changes to be applied, a config job must be created.

        :param raid_controller: id of the RAID controller
        :returns: a dictionary containing:
                 - The is_commit_required key with the value always set to
                   True indicating that a config job must be created to
                   clear foreign configuration.
                 - The is_reboot_required key with a RebootRequired enumerated
                   value indicating whether the server must be rebooted to
                   clear foreign configuration.
        :raises: WSManRequestFailure on request failures
        :raises: WSManInvalidResponse when receiving invalid response
        :raises: DRACOperationFailed on error reported back by the DRAC
                 interface
        :raises: DRACUnexpectedReturnValue on return value mismatch
        """

        selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
                     'CreationClassName': 'DCIM_RAIDService',
                     'SystemName': 'DCIM:ComputerSystem',
                     'Name': 'DCIM:RAIDService'}
        properties = {'Target': raid_controller}

        doc = self.client.invoke(uris.DCIM_RAIDService, 'ClearForeignConfig',
                                 selectors, properties,
                                 check_return_value=False)

        is_commit_required_value = True
        is_reboot_required_value = None

        ret_value = utils.find_xml(doc,
                                   'ReturnValue',
                                   uris.DCIM_RAIDService).text

        if ret_value == utils.RET_ERROR:
            message_id = utils.find_xml(doc,
                                        'MessageID',
                                        uris.DCIM_RAIDService).text

            # A MessageID 'STOR018' indicates no foreign drive was
            # detected. Return a value which informs the caller nothing
            # further needs to be done.
            if message_id == NO_FOREIGN_DRIVE:
                is_commit_required_value = False
                is_reboot_required_value = constants.RebootRequired.false
            else:
                message = utils.find_xml(doc,
                                         'Message',
                                         uris.DCIM_RAIDService).text
                raise exceptions.DRACOperationFailed(
                        drac_messages=message)

        return utils.build_return_dict(
                doc, uris.DCIM_RAIDService,
                is_commit_required_value=is_commit_required_value,
                is_reboot_required_value=is_reboot_required_value)
Esempio n. 5
0
    def change_physical_disk_state(self,
                                   mode,
                                   controllers_to_physical_disk_ids=None):
        """Convert disks RAID status

        This method intelligently converts the requested physical disks from
        RAID to JBOD or vice versa.  It does this by only converting the
        disks that are not already in the correct state.

        :param mode: constants.RaidStatus enumeration that indicates the mode
                     to change the disks to.
        :param controllers_to_physical_disk_ids: Dictionary of controllers and
               corresponding disk ids to convert to the requested mode.
        :returns: a dictionary containing:
                  - conversion_results, a dictionary that maps controller ids
                    to the conversion results for that controller.  The
                    conversion results are a dict that contains:
                    - The is_commit_required key with the value always set to
                      True indicating that a config job must be created to
                      complete disk conversion.
                    - The is_reboot_required key with a RebootRequired
                      enumerated value indicating whether the server must be
                      rebooted to complete disk conversion.
                  Also contained in the main dict are the following key/values,
                  which are deprecated, should not be used, and will be removed
                  in a future release:
                  - is_reboot_required, a boolean stating whether a reboot is
                    required or not.
                  - commit_required_ids, a list of controller ids that will
                    need to commit their pending RAID changes via a config job.
        :raises: DRACOperationFailed on error reported back by the DRAC and the
                 exception message does not contain NOT_SUPPORTED_MSG constant.
        :raises: Exception on unknown error.
        """
        physical_disks = self.list_physical_disks()

        raid = constants.RaidStatus.raid

        if not controllers_to_physical_disk_ids:
            controllers_to_physical_disk_ids = collections.defaultdict(list)

            all_controllers = self.list_raid_controllers()
            for physical_d in physical_disks:
                # Weed out disks that are not attached to a RAID controller
                if self.is_raid_controller(physical_d.controller,
                                           all_controllers):
                    physical_disk_ids = controllers_to_physical_disk_ids[
                        physical_d.controller]

                    physical_disk_ids.append(physical_d.id)
        '''Modify controllers_to_physical_disk_ids dict by inspecting desired
        status vs current status of each controller's disks.
        Raise exception if there are any failed drives or
        drives not in status 'ready' or 'non-RAID'
        '''
        final_ctls_to_phys_disk_ids = self._check_disks_status(
            mode, physical_disks, controllers_to_physical_disk_ids)

        is_reboot_required = False
        controllers = []
        controllers_to_results = {}
        for controller, physical_disk_ids \
                in final_ctls_to_phys_disk_ids.items():
            if physical_disk_ids:
                LOG.debug("Converting the following disks to {} on RAID "
                          "controller {}: {}".format(mode, controller,
                                                     str(physical_disk_ids)))
                try:
                    conversion_results = \
                        self.convert_physical_disks(physical_disk_ids,
                                                    mode == raid)
                except exceptions.DRACOperationFailed as ex:
                    if constants.NOT_SUPPORTED_MSG in str(ex):
                        LOG.debug("Controller {} does not support "
                                  "JBOD mode".format(controller))
                        controllers_to_results[controller] = \
                            utils.build_return_dict(
                                doc=None,
                                resource_uri=None,
                                is_commit_required_value=False,
                                is_reboot_required_value=constants.
                                RebootRequired.false)
                    else:
                        raise
                else:
                    controllers_to_results[controller] = conversion_results

                    # Remove the code below when is_reboot_required and
                    # commit_required_ids are deprecated
                    reboot_true = constants.RebootRequired.true
                    reboot_optional = constants.RebootRequired.optional
                    _is_reboot_required = \
                        conversion_results["is_reboot_required"]
                    is_reboot_required = is_reboot_required \
                        or (_is_reboot_required
                            in [reboot_true, reboot_optional])
                    controllers.append(controller)
            else:
                controllers_to_results[controller] = \
                    utils.build_return_dict(
                        doc=None,
                        resource_uri=None,
                        is_commit_required_value=False,
                        is_reboot_required_value=constants.
                        RebootRequired.false)

        return {
            'conversion_results': controllers_to_results,
            'is_reboot_required': is_reboot_required,
            'commit_required_ids': controllers
        }
Esempio n. 6
0
    def create_virtual_disk(self,
                            raid_controller,
                            physical_disks,
                            raid_level,
                            size_mb,
                            disk_name=None,
                            span_length=None,
                            span_depth=None):
        """Creates a virtual disk

        The created virtual disk will be in pending state. For the changes to
        be applied, a config job must be created and the node must be rebooted.

        :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_mb: size of the virtual disk in megabytes
        :param disk_name: name of the virtual disk (optional)
        :param span_length: number of disks per span (optional)
        :param span_depth: number of spans in virtual disk (optional)
        :returns: a dictionary containing:
                 - The is_commit_required key with the value always set to
                   True indicating that a config job must be created to
                   complete virtual disk creation.
                 - The is_reboot_required key with a RebootRequired enumerated
                   value indicating whether the server must be rebooted to
                   complete virtual disk creation.
        :raises: WSManRequestFailure on request failures
        :raises: WSManInvalidResponse when receiving invalid response
        :raises: DRACOperationFailed on error reported back by the DRAC
                 interface
        :raises: DRACUnexpectedReturnValue on return value mismatch
        :raises: InvalidParameterValue on invalid input parameter
        """

        virtual_disk_prop_names = []
        virtual_disk_prop_values = []
        error_msgs = []

        # RAID controller validation
        if not raid_controller:
            error_msgs.append("'raid_controller' is not supplied")

        # physical disks validation
        if not physical_disks:
            error_msgs.append("'physical_disks' is not supplied")

        # size validation
        utils.validate_integer_value(size_mb, 'size_mb', error_msgs)

        virtual_disk_prop_names.append('Size')
        virtual_disk_prop_values.append(str(size_mb))

        # RAID level validation
        virtual_disk_prop_names.append('RAIDLevel')
        try:
            virtual_disk_prop_values.append(RAID_LEVELS[str(raid_level)])
        except KeyError:
            error_msgs.append("'raid_level' is invalid")

        if disk_name is not None:
            virtual_disk_prop_names.append('VirtualDiskName')
            virtual_disk_prop_values.append(disk_name)

        if span_depth is not None:
            utils.validate_integer_value(span_depth, 'span_depth', error_msgs)

            virtual_disk_prop_names.append('SpanDepth')
            virtual_disk_prop_values.append(str(span_depth))

        if span_length is not None:
            utils.validate_integer_value(span_length, 'span_length',
                                         error_msgs)

            virtual_disk_prop_names.append('SpanLength')
            virtual_disk_prop_values.append(str(span_length))

        if error_msgs:
            msg = ('The following errors were encountered while parsing '
                   'the provided parameters: %r') % ','.join(error_msgs)
            raise exceptions.InvalidParameterValue(reason=msg)

        selectors = {
            'SystemCreationClassName': 'DCIM_ComputerSystem',
            'CreationClassName': 'DCIM_RAIDService',
            'SystemName': 'DCIM:ComputerSystem',
            'Name': 'DCIM:RAIDService'
        }
        properties = {
            'Target': raid_controller,
            'PDArray': physical_disks,
            'VDPropNameArray': virtual_disk_prop_names,
            'VDPropValueArray': virtual_disk_prop_values
        }
        doc = self.client.invoke(uris.DCIM_RAIDService,
                                 'CreateVirtualDisk',
                                 selectors,
                                 properties,
                                 expected_return_value=utils.RET_SUCCESS)

        return utils.build_return_dict(doc,
                                       uris.DCIM_RAIDService,
                                       is_commit_required_value=True)