diff --git a/.gitreview b/.gitreview
index ff78bb3..2cf8792 100644
--- a/.gitreview
+++ b/.gitreview
@@ -1,4 +1,5 @@
[gerrit]
-host=review.openstack.org
+host=review.opendev.org
port=29418
project=openstack/python-dracclient.git
+defaultbranch=stable/stein
diff --git a/README.rst b/README.rst
index 5263fe0..b906b5e 100644
--- a/README.rst
+++ b/README.rst
@@ -14,5 +14,5 @@ Library for managing machines with Dell iDRAC cards.
* Free software: Apache license
* Documentation: https://docs.openstack.org/python-dracclient/latest
-* Source: http://git.openstack.org/cgit/openstack/python-dracclient
+* Source: http://opendev.org/openstack/python-dracclient
* Bugs: https://bugs.launchpad.net/python-dracclient
diff --git a/doc/requirements.txt b/doc/requirements.txt
new file mode 100644
index 0000000..073d2a4
--- /dev/null
+++ b/doc/requirements.txt
@@ -0,0 +1,7 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
+
+sphinx!=1.6.6,!=1.6.7,<2.0.0;python_version=='2.7' # BSD
+sphinx!=1.6.6,!=1.6.7,!=2.1.0;python_version>='3.4' # BSD
+openstackdocstheme # Apache-2.0
diff --git a/doc/source/conf.py b/doc/source/conf.py
index e6c81e8..6665e41 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -21,7 +21,7 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
- 'oslosphinx'
+ 'openstackdocstheme'
]
# autodoc generation is a bit aggressive and a nuisance when doing heavy
@@ -55,6 +55,7 @@
# html_theme_path = ["."]
# html_theme = '_theme'
# html_static_path = ['static']
+html_theme = 'openstackdocs'
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
@@ -71,3 +72,6 @@
# Example configuration for intersphinx: refer to the Python standard library.
#intersphinx_mapping = {'http://docs.python.org/': None}
+
+# openstackdocstheme options
+repository_name = 'openstack/python-dracclient'
diff --git a/dracclient/client.py b/dracclient/client.py
index 74decc3..d8f55e1 100644
--- a/dracclient/client.py
+++ b/dracclient/client.py
@@ -33,7 +33,7 @@
from dracclient import utils
from dracclient import wsman
-IDRAC_IS_READY = "LC061"
+IDRAC_IS_READY = "0"
LOG = logging.getLogger(__name__)
@@ -272,7 +272,7 @@ def reset_idrac(self, force=False, wait=False,
state_reached = self._wait_for_host_state(
self.client.host,
alive=False,
- ping_count=3,
+ ping_count=2,
retries=24)
if not state_reached:
@@ -388,9 +388,12 @@ def abandon_pending_idrac_changes(self, idrac_fqdd=IDRAC_FQDD):
cim_name='DCIM:iDRACCardService',
target=idrac_fqdd)
- def list_lifecycle_settings(self):
+ def list_lifecycle_settings(self, by_name=False):
"""List the Lifecycle Controller configuration settings
+ :param by_name: Controls whether returned dictionary uses Lifecycle
+ attribute name as key. If set to False, instance_id
+ will be used.
:returns: a dictionary with the Lifecycle Controller settings using its
InstanceID as the key. The attributes are either
LCEnumerableAttribute or LCStringAttribute objects.
@@ -399,7 +402,49 @@ def list_lifecycle_settings(self):
:raises: DRACOperationFailed on error reported back by the DRAC
interface
"""
- return self._lifecycle_cfg.list_lifecycle_settings()
+ return self._lifecycle_cfg.list_lifecycle_settings(by_name)
+
+ def is_lifecycle_in_recovery(self):
+ """Checks if Lifecycle Controller in recovery mode or not
+
+ This method checks the LCStatus value to determine if lifecycle
+ controller is in recovery mode by invoking GetRemoteServicesAPIStatus
+ from iDRAC.
+
+ :returns: a boolean indicating if lifecycle controller is in recovery
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
+ """
+
+ return self._lifecycle_cfg.is_lifecycle_in_recovery()
+
+ def set_lifecycle_settings(self, settings):
+ """Sets lifecycle controller configuration
+
+ It sets the pending_value parameter for each of the attributes
+ passed in. For the values to be applied, a config job must
+ be created.
+
+ :param settings: a dictionary containing the proposed values, with
+ each key being the name of attribute and the value
+ being the proposed value.
+ :returns: a dictionary containing:
+ - The is_commit_required key with a boolean value indicating
+ whether a config job must be created for the values to be
+ applied.
+ - The is_reboot_required key with a RebootRequired enumerated
+ value indicating whether the server must be rebooted for the
+ values to be applied. Possible values are true and false.
+ :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 Lifecycle attribute
+ """
+ return self._lifecycle_cfg.set_lifecycle_settings(settings)
def list_system_settings(self):
"""List the System configuration settings
@@ -468,7 +513,10 @@ def create_config_job(self,
cim_system_creation_class_name='DCIM_ComputerSystem',
cim_system_name='DCIM:ComputerSystem',
reboot=False,
- start_time='TIME_NOW'):
+ start_time='TIME_NOW',
+ realtime=False,
+ wait_for_idrac=True,
+ method_name='CreateTargetedConfigJob'):
"""Creates a configuration job.
In CIM (Common Information Model), weak association is used to name an
@@ -492,6 +540,12 @@ def create_config_job(self,
means execute immediately or None which means
the job will not execute until
schedule_job_execution is called
+ :param realtime: Indicates if reatime mode should be used.
+ Valid values are True and False.
+ :param wait_for_idrac: indicates whether or not to wait for the
+ iDRAC to be ready to accept commands before
+ issuing the command.
+ :param method_name: method of CIM object to invoke
:returns: id of the created job
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
@@ -508,7 +562,10 @@ def create_config_job(self,
cim_system_creation_class_name=cim_system_creation_class_name,
cim_system_name=cim_system_name,
reboot=reboot,
- start_time=start_time)
+ start_time=start_time,
+ realtime=realtime,
+ wait_for_idrac=wait_for_idrac,
+ method_name=method_name)
def create_nic_config_job(
self,
@@ -647,6 +704,37 @@ def abandon_pending_bios_changes(self):
cim_creation_class_name='DCIM_BIOSService',
cim_name='DCIM:BIOSService', target=self.BIOS_DEVICE_FQDD)
+ def commit_pending_lifecycle_changes(
+ self,
+ reboot=False,
+ start_time='TIME_NOW'):
+ """Applies all pending changes on Lifecycle by creating a config job
+
+ :param reboot: indicates whether a RebootJob should also be
+ created or not
+ :param start_time: start time for job execution in format
+ yyyymmddhhmmss, the string 'TIME_NOW' which
+ means execute immediately or None which means
+ the job will not execute until
+ schedule_job_execution is called
+ :returns: id of the created job
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface, including start_time being in the past or
+ badly formatted start_time
+ :raises: DRACUnexpectedReturnValue on return value mismatch
+ """
+ return self._job_mgmt.create_config_job(
+ resource_uri=uris.DCIM_LCService,
+ cim_creation_class_name='DCIM_LCService',
+ cim_name='DCIM:LCService',
+ target='',
+ reboot=reboot,
+ start_time=start_time,
+ wait_for_idrac=False,
+ method_name='CreateConfigJob')
+
def get_lifecycle_controller_version(self):
"""Returns the Lifecycle controller version
@@ -670,6 +758,43 @@ def list_raid_controllers(self):
"""
return self._raid_mgmt.list_raid_controllers()
+ def list_raid_settings(self):
+ """List the RAID configuration settings
+
+ :returns: a dictionary with the RAID settings using InstanceID as the
+ key. The attributes are either RAIDEnumerableAttribute,
+ RAIDStringAttribute objects.
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
+ """
+ return self._raid_mgmt.list_raid_settings()
+
+ def set_raid_settings(self, raid_fqdd, settings):
+ """Sets the RAID configuration
+
+ It sets the pending_value parameter for each of the attributes
+ passed in. For the values to be applied, a config job must
+ be created.
+ :param raid_fqdd: the FQDD of the RAID setting.
+ :param settings: a dictionary containing the proposed values, with
+ each key being the name of attribute and the value
+ being the proposed value.
+ :returns: a dictionary containing:
+ - The is_commit_required key with a boolean value indicating
+ whether a config job must be created for the values to be
+ applied.
+ - The is_reboot_required key with a RebootRequired enumerated
+ value indicating whether the server must be rebooted for the
+ values to be applied. Possible values are true and false.
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
+ """
+ return self._raid_mgmt.set_raid_settings(raid_fqdd, settings)
+
def list_virtual_disks(self):
"""Returns the list of RAID arrays
@@ -784,8 +909,52 @@ def delete_virtual_disk(self, virtual_disk):
"""
return self._raid_mgmt.delete_virtual_disk(virtual_disk)
+ def reset_raid_config(self, raid_controller):
+ """Delete all the virtual disks and unassign all hot spare physical disks
+
+ 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
+ """
+ return self._raid_mgmt.reset_raid_config(raid_controller)
+
+ 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
+ """
+ return self._raid_mgmt.clear_foreign_config(raid_controller)
+
def commit_pending_raid_changes(self, raid_controller, reboot=False,
- start_time='TIME_NOW'):
+ start_time='TIME_NOW', realtime=False):
"""Applies all pending changes on a RAID controller
...by creating a config job.
@@ -798,6 +967,8 @@ def commit_pending_raid_changes(self, raid_controller, reboot=False,
means execute immediately or None which means
the job will not execute until
schedule_job_execution is called
+ :param realtime: Indicates if reatime mode should be used.
+ Valid values are True and False.
:returns: id of the created job
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
@@ -811,7 +982,8 @@ def commit_pending_raid_changes(self, raid_controller, reboot=False,
cim_name='DCIM:RAIDService',
target=raid_controller,
reboot=reboot,
- start_time=start_time)
+ start_time=start_time,
+ realtime=realtime)
def abandon_pending_raid_changes(self, raid_controller):
"""Deletes all pending changes on a RAID controller
@@ -830,6 +1002,14 @@ def abandon_pending_raid_changes(self, raid_controller):
cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target=raid_controller)
+ def is_realtime_supported(self, raid_controller):
+ """Find if controller supports realtime or not
+
+ :param raid_controller: ID of RAID controller
+ :returns: True or False
+ """
+ return self._raid_mgmt.is_realtime_supported(raid_controller)
+
def list_cpus(self):
"""Returns the list of CPUs
@@ -962,53 +1142,71 @@ def is_jbod_capable(self, raid_controller_fqdd):
"""
return self._raid_mgmt.is_jbod_capable(raid_controller_fqdd)
- def is_raid_controller(self, raid_controller_fqdd):
- """Find out if object's fqdd is for a raid controller or not
+ def is_raid_controller(self, raid_controller_fqdd, raid_controllers=None):
+ """Determine if the given controller is a RAID controller
+
+ Since a BOSS controller is a type of RAID controller, this method will
+ return True for both BOSS and RAID controllers.
:param raid_controller_fqdd: The object's fqdd we are testing to see
if it is a raid controller or not.
+ :param raid_controllers: A list of RAIDControllers used to check for
+ the presence of BOSS cards. If None, the
+ iDRAC will be queried for the list of
+ controllers.
:returns: boolean, True if the device is a RAID controller,
False if not.
"""
- return self._raid_mgmt.is_raid_controller(raid_controller_fqdd)
+ return self._raid_mgmt.is_raid_controller(raid_controller_fqdd,
+ raid_controllers)
- def is_boss_controller(self, raid_controller_fqdd):
+ def is_boss_controller(self, raid_controller_fqdd, raid_controllers=None):
"""Find out if a RAID controller a BOSS card or not
:param raid_controller_fqdd: The object's fqdd we are testing to see
if it is a BOSS card or not.
+ :param raid_controllers: A list of RAIDController to scan for presence
+ of BOSS card, if None the drac will be queried
+ for the list of controllers which will then be
+ scanned.
:returns: boolean, True if the device is a BOSS card, False if not.
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
"""
- return self._raid_mgmt.is_boss_controller(raid_controller_fqdd)
+ return self._raid_mgmt.is_boss_controller(raid_controller_fqdd,
+ raid_controllers)
def change_physical_disk_state(self, mode,
controllers_to_physical_disk_ids=None):
- """Convert disks RAID status and return a list of controller IDs
-
- Builds a list of controller ids that have had disks converted to the
- specified RAID status by:
- - Examining all the disks in the system and filtering out any that are
- not attached to a RAID/BOSS controller.
- - Inspect the controllers' disks to see if there are any that need to
- be converted, if so convert them. If a disk is already in the desired
- status the disk is ignored. Also check for failed or unknown disk
- statuses and raise an exception where appropriate.
- - Return a list of controller IDs for controllers whom have had any of
- their disks converted, and whether a reboot is required.
-
- The caller typically should then create a config job for the list of
- controllers returned to finalize the RAID configuration.
-
- :param mode: constants.RaidStatus enumeration used to determine what
- raid status to check for.
+ """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 we are inspecting and creating jobs for
- when needed.
- :returns: a dict containing the following key/values:
+ 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.
+ required or not.
- commit_required_ids, a list of controller ids that will
- need to commit their pending RAID changes via a config job.
+ 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.
@@ -1170,11 +1368,11 @@ def is_idrac_ready(self):
expected_return_value=utils.RET_SUCCESS,
wait_for_idrac=False)
- message_id = utils.find_xml(result,
- 'MessageID',
- uris.DCIM_LCService).text
+ lc_status = utils.find_xml(result,
+ 'LCStatus',
+ uris.DCIM_LCService).text
- return message_id == IDRAC_IS_READY
+ return lc_status == IDRAC_IS_READY
def wait_until_idrac_is_ready(self, retries=None, retry_delay=None):
"""Waits until the iDRAC is in a ready state
diff --git a/dracclient/constants.py b/dracclient/constants.py
index 9356060..ecaffa1 100644
--- a/dracclient/constants.py
+++ b/dracclient/constants.py
@@ -37,6 +37,9 @@
# binary unit constants
UNITS_KI = 2 ** 10
+# Lifecycle Controller status constant
+LC_IN_RECOVERY = '4'
+
# Reboot required indicator
# Note: When the iDRAC returns optional for this value, this indicates that
diff --git a/dracclient/resources/job.py b/dracclient/resources/job.py
index 5bddec7..5ec3443 100644
--- a/dracclient/resources/job.py
+++ b/dracclient/resources/job.py
@@ -101,7 +101,10 @@ def create_config_job(self, resource_uri, cim_creation_class_name,
cim_system_creation_class_name='DCIM_ComputerSystem',
cim_system_name='DCIM:ComputerSystem',
reboot=False,
- start_time='TIME_NOW'):
+ start_time='TIME_NOW',
+ realtime=False,
+ wait_for_idrac=True,
+ method_name='CreateTargetedConfigJob'):
"""Creates a config job
In CIM (Common Information Model), weak association is used to name an
@@ -126,6 +129,12 @@ def create_config_job(self, resource_uri, cim_creation_class_name,
but will not start execution until
schedule_job_execution is called with the returned
job id.
+ :param realtime: Indicates if reatime mode should be used.
+ Valid values are True and False. Default value is False.
+ :param wait_for_idrac: indicates whether or not to wait for the
+ iDRAC to be ready to accept commands before
+ issuing the command.
+ :param method_name: method of CIM object to invoke
:returns: id of the created job
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
@@ -141,16 +150,19 @@ def create_config_job(self, resource_uri, cim_creation_class_name,
properties = {'Target': target}
- if reboot:
+ if realtime:
+ properties['RealTime'] = '1'
+
+ if not realtime and reboot:
properties['RebootJobType'] = '3'
if start_time is not None:
properties['ScheduledStartTime'] = start_time
- doc = self.client.invoke(resource_uri, 'CreateTargetedConfigJob',
+ doc = self.client.invoke(resource_uri, method_name,
selectors, properties,
- expected_return_value=utils.RET_CREATED)
-
+ expected_return_value=utils.RET_CREATED,
+ wait_for_idrac=wait_for_idrac)
return self._get_job_id(doc)
def create_reboot_job(
diff --git a/dracclient/resources/lifecycle_controller.py b/dracclient/resources/lifecycle_controller.py
index 9d903ef..c42bfd1 100644
--- a/dracclient/resources/lifecycle_controller.py
+++ b/dracclient/resources/lifecycle_controller.py
@@ -11,9 +11,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+from dracclient import constants
from dracclient.resources import uris
from dracclient import utils
-from dracclient import wsman
class LifecycleControllerManagement(object):
@@ -42,47 +42,6 @@ def get_version(self):
return tuple(map(int, (lc_version_str.split('.'))))
-class LCConfiguration(object):
-
- def __init__(self, client):
- """Creates LifecycleControllerManagement object
-
- :param client: an instance of WSManClient
- """
- self.client = client
-
- def list_lifecycle_settings(self):
- """List the LC configuration settings
-
- :returns: a dictionary with the LC settings using InstanceID as the
- key. The attributes are either LCEnumerableAttribute,
- LCStringAttribute or LCIntegerAttribute objects.
- :raises: WSManRequestFailure on request failures
- :raises: WSManInvalidResponse when receiving invalid response
- :raises: DRACOperationFailed on error reported back by the DRAC
- interface
- """
- result = {}
- namespaces = [(uris.DCIM_LCEnumeration, LCEnumerableAttribute),
- (uris.DCIM_LCString, LCStringAttribute)]
- for (namespace, attr_cls) in namespaces:
- attribs = self._get_config(namespace, attr_cls)
- result.update(attribs)
- return result
-
- def _get_config(self, resource, attr_cls):
- result = {}
-
- doc = self.client.enumerate(resource)
-
- items = doc.find('.//{%s}Items' % wsman.NS_WSMAN)
- for item in items:
- attribute = attr_cls.parse(item)
- result[attribute.instance_id] = attribute
-
- return result
-
-
class LCAttribute(object):
"""Generic LC attribute class"""
@@ -161,6 +120,17 @@ def parse(cls, lifecycle_attr_xml):
lifecycle_attr.current_value, lifecycle_attr.pending_value,
lifecycle_attr.read_only, possible_values)
+ def validate(self, new_value):
+ """Validates new value"""
+
+ if str(new_value) not in self.possible_values:
+ msg = ("Attribute '%(attr)s' cannot be set to value '%(val)s'."
+ " It must be in %(possible_values)r.") % {
+ 'attr': self.name,
+ 'val': new_value,
+ 'possible_values': self.possible_values}
+ return msg
+
class LCStringAttribute(LCAttribute):
"""String LC attribute class"""
@@ -199,3 +169,96 @@ def parse(cls, lifecycle_attr_xml):
return cls(lifecycle_attr.name, lifecycle_attr.instance_id,
lifecycle_attr.current_value, lifecycle_attr.pending_value,
lifecycle_attr.read_only, min_length, max_length)
+
+
+class LCConfiguration(object):
+
+ NAMESPACES = [(uris.DCIM_LCEnumeration, LCEnumerableAttribute),
+ (uris.DCIM_LCString, LCStringAttribute)]
+
+ def __init__(self, client):
+ """Creates LifecycleControllerManagement object
+
+ :param client: an instance of WSManClient
+ """
+ self.client = client
+
+ def list_lifecycle_settings(self, by_name=False):
+ """List the LC configuration settings
+
+ :param by_name: Controls whether returned dictionary uses Lifecycle
+ attribute name or instance_id as key.
+ :returns: a dictionary with the LC settings using InstanceID as the
+ key. The attributes are either LCEnumerableAttribute,
+ LCStringAttribute or LCIntegerAttribute objects.
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
+ """
+ return utils.list_settings(self.client, self.NAMESPACES, by_name)
+
+ def is_lifecycle_in_recovery(self):
+ """Check if Lifecycle Controller in recovery mode or not
+
+ This method checks the LCStatus value to determine if lifecycle
+ controller is in recovery mode by invoking GetRemoteServicesAPIStatus
+ from iDRAC.
+
+ :returns: a boolean indicating if lifecycle controller is in recovery
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
+ """
+
+ selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
+ 'SystemName': 'DCIM:ComputerSystem',
+ 'CreationClassName': 'DCIM_LCService',
+ 'Name': 'DCIM:LCService'}
+
+ doc = self.client.invoke(uris.DCIM_LCService,
+ 'GetRemoteServicesAPIStatus',
+ selectors,
+ {},
+ expected_return_value=utils.RET_SUCCESS,
+ wait_for_idrac=False)
+
+ lc_status = utils.find_xml(doc,
+ 'LCStatus',
+ uris.DCIM_LCService).text
+
+ return lc_status == constants.LC_IN_RECOVERY
+
+ def set_lifecycle_settings(self, settings):
+ """Sets the Lifecycle Controller configuration
+
+ It sets the pending_value parameter for each of the attributes
+ passed in. For the values to be applied, a config job must
+ be created.
+
+ :param settings: a dictionary containing the proposed values, with
+ each key being the name of attribute and the value
+ being the proposed value.
+ :returns: a dictionary containing:
+ - The is_commit_required key with a boolean value indicating
+ whether a config job must be created for the values to be
+ applied.
+ - The is_reboot_required key with a RebootRequired enumerated
+ value indicating whether the server must be rebooted for the
+ values to be applied. Possible values are true and false.
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
+ """
+
+ return utils.set_settings('Lifecycle',
+ self.client,
+ self.NAMESPACES,
+ settings,
+ uris.DCIM_LCService,
+ "DCIM_LCService",
+ "DCIM:LCService",
+ '',
+ wait_for_idrac=False)
diff --git a/dracclient/resources/raid.py b/dracclient/resources/raid.py
index 4fe31d1..13c8628 100644
--- a/dracclient/resources/raid.py
+++ b/dracclient/resources/raid.py
@@ -12,6 +12,7 @@
# under the License.
import collections
+import copy
import logging
from dracclient import constants
@@ -34,6 +35,11 @@
REVERSE_RAID_LEVELS = dict((v, k) for (k, v) in RAID_LEVELS.items())
+RAID_CONTROLLER_IS_REALTIME = {
+ '1': True,
+ '0': False
+}
+
DISK_RAID_STATUS = {
'0': 'unknown',
'1': 'ready',
@@ -76,11 +82,12 @@
['id', 'description', 'controller', 'manufacturer', 'model', 'media_type',
'interface_type', 'size_mb', 'free_size_mb', 'serial_number',
'firmware_version', 'status', 'raid_status', 'sas_address',
- 'device_protocol'])
+ 'device_protocol', 'bus'])
RAIDController = collections.namedtuple(
'RAIDController', ['id', 'description', 'manufacturer', 'model',
- 'primary_status', 'firmware_version', 'bus'])
+ 'primary_status', 'firmware_version', 'bus',
+ 'supports_realtime'])
VirtualDisk = collections.namedtuple(
'VirtualDisk',
@@ -88,9 +95,225 @@
'status', 'raid_status', 'span_depth', 'span_length',
'pending_operations', 'physical_disks'])
+NO_FOREIGN_DRIVES = ["STOR058", "STOR018"]
+
+
+class RAIDAttribute(object):
+ """Generic RAID attribute class"""
+
+ def __init__(self, name, instance_id, current_value, pending_value,
+ read_only, fqdd):
+ """Creates RAIDAttribute object
+
+ :param name: name of the RAID attribute
+ :param instance_id: InstanceID of the RAID attribute
+ :param current_value: list containing the current values of the
+ RAID attribute
+ :param pending_value: pending value of the RAID attribute, reflecting
+ an unprocessed change (eg. config job not completed)
+ :param read_only: indicates whether this RAID attribute can be changed
+ :param fqdd: Fully Qualified Device Description of the RAID Attribute
+ """
+
+ self.name = name
+ self.instance_id = instance_id
+ self.current_value = current_value
+ self.pending_value = pending_value
+ self.read_only = read_only
+ self.fqdd = fqdd
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+ @classmethod
+ def parse(cls, namespace, raid_attr_xml):
+ """Parses XML and creates RAIDAttribute object"""
+
+ name = utils.get_wsman_resource_attr(
+ raid_attr_xml, namespace, 'AttributeName')
+ instance_id = utils.get_wsman_resource_attr(
+ raid_attr_xml, namespace, 'InstanceID')
+ current_value = [attr.text for attr in
+ utils.find_xml(raid_attr_xml, 'CurrentValue',
+ namespace, find_all=True)]
+ pending_value = utils.get_wsman_resource_attr(
+ raid_attr_xml, namespace, 'PendingValue', nullable=True)
+ read_only = utils.get_wsman_resource_attr(
+ raid_attr_xml, namespace, 'IsReadOnly')
+ fqdd = utils.get_wsman_resource_attr(
+ raid_attr_xml, namespace, 'FQDD')
+
+ return cls(name, instance_id, current_value, pending_value,
+ (read_only == 'true'), fqdd)
+
+
+class RAIDEnumerableAttribute(RAIDAttribute):
+ """Enumerable RAID attribute class"""
+
+ namespace = uris.DCIM_RAIDEnumeration
+
+ def __init__(self, name, instance_id, current_value, pending_value,
+ read_only, fqdd, possible_values):
+ """Creates RAIDEnumerableAttribute object
+
+ :param name: name of the RAID attribute
+ :param instance_id: InstanceID of the RAID attribute
+ :param current_value: list containing the current values of the
+ RAID attribute
+ :param pending_value: pending value of the RAID attribute, reflecting
+ an unprocessed change (eg. config job not completed)
+ :param read_only: indicates whether this RAID attribute can be changed
+ :param fqdd: Fully Qualified Device Description of the RAID
+ Attribute
+ :param possible_values: list containing the allowed values for the RAID
+ attribute
+ """
+ super(RAIDEnumerableAttribute, self).__init__(name, instance_id,
+ current_value,
+ pending_value,
+ read_only, fqdd)
+
+ self.possible_values = possible_values
+
+ @classmethod
+ def parse(cls, raid_attr_xml):
+ """Parses XML and creates RAIDEnumerableAttribute object"""
+
+ raid_attr = RAIDAttribute.parse(cls.namespace, raid_attr_xml)
+ possible_values = [attr.text for attr
+ in utils.find_xml(raid_attr_xml,
+ 'PossibleValues',
+ cls.namespace, find_all=True)]
+
+ return cls(raid_attr.name, raid_attr.instance_id,
+ raid_attr.current_value, raid_attr.pending_value,
+ raid_attr.read_only, raid_attr.fqdd, possible_values)
+
+ def validate(self, new_value):
+ """Validates new value"""
+
+ if str(new_value) not in self.possible_values:
+ msg = ("Attribute '%(attr)s' cannot be set to value '%(val)s'."
+ " It must be in %(possible_values)r.") % {
+ 'attr': self.name,
+ 'val': new_value,
+ 'possible_values': self.possible_values}
+ return msg
+
+
+class RAIDStringAttribute(RAIDAttribute):
+ """String RAID attribute class"""
+
+ namespace = uris.DCIM_RAIDString
+
+ def __init__(self, name, instance_id, current_value, pending_value,
+ read_only, fqdd, min_length, max_length):
+ """Creates RAIDStringAttribute object
+
+ :param name: name of the RAID attribute
+ :param instance_id: InstanceID of the RAID attribute
+ :param current_value: list containing the current values of the
+ RAID attribute
+ :param pending_value: pending value of the RAID attribute, reflecting
+ an unprocessed change (eg. config job not completed)
+ :param read_only: indicates whether this RAID attribute can be changed
+ :param fqdd: Fully Qualified Device Description of the RAID
+ Attribute
+ :param min_length: minimum length of the string
+ :param max_length: maximum length of the string
+ """
+ super(RAIDStringAttribute, self).__init__(name, instance_id,
+ current_value, pending_value,
+ read_only, fqdd)
+ self.min_length = min_length
+ self.max_length = max_length
+
+ @classmethod
+ def parse(cls, raid_attr_xml):
+ """Parses XML and creates RAIDStringAttribute object"""
+
+ raid_attr = RAIDAttribute.parse(cls.namespace, raid_attr_xml)
+ min_length = int(utils.get_wsman_resource_attr(
+ raid_attr_xml, cls.namespace, 'MinLength'))
+ max_length = int(utils.get_wsman_resource_attr(
+ raid_attr_xml, cls.namespace, 'MaxLength'))
+
+ return cls(raid_attr.name, raid_attr.instance_id,
+ raid_attr.current_value, raid_attr.pending_value,
+ raid_attr.read_only, raid_attr.fqdd,
+ min_length, max_length)
+
+
+class RAIDIntegerAttribute(RAIDAttribute):
+ """Integer RAID attribute class"""
+
+ namespace = uris.DCIM_RAIDInteger
+
+ def __init__(self, name, instance_id, current_value, pending_value,
+ read_only, fqdd, lower_bound, upper_bound):
+ """Creates RAIDIntegerAttribute object
+
+ :param name: name of the RAID attribute
+ :param instance_id: InstanceID of the RAID attribute
+ :param current_value: list containing the current value of the
+ RAID attribute
+ :param pending_value: pending value of the RAID attribute,
+ reflecting an unprocessed change
+ (eg. config job not completed)
+ :param read_only: indicates whether this RAID attribute can be
+ changed
+ :param fqdd: Fully Qualified Device Description of the RAID
+ Attribute
+ :param lower_bound: minimum value for the RAID attribute
+ :param upper_bound: maximum value for the RAID attribute
+ """
+ super(RAIDIntegerAttribute, self).__init__(name, instance_id,
+ current_value,
+ pending_value,
+ read_only, fqdd)
+ self.lower_bound = lower_bound
+ self.upper_bound = upper_bound
+
+ @classmethod
+ def parse(cls, raid_attr_xml):
+ """Parses XML and creates RAIDIntegerAttribute object"""
+
+ raid_attr = RAIDAttribute.parse(cls.namespace, raid_attr_xml)
+ lower_bound = utils.get_wsman_resource_attr(
+ raid_attr_xml, cls.namespace, 'LowerBound')
+ upper_bound = utils.get_wsman_resource_attr(
+ raid_attr_xml, cls.namespace, 'UpperBound')
+
+ if raid_attr.current_value:
+ raid_attr.current_value = int(raid_attr.current_value[0])
+ if raid_attr.pending_value:
+ raid_attr.pending_value = int(raid_attr.pending_value)
+
+ return cls(raid_attr.name, raid_attr.instance_id,
+ raid_attr.current_value, raid_attr.pending_value,
+ raid_attr.read_only, raid_attr.fqdd,
+ int(lower_bound), int(upper_bound))
+
+ def validate(self, new_value):
+ """Validates new value"""
+
+ val = int(new_value)
+ if val < self.lower_bound or val > self.upper_bound:
+ msg = ('Attribute %(attr)s cannot be set to value %(val)d.'
+ ' It must be between %(lower)d and %(upper)d.') % {
+ 'attr': self.name,
+ 'val': new_value,
+ 'lower': self.lower_bound,
+ 'upper': self.upper_bound}
+ return msg
+
class RAIDManagement(object):
+ NAMESPACES = [(uris.DCIM_RAIDEnumeration, RAIDEnumerableAttribute),
+ (uris.DCIM_RAIDString, RAIDStringAttribute),
+ (uris.DCIM_RAIDInteger, RAIDIntegerAttribute)]
+
def __init__(self, client):
"""Creates RAIDManagement object
@@ -98,6 +321,54 @@ def __init__(self, client):
"""
self.client = client
+ def list_raid_settings(self):
+ """List the RAID configuration settings
+
+ :returns: a dictionary with the RAID settings using InstanceID as the
+ key. The attributes are either RAIDEnumerableAttribute,
+ RAIDStringAttribute objects.
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
+ """
+
+ return utils.list_settings(self.client, self.NAMESPACES,
+ by_name=False)
+
+ def set_raid_settings(self, raid_fqdd, new_settings):
+ """Sets the RAID configuration
+
+ It sets the pending_value parameter for each of the attributes
+ passed in. For the values to be applied, a config job must
+ be created.
+ :param raid_fqdd: the FQDD of the RAID setting.
+ :param new_settings: a dictionary containing the proposed values, with
+ each key being the name of attribute and the value
+ being the proposed value.
+ :returns: a dictionary containing:
+ - The is_commit_required key with a boolean value indicating
+ whether a config job must be created for the values to be
+ applied.
+ - The is_reboot_required key with a RebootRequired enumerated
+ value indicating whether the server must be rebooted for the
+ values to be applied. Possible values are true and false.
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
+ """
+
+ return utils.set_settings('RAID',
+ self.client,
+ self.NAMESPACES,
+ new_settings,
+ uris.DCIM_RAIDService,
+ "DCIM_RAIDService",
+ "DCIM:RAIDService",
+ raid_fqdd,
+ by_name=False)
+
def list_raid_controllers(self):
"""Returns the list of RAID controllers
@@ -131,7 +402,10 @@ def _parse_drac_raid_controller(self, drac_controller):
'PrimaryStatus')],
firmware_version=self._get_raid_controller_attr(
drac_controller, 'ControllerFirmwareVersion'),
- bus=self._get_raid_controller_attr(drac_controller, 'Bus'))
+ bus=self._get_raid_controller_attr(drac_controller, 'Bus').upper(),
+ supports_realtime=RAID_CONTROLLER_IS_REALTIME[
+ self._get_raid_controller_attr(
+ drac_controller, 'RealtimeCapability')])
def _get_raid_controller_attr(self, drac_controller, attr_name):
return utils.get_wsman_resource_attr(
@@ -162,7 +436,12 @@ def _parse_drac_virtual_disk(self, drac_disk):
drac_raid_level = self._get_virtual_disk_attr(drac_disk, 'RAIDTypes')
size_b = self._get_virtual_disk_attr(drac_disk, 'SizeInBytes')
drac_status = self._get_virtual_disk_attr(drac_disk, 'PrimaryStatus')
- drac_raid_status = self._get_virtual_disk_attr(drac_disk, 'RAIDStatus')
+ drac_raid_status = self._get_virtual_disk_attr(
+ drac_disk, 'RAIDStatus', allow_missing=True)
+ if drac_raid_status is None:
+ drac_raid_status = self._get_virtual_disk_attr(
+ drac_disk, 'RaidStatus')
+
drac_pending_operations = self._get_virtual_disk_attr(
drac_disk, 'PendingOperations')
@@ -187,10 +466,11 @@ def _parse_drac_virtual_disk(self, drac_disk):
physical_disks=self._get_virtual_disk_attrs(drac_disk,
'PhysicalDiskIDs'))
- def _get_virtual_disk_attr(self, drac_disk, attr_name, nullable=False):
+ def _get_virtual_disk_attr(
+ self, drac_disk, attr_name, nullable=False, allow_missing=False):
return utils.get_wsman_resource_attr(
drac_disk, uris.DCIM_VirtualDiskView, attr_name,
- nullable=nullable)
+ nullable=nullable, allow_missing=allow_missing)
def _get_virtual_disk_attrs(self, drac_disk, attr_name):
return utils.get_all_wsman_resource_attrs(
@@ -247,6 +527,11 @@ def _parse_drac_physical_disk(self,
uri)
drac_bus_protocol = self._get_physical_disk_attr(drac_disk,
'BusProtocol', uri)
+ bus = self._get_physical_disk_attr(drac_disk,
+ 'Bus', uri, allow_missing=True)
+
+ if bus is not None:
+ bus = bus.upper()
return PhysicalDisk(
id=fqdd,
@@ -272,7 +557,8 @@ def _parse_drac_physical_disk(self,
device_protocol=self._get_physical_disk_attr(drac_disk,
'DeviceProtocol',
uri,
- allow_missing=True))
+ allow_missing=True),
+ bus=bus)
def _get_physical_disk_attr(self, drac_disk, attr_name, uri,
allow_missing=False):
@@ -512,24 +798,41 @@ def is_jbod_capable(self, raid_controller_fqdd):
return is_jbod_capable
- def is_raid_controller(self, raid_controller_fqdd):
+ def is_raid_controller(self, raid_controller_fqdd, raid_controllers=None):
"""Find out if object's fqdd is for a raid controller or not
:param raid_controller_fqdd: The object's fqdd we are testing to see
if it is a raid controller or not.
+ :param raid_controllers: A list of RAIDControllers used to check for
+ the presence of BOSS cards. If None, the
+ iDRAC will be queried for the list of
+ controllers.
:returns: boolean, True if the device is a RAID controller,
False if not.
"""
- return raid_controller_fqdd.startswith('RAID.')
+ return raid_controller_fqdd.startswith('RAID.') or \
+ self.is_boss_controller(raid_controller_fqdd, raid_controllers)
- def is_boss_controller(self, raid_controller_fqdd):
+ def is_boss_controller(self, raid_controller_fqdd, raid_controllers=None):
"""Find out if a RAID controller a BOSS card or not
:param raid_controller_fqdd: The object's fqdd we are testing to see
if it is a BOSS card or not.
+ :param raid_controllers: A list of RAIDController to scan for presence
+ of BOSS card, if None the drac will be queried
+ for the list of controllers which will then be
+ scanned.
:returns: boolean, True if the device is a BOSS card, False if not.
+ :raises: WSManRequestFailure on request failures
+ :raises: WSManInvalidResponse when receiving invalid response
+ :raises: DRACOperationFailed on error reported back by the DRAC
+ interface
"""
- return raid_controller_fqdd.startswith('AHCI.')
+ if raid_controllers is None:
+ raid_controllers = self.list_raid_controllers()
+ boss_raid_controllers = [
+ c.id for c in raid_controllers if c.model.startswith('BOSS')]
+ return raid_controller_fqdd in boss_raid_controllers
def _check_disks_status(self, mode, physical_disks,
controllers_to_physical_disk_ids):
@@ -547,15 +850,17 @@ def _check_disks_status(self, mode, physical_disks,
:param mode: constants.RaidStatus enumeration used to
determine what raid status to check for.
:param physical_disks: all physical disks
- :param controllers_to_physical_disk_ids: Dictionary of controllers
- we are inspecting and creating jobs for when needed. If
- needed modify this dict so that only drives that need to
- be changed to RAID or JBOD are in the list of disk keys
- for corresponding controller.
+ :param controllers_to_physical_disk_ids: Dictionary of controllers and
+ corresponding disk ids to convert to the requested mode.
+ :returns: a dictionary mapping controller FQDDs to the list of
+ physical disks that need to be converted for that controller.
:raises: ValueError: Exception message will list failed drives and
drives whose state cannot be changed at this time, drive
state is not "ready" or "non-RAID".
"""
+ controllers_to_physical_disk_ids = copy.deepcopy(
+ controllers_to_physical_disk_ids)
+
p_disk_id_to_status = {}
for physical_disk in physical_disks:
p_disk_id_to_status[physical_disk.id] = physical_disk.raid_status
@@ -614,34 +919,37 @@ def _check_disks_status(self, mode, physical_disks,
raise ValueError(error_msg)
+ return controllers_to_physical_disk_ids
+
def change_physical_disk_state(self, mode,
controllers_to_physical_disk_ids=None):
- """Convert disks RAID status and return a list of controller IDs
-
- Builds a list of controller ids that have had disks converted to the
- specified RAID status by:
- - Examining all the disks in the system and filtering out any that are
- not attached to a RAID/BOSS controller.
- - Inspect the controllers' disks to see if there are any that need to
- be converted, if so convert them. If a disk is already in the desired
- status the disk is ignored. Also check for failed or unknown disk
- statuses and raise an exception where appropriate.
- - Return a list of controller IDs for controllers whom have had any of
- their disks converted, and whether a reboot is required.
-
- The caller typically should then create a config job for the list of
- controllers returned to finalize the RAID configuration.
-
- :param mode: constants.RaidStatus enumeration used to determine what
- raid status to check for.
+ """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 we are inspecting and creating jobs for
- when needed.
- :returns: a dict containing the following key/values:
+ 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.
+ required or not.
- commit_required_ids, a list of controller ids that will
- need to commit their pending RAID changes via a config job.
+ 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.
@@ -653,10 +961,11 @@ def change_physical_disk_state(self, mode,
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)
- or self.is_boss_controller(physical_d.controller)):
+ if self.is_raid_controller(physical_d.controller,
+ all_controllers):
physical_disk_ids = controllers_to_physical_disk_ids[
physical_d.controller]
@@ -667,13 +976,14 @@ def change_physical_disk_state(self, mode,
Raise exception if there are any failed drives or
drives not in status 'ready' or 'non-RAID'
'''
- self._check_disks_status(mode, physical_disks,
- controllers_to_physical_disk_ids)
+ 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 controllers_to_physical_disk_ids.items():
+ in final_ctls_to_phys_disk_ids.items():
if physical_disk_ids:
LOG.debug("Converting the following disks to {} on RAID "
"controller {}: {}".format(
@@ -686,20 +996,149 @@ def change_physical_disk_state(self, mode,
if constants.NOT_SUPPORTED_MSG in str(ex):
LOG.debug("Controller {} does not support "
"JBOD mode".format(controller))
- pass
+ 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:
- if conversion_results:
- 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])
- if conversion_results["is_commit_required"]:
- controllers.append(controller)
-
- return {'is_reboot_required': is_reboot_required,
+ 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}
+
+ def is_realtime_supported(self, raid_controller_fqdd):
+ """Find if controller supports realtime or not
+
+ :param raid_controller_fqdd: ID of RAID controller
+ :returns: True or False
+ """
+ drac_raid_controllers = self.list_raid_controllers()
+ realtime_controller = [cnt.id for cnt in drac_raid_controllers
+ if cnt.supports_realtime]
+
+ if raid_controller_fqdd in realtime_controller:
+ return True
+
+ return False
+
+ 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)
+
+ 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'/'STOR058' indicates no foreign drive was
+ # detected. Return a value which informs the caller nothing
+ # further needs to be done.
+ no_foreign_drives_detected = any(
+ stor_id == message_id for stor_id in NO_FOREIGN_DRIVES)
+ if no_foreign_drives_detected:
+ 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)
diff --git a/dracclient/resources/uris.py b/dracclient/resources/uris.py
index b39a14b..218d85d 100644
--- a/dracclient/resources/uris.py
+++ b/dracclient/resources/uris.py
@@ -94,20 +94,30 @@
DCIM_PhysicalDiskView = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
'DCIM_PhysicalDiskView')
+DCIM_RAIDEnumeration = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
+ 'DCIM_RAIDEnumeration')
+
+DCIM_RAIDInteger = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
+ 'DCIM_RAIDInteger')
+
DCIM_RAIDService = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
'DCIM_RAIDService')
-DCIM_SystemView = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
- 'DCIM_SystemView')
+
+DCIM_RAIDString = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
+ 'DCIM_RAIDString')
DCIM_SystemEnumeration = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
'DCIM_SystemEnumeration')
+DCIM_SystemInteger = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
+ 'DCIM_SystemInteger')
+
DCIM_SystemString = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
'DCIM_SystemString')
-DCIM_SystemInteger = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
- 'DCIM_SystemInteger')
+DCIM_SystemView = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
+ 'DCIM_SystemView')
DCIM_VirtualDiskView = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
'DCIM_VirtualDiskView')
diff --git a/dracclient/tests/test_bios.py b/dracclient/tests/test_bios.py
index 38f6d1b..b9f56be 100644
--- a/dracclient/tests/test_bios.py
+++ b/dracclient/tests/test_bios.py
@@ -354,7 +354,8 @@ def test_set_bios_settings(self, mock_requests, mock_invoke,
result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_BIOSService, 'SetAttributes',
- expected_selectors, expected_properties)
+ expected_selectors, expected_properties,
+ wait_for_idrac=True)
def test_set_bios_settings_error(self, mock_requests,
mock_wait_until_idrac_is_ready):
diff --git a/dracclient/tests/test_idrac_card.py b/dracclient/tests/test_idrac_card.py
index 21e46d7..6228554 100644
--- a/dracclient/tests/test_idrac_card.py
+++ b/dracclient/tests/test_idrac_card.py
@@ -214,7 +214,8 @@ def test_set_idrac_settings(
result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_iDRACCardService, 'SetAttributes',
- expected_selectors, expected_properties)
+ expected_selectors, expected_properties,
+ wait_for_idrac=True)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
@@ -245,7 +246,8 @@ def test_set_idrac_settings_with_valid_length_string(
result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_iDRACCardService, 'SetAttributes',
- expected_selectors, expected_properties)
+ expected_selectors, expected_properties,
+ wait_for_idrac=True)
def test_set_idrac_settings_with_too_long_string(
self, mock_requests, mock_wait_until_idrac_is_ready):
diff --git a/dracclient/tests/test_job.py b/dracclient/tests/test_job.py
index 4dcbc56..adb1a34 100644
--- a/dracclient/tests/test_job.py
+++ b/dracclient/tests/test_job.py
@@ -226,12 +226,43 @@ def test_delete_some_jobs_not_found(
self.assertEqual(mock_requests.call_count, 2)
+ @mock.patch.object(dracclient.client.WSManClient, 'invoke',
+ spec_set=True, autospec=True)
+ def test_create_config_job_for_lifecycle(self, mock_invoke):
+ cim_creation_class_name = 'DCIM_LCService'
+ cim_name = 'DCIM:LCService'
+ target = ''
+
+ expected_selectors = {'CreationClassName': cim_creation_class_name,
+ 'Name': cim_name,
+ 'SystemCreationClassName': 'DCIM_ComputerSystem',
+ 'SystemName': 'DCIM:ComputerSystem'}
+ expected_properties = {'Target': target,
+ 'ScheduledStartTime': 'TIME_NOW'}
+
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.JobInvocations[uris.DCIM_LCService][
+ 'CreateConfigJob']['ok'])
+
+ job_id = self.drac_client.create_config_job(
+ uris.DCIM_LCService, cim_creation_class_name, cim_name, target,
+ start_time='TIME_NOW',
+ wait_for_idrac=False, method_name='CreateConfigJob')
+
+ mock_invoke.assert_called_once_with(
+ mock.ANY, uris.DCIM_LCService, 'CreateConfigJob',
+ expected_selectors, expected_properties,
+ expected_return_value=utils.RET_CREATED,
+ wait_for_idrac=False)
+ self.assertEqual('JID_442507917525', job_id)
+
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_create_config_job(self, mock_invoke):
cim_creation_class_name = 'DCIM_BIOSService'
cim_name = 'DCIM:BIOSService'
target = 'BIOS.Setup.1-1'
+ wait_for_idrac = True
expected_selectors = {'CreationClassName': cim_creation_class_name,
'Name': cim_name,
'SystemCreationClassName': 'DCIM_ComputerSystem',
@@ -249,7 +280,8 @@ def test_create_config_job(self, mock_invoke):
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_BIOSService, 'CreateTargetedConfigJob',
expected_selectors, expected_properties,
- expected_return_value=utils.RET_CREATED)
+ expected_return_value=utils.RET_CREATED,
+ wait_for_idrac=wait_for_idrac)
self.assertEqual('JID_442507917525', job_id)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
@@ -259,6 +291,7 @@ def test_create_config_job_with_start_time(self, mock_invoke):
cim_name = 'DCIM:BIOSService'
target = 'BIOS.Setup.1-1'
start_time = "20140924120105"
+ wait_for_idrac = True
expected_selectors = {'CreationClassName': cim_creation_class_name,
'Name': cim_name,
'SystemCreationClassName': 'DCIM_ComputerSystem',
@@ -276,7 +309,8 @@ def test_create_config_job_with_start_time(self, mock_invoke):
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_BIOSService, 'CreateTargetedConfigJob',
expected_selectors, expected_properties,
- expected_return_value=utils.RET_CREATED)
+ expected_return_value=utils.RET_CREATED,
+ wait_for_idrac=wait_for_idrac)
self.assertEqual('JID_442507917525', job_id)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
@@ -286,6 +320,7 @@ def test_create_config_job_with_no_start_time(self, mock_invoke):
cim_name = 'DCIM:BIOSService'
target = 'BIOS.Setup.1-1'
start_time = None
+ wait_for_idrac = True
expected_selectors = {'CreationClassName': cim_creation_class_name,
'Name': cim_name,
'SystemCreationClassName': 'DCIM_ComputerSystem',
@@ -302,7 +337,8 @@ def test_create_config_job_with_no_start_time(self, mock_invoke):
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_BIOSService, 'CreateTargetedConfigJob',
expected_selectors, expected_properties,
- expected_return_value=utils.RET_CREATED)
+ expected_return_value=utils.RET_CREATED,
+ wait_for_idrac=wait_for_idrac)
self.assertEqual('JID_442507917525', job_id)
@requests_mock.Mocker()
@@ -323,12 +359,32 @@ def test_create_config_job_failed(self, mock_requests,
exceptions.DRACOperationFailed, self.drac_client.create_config_job,
uris.DCIM_BIOSService, cim_creation_class_name, cim_name, target)
+ @requests_mock.Mocker()
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_create_config_job_for_lifecycle_failed(
+ self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ cim_creation_class_name = 'DCIM_LCService'
+ cim_name = 'DCIM:LCService'
+ target = ''
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.JobInvocations[uris.DCIM_LCService][
+ 'CreateConfigJob']['error'])
+
+ self.assertRaises(
+ exceptions.DRACOperationFailed, self.drac_client.create_config_job,
+ uris.DCIM_LCService, cim_creation_class_name, cim_name, target)
+
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True)
def test_create_config_job_with_reboot(self, mock_invoke):
cim_creation_class_name = 'DCIM_BIOSService'
cim_name = 'DCIM:BIOSService'
target = 'BIOS.Setup.1-1'
+ wait_for_idrac = True
expected_selectors = {'CreationClassName': cim_creation_class_name,
'Name': cim_name,
'SystemCreationClassName': 'DCIM_ComputerSystem',
@@ -342,12 +398,42 @@ def test_create_config_job_with_reboot(self, mock_invoke):
job_id = self.drac_client.create_config_job(
uris.DCIM_BIOSService, cim_creation_class_name, cim_name, target,
- reboot=True)
+ reboot=True, realtime=False)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_BIOSService, 'CreateTargetedConfigJob',
expected_selectors, expected_properties,
- expected_return_value=utils.RET_CREATED)
+ expected_return_value=utils.RET_CREATED,
+ wait_for_idrac=wait_for_idrac)
+ self.assertEqual('JID_442507917525', job_id)
+
+ @mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
+ autospec=True)
+ def test_create_config_job_with_realtime(self, mock_invoke):
+ cim_creation_class_name = 'DCIM_BIOSService'
+ cim_name = 'DCIM:BIOSService'
+ target = 'BIOS.Setup.1-1'
+ wait_for_idrac = True
+ expected_selectors = {'CreationClassName': cim_creation_class_name,
+ 'Name': cim_name,
+ 'SystemCreationClassName': 'DCIM_ComputerSystem',
+ 'SystemName': 'DCIM:ComputerSystem'}
+ expected_properties = {'Target': target,
+ 'ScheduledStartTime': 'TIME_NOW',
+ 'RealTime': '1'}
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.JobInvocations[uris.DCIM_BIOSService][
+ 'CreateTargetedConfigJob']['ok'])
+
+ job_id = self.drac_client.create_config_job(
+ uris.DCIM_BIOSService, cim_creation_class_name, cim_name, target,
+ reboot=False, realtime=True)
+
+ mock_invoke.assert_called_once_with(
+ mock.ANY, uris.DCIM_BIOSService, 'CreateTargetedConfigJob',
+ expected_selectors, expected_properties,
+ expected_return_value=utils.RET_CREATED,
+ wait_for_idrac=wait_for_idrac)
self.assertEqual('JID_442507917525', job_id)
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
diff --git a/dracclient/tests/test_lifecycle_controller.py b/dracclient/tests/test_lifecycle_controller.py
index 3427cc5..fac60f3 100644
--- a/dracclient/tests/test_lifecycle_controller.py
+++ b/dracclient/tests/test_lifecycle_controller.py
@@ -11,14 +11,20 @@
# License for the specific language governing permissions and limitations
# under the License.
+import lxml.etree
import mock
+import re
import requests_mock
import dracclient.client
+from dracclient import constants
+from dracclient import exceptions
+import dracclient.resources.job
from dracclient.resources import lifecycle_controller
from dracclient.resources import uris
from dracclient.tests import base
from dracclient.tests import utils as test_utils
+from dracclient import utils
class ClientLifecycleControllerManagementTestCase(base.BaseTest):
@@ -40,6 +46,7 @@ def test_get_lifecycle_controller_version(self, mock_requests):
self.assertEqual((2, 1, 0), version)
+@requests_mock.Mocker()
class ClientLCConfigurationTestCase(base.BaseTest):
def setUp(self):
@@ -47,12 +54,12 @@ def setUp(self):
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
- @requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
- def test_list_lifecycle_settings(self, mock_requests,
- mock_wait_until_idrac_is_ready):
+ def test_list_lifecycle_settings_by_instance_id(
+ self, mock_requests,
+ mock_wait_until_idrac_is_ready):
expected_enum_attr = lifecycle_controller.LCEnumerableAttribute(
name='Lifecycle Controller State',
instance_id='LifecycleController.Embedded.1#LCAttributes.1#LifecycleControllerState', # noqa
@@ -74,7 +81,8 @@ def test_list_lifecycle_settings(self, mock_requests,
{'text': test_utils.LifecycleControllerEnumerations[
uris.DCIM_LCString]['ok']}])
- lifecycle_settings = self.drac_client.list_lifecycle_settings()
+ lifecycle_settings = self.drac_client.list_lifecycle_settings(
+ by_name=False)
self.assertEqual(14, len(lifecycle_settings))
# enumerable attribute
@@ -89,3 +97,203 @@ def test_list_lifecycle_settings(self, mock_requests,
lifecycle_settings)
self.assertEqual(expected_string_attr,
lifecycle_settings['LifecycleController.Embedded.1#LCAttributes.1#SystemID']) # noqa
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_list_lifecycle_settings_by_name(
+ self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ expected_enum_attr = lifecycle_controller.LCEnumerableAttribute(
+ name='Lifecycle Controller State',
+ instance_id='LifecycleController.Embedded.1#LCAttributes.1#LifecycleControllerState', # noqa
+ read_only=False,
+ current_value='Enabled',
+ pending_value=None,
+ possible_values=['Disabled', 'Enabled', 'Recovery'])
+ expected_string_attr = lifecycle_controller.LCStringAttribute(
+ name='SYSID',
+ instance_id='LifecycleController.Embedded.1#LCAttributes.1#SystemID', # noqa
+ read_only=True,
+ current_value='639',
+ pending_value=None,
+ min_length=0,
+ max_length=3)
+
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCEnumeration]['ok']},
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCString]['ok']}])
+
+ lifecycle_settings = self.drac_client.list_lifecycle_settings(
+ by_name=True)
+
+ self.assertEqual(14, len(lifecycle_settings))
+ # enumerable attribute
+ self.assertIn(
+ 'Lifecycle Controller State',
+ lifecycle_settings)
+ self.assertEqual(expected_enum_attr, lifecycle_settings[
+ 'Lifecycle Controller State'])
+ # string attribute
+ self.assertIn(
+ 'SYSID',
+ lifecycle_settings)
+ self.assertEqual(expected_string_attr,
+ lifecycle_settings['SYSID'])
+
+ @mock.patch.object(dracclient.client.WSManClient, 'invoke',
+ spec_set=True, autospec=True)
+ def test_is_lifecycle_in_recovery(self, mock_requests,
+ mock_invoke):
+ expected_selectors = {'CreationClassName': 'DCIM_LCService',
+ 'SystemName': 'DCIM:ComputerSystem',
+ 'Name': 'DCIM:LCService',
+ 'SystemCreationClassName': 'DCIM_ComputerSystem'}
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.LifecycleControllerInvocations[uris.DCIM_LCService][
+ 'GetRemoteServicesAPIStatus']['is_recovery'])
+ result = self.drac_client.is_lifecycle_in_recovery()
+
+ mock_invoke.assert_called_once_with(
+ mock.ANY, uris.DCIM_LCService, 'GetRemoteServicesAPIStatus',
+ expected_selectors, {},
+ expected_return_value=utils.RET_SUCCESS,
+ wait_for_idrac=False)
+
+ self.assertEqual(True, result)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'invoke', spec_set=True,
+ autospec=True)
+ def test_set_lifecycle_settings(self, mock_requests,
+ mock_invoke):
+
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCEnumeration]['ok']},
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCString]['ok']}])
+
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.LifecycleControllerInvocations[uris.DCIM_LCService][
+ 'SetAttributes']['ok'])
+
+ result = self.drac_client.set_lifecycle_settings(
+ {'Collect System Inventory on Restart': 'Disabled'})
+
+ self.assertEqual({'is_commit_required': True,
+ 'is_reboot_required': constants.RebootRequired.false
+ },
+ result)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_set_lifecycle_settings_with_unknown_attr(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCEnumeration]['ok']},
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCString]['ok']},
+ {'text': test_utils.LifecycleControllerInvocations[
+ uris.DCIM_LCService]['SetAttributes']['error']}])
+
+ self.assertRaises(exceptions.InvalidParameterValue,
+ self.drac_client.set_lifecycle_settings,
+ {'foo': 'bar'})
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_set_lifecycle_settings_with_unchanged_attr(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCEnumeration]['ok']},
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCString]['ok']}])
+
+ result = self.drac_client.set_lifecycle_settings(
+ {'Lifecycle Controller State': 'Enabled'})
+
+ self.assertEqual({'is_commit_required': False,
+ 'is_reboot_required':
+ constants.RebootRequired.false},
+ result)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_set_lifecycle_settings_with_readonly_attr(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ expected_message = ("Cannot set read-only Lifecycle attributes: "
+ "['Licensed'].")
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCEnumeration]['ok']},
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCString]['ok']}])
+
+ self.assertRaisesRegexp(
+ exceptions.DRACOperationFailed, re.escape(expected_message),
+ self.drac_client.set_lifecycle_settings, {'Licensed': 'yes'})
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_set_lifecycle_settings_with_incorrect_enum_value(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ expected_message = ("Attribute 'Lifecycle Controller State' cannot "
+ "be set to value 'foo'. It must be in "
+ "['Disabled', 'Enabled', 'Recovery'].")
+
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCEnumeration]['ok']},
+ {'text': test_utils.LifecycleControllerEnumerations[
+ uris.DCIM_LCString]['ok']}])
+ self.assertRaisesRegexp(
+ exceptions.DRACOperationFailed, re.escape(expected_message),
+ self.drac_client.set_lifecycle_settings,
+ {'Lifecycle Controller State': 'foo'})
+
+
+class ClientLCChangesTestCase(base.BaseTest):
+
+ def setUp(self):
+ super(ClientLCChangesTestCase, self).setUp()
+ self.drac_client = dracclient.client.DRACClient(
+ **test_utils.FAKE_ENDPOINT)
+
+ @mock.patch.object(dracclient.resources.job.JobManagement,
+ 'create_config_job', spec_set=True, autospec=True)
+ def test_commit_pending_lifecycle_changes(self, mock_create_config_job):
+
+ self.drac_client.commit_pending_lifecycle_changes()
+
+ mock_create_config_job.assert_called_once_with(
+ mock.ANY, resource_uri=uris.DCIM_LCService,
+ cim_creation_class_name='DCIM_LCService',
+ cim_name='DCIM:LCService', target='',
+ reboot=False, start_time='TIME_NOW',
+ wait_for_idrac=False,
+ method_name='CreateConfigJob')
+
+ @mock.patch.object(dracclient.resources.job.JobManagement,
+ 'create_config_job', spec_set=True, autospec=True)
+ def test_commit_pending_lifecycle_changes_with_time(
+ self, mock_create_config_job):
+ timestamp = '20140924140201'
+ self.drac_client.commit_pending_lifecycle_changes(
+ start_time=timestamp)
+
+ mock_create_config_job.assert_called_once_with(
+ mock.ANY, resource_uri=uris.DCIM_LCService,
+ cim_creation_class_name='DCIM_LCService',
+ cim_name='DCIM:LCService', target='',
+ reboot=False, start_time=timestamp,
+ wait_for_idrac=False,
+ method_name='CreateConfigJob')
diff --git a/dracclient/tests/test_nic.py b/dracclient/tests/test_nic.py
index e393d5c..7029df3 100644
--- a/dracclient/tests/test_nic.py
+++ b/dracclient/tests/test_nic.py
@@ -214,7 +214,8 @@ def test_set_nic_settings(self, mock_requests, mock_invoke,
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_NICService, 'SetAttributes',
- expected_selectors, expected_properties)
+ expected_selectors, expected_properties,
+ wait_for_idrac=True)
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True)
@@ -250,7 +251,8 @@ def test_set_nic_settings_string(self, mock_requests, mock_invoke,
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_NICService, 'SetAttributes',
- expected_selectors, expected_properties)
+ expected_selectors, expected_properties,
+ wait_for_idrac=True)
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True)
@@ -286,7 +288,8 @@ def test_set_nic_settings_integer(self, mock_requests, mock_invoke,
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_NICService, 'SetAttributes',
- expected_selectors, expected_properties)
+ expected_selectors, expected_properties,
+ wait_for_idrac=True)
def test_set_nic_settings_error(self, mock_requests,
mock_wait_until_idrac_is_ready):
diff --git a/dracclient/tests/test_raid.py b/dracclient/tests/test_raid.py
index 5fbf60c..fccfc60 100644
--- a/dracclient/tests/test_raid.py
+++ b/dracclient/tests/test_raid.py
@@ -16,6 +16,7 @@
import lxml.etree
import mock
import random
+import re
import requests_mock
import dracclient.client
@@ -37,6 +38,7 @@ def setUp(self):
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
self.raid_controller_fqdd = "RAID.Integrated.1-1"
+ self.boss_controller_fqdd = "AHCI.Slot.3-1"
cntl_dict = {'RAID.Integrated.1-1':
['Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1',
'Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1'],
@@ -59,7 +61,8 @@ def setUp(self):
status='ok',
raid_status='ready',
sas_address='500056B37789ABE3',
- device_protocol=None)
+ device_protocol=None,
+ bus=None)
self.disk_2 = raid.PhysicalDisk(
id='Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1',
@@ -76,7 +79,8 @@ def setUp(self):
status='online',
raid_status='ready',
sas_address='500056B37789ABE3',
- device_protocol=None)
+ device_protocol=None,
+ bus=None)
self.disk_3 = raid.PhysicalDisk(
id='Disk.Bay.0:Enclosure.Internal.0-1:AHCI.Integrated.1-1',
@@ -93,7 +97,8 @@ def setUp(self):
status='online',
raid_status='ready',
sas_address='500056B37789ABE3',
- device_protocol=None)
+ device_protocol=None,
+ bus=None)
self.disk_4 = raid.PhysicalDisk(
id='Disk.Bay.1:Enclosure.Internal.0-1:AHCI.Integrated.1-1',
@@ -110,7 +115,185 @@ def setUp(self):
status='online',
raid_status='ready',
sas_address='500056B37789ABE3',
- device_protocol=None)
+ device_protocol=None,
+ bus=None)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_list_raid_settings(self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ expected_enum_attr = raid.RAIDEnumerableAttribute(
+ name='RAIDCurrentControllerMode',
+ instance_id='RAID.Integrated.1-1:RAIDCurrentControllerMode', # noqa
+ current_value=['RAID'],
+ pending_value=None,
+ read_only=True,
+ fqdd='RAID.Integrated.1-1',
+ possible_values=['RAID', 'Enhanced HBA'])
+ expected_string_attr = raid.RAIDStringAttribute(
+ name='Name',
+ instance_id='Disk.Virtual.1:RAID.Integrated.1-1:Name', # noqa
+ current_value='Virtual Disk 1',
+ pending_value=None,
+ read_only=True,
+ fqdd='Disk.Virtual.1:RAID.Integrated.1-1',
+ min_length=0,
+ max_length=129)
+ expected_integer_attr = raid.RAIDIntegerAttribute(
+ name='RAIDmaxSupportedVD',
+ instance_id='RAID.Integrated.1-1:RAIDmaxSupportedVD', # noqa
+ current_value=240,
+ pending_value=None,
+ read_only=True,
+ fqdd='RAID.Integrated.1-1',
+ lower_bound=0,
+ upper_bound=0)
+ # expected_string_attr
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDEnumeration]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDString]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDInteger]['ok']}
+ ])
+
+ raid_settings = self.drac_client.list_raid_settings()
+ self.assertEqual(219, len(raid_settings))
+ # enumerable attribute
+ self.assertIn(
+ 'RAID.Integrated.1-1:RAIDCurrentControllerMode', # noqa
+ raid_settings)
+ self.assertEqual(expected_enum_attr.fqdd, raid_settings[
+ 'RAID.Integrated.1-1:RAIDCurrentControllerMode'].fqdd) # noqa
+ # string attribute
+ self.assertIn(
+ 'Disk.Virtual.1:RAID.Integrated.1-1:Name', # noqa
+ raid_settings)
+ self.assertEqual(expected_string_attr.fqdd,
+ raid_settings['Disk.Virtual.1:RAID.Integrated.1-1:Name'].fqdd) # noqa
+ # integer attribute
+ self.assertIn(
+ 'RAID.Integrated.1-1:RAIDmaxSupportedVD', # noqa
+ raid_settings)
+ self.assertEqual(expected_integer_attr.fqdd, raid_settings[
+ 'RAID.Integrated.1-1:RAIDmaxSupportedVD'].fqdd) # noqa
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'invoke', spec_set=True,
+ autospec=True)
+ def test_set_raid_settings(self, mock_requests,
+ mock_invoke,
+ mock_wait_until_idrac_is_ready):
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDEnumeration]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDString]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDInteger]['ok']}])
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.RAIDInvocations[uris.DCIM_RAIDService][
+ 'SetAttributes']['ok'])
+
+ result = self.drac_client.set_raid_settings(
+ self.raid_controller_fqdd,
+ {'RAID.Integrated.1-1:RAIDRequestedControllerMode': 'RAID'})
+
+ self.assertEqual({'is_commit_required': True,
+ 'is_reboot_required': constants.RebootRequired.true
+ },
+ result)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_set_raid_settings_with_unknown_attr(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDEnumeration]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDString]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDInteger]['ok']},
+ {'text': test_utils.RAIDInvocations[
+ uris.DCIM_RAIDService]['SetAttributes']['error']}])
+
+ self.assertRaises(exceptions.InvalidParameterValue,
+ self.drac_client.set_raid_settings,
+ self.raid_controller_fqdd, {'foo': 'bar'})
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_set_raid_settings_with_unchanged_attr(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDEnumeration]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDString]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDInteger]['ok']}])
+ attrKey = 'Disk.Virtual.1:RAID.Integrated.1-1:RAIDdefaultWritePolicy'
+ result = self.drac_client.set_raid_settings(
+ self.raid_controller_fqdd,
+ {attrKey: 'WriteBack'})
+
+ self.assertEqual({'is_commit_required': False,
+ 'is_reboot_required':
+ constants.RebootRequired.false},
+ result)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_set_raid_settings_with_readonly_attr(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ expected_message = (
+ "Cannot set read-only RAID attributes: "
+ "['RAID.Integrated.1-1:RAIDCurrentControllerMode']."
+ )
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDEnumeration]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDString]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDInteger]['ok']}])
+
+ self.assertRaisesRegexp(
+ exceptions.DRACOperationFailed, re.escape(expected_message),
+ self.drac_client.set_raid_settings,
+ self.raid_controller_fqdd,
+ {'RAID.Integrated.1-1:RAIDCurrentControllerMode': 'Enhanced HBA'})
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_set_raid_settings_with_incorrect_enum_value(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ expected_message = ("Attribute 'RAIDRequestedControllerMode' cannot "
+ "be set to value 'foo'. It must be in "
+ "['RAID', 'Enhanced HBA', 'None'].")
+
+ mock_requests.post('https://1.2.3.4:443/wsman', [
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDEnumeration]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDString]['ok']},
+ {'text': test_utils.RAIDEnumerations[
+ uris.DCIM_RAIDInteger]['ok']}])
+ self.assertRaisesRegexp(
+ exceptions.DRACOperationFailed, re.escape(expected_message),
+ self.drac_client.set_raid_settings,
+ self.raid_controller_fqdd,
+ {'RAID.Integrated.1-1:RAIDRequestedControllerMode': 'foo'})
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
@@ -124,8 +307,8 @@ def test_list_raid_controllers(self, mock_requests,
model='PERC H710 Mini',
primary_status='ok',
firmware_version='21.3.0-0009',
- bus='1')
-
+ bus='1',
+ supports_realtime=True)
mock_requests.post(
'https://1.2.3.4:443/wsman',
text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok'])
@@ -162,6 +345,36 @@ def test_list_virtual_disks(self, mock_requests,
self.assertIn(expected_virtual_disk,
self.drac_client.list_virtual_disks())
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_list_virtual_disks_with_raid_status_change(
+ self, mock_requests, mock_wait_until_idrac_is_ready):
+ expected_virtual_disk = raid.VirtualDisk(
+ id='Disk.Virtual.0:RAID.Integrated.1-1',
+ name='disk 0',
+ description='Virtual Disk 0 on Integrated RAID Controller 1',
+ controller='RAID.Integrated.1-1',
+ raid_level='1',
+ size_mb=571776,
+ status='ok',
+ raid_status='online',
+ span_depth=1,
+ span_length=2,
+ pending_operations=None,
+ physical_disks=[
+ 'Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1',
+ 'Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1'
+ ])
+
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDEnumerations[
+ uris.DCIM_VirtualDiskView]['Raid_Status_ok'])
+
+ self.assertIn(expected_virtual_disk,
+ self.drac_client.list_virtual_disks())
+
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
@@ -183,7 +396,8 @@ def test_list_physical_disks(self, mock_requests,
status='ok',
raid_status='ready',
sas_address='5000C5007764F409',
- device_protocol=None)
+ device_protocol=None,
+ bus=None)
mock_requests.post(
'https://1.2.3.4:443/wsman',
@@ -213,7 +427,8 @@ def test_list_physical_disks_direct(self, mock_requests,
status='ok',
raid_status='ready',
sas_address='5000C5007764F409',
- device_protocol=None)
+ device_protocol=None,
+ bus=None)
mock_requests.post(
'https://1.2.3.4:443/wsman',
@@ -242,7 +457,8 @@ def test_list_physical_disks_nvme(self, mock_requests,
status='unknown',
raid_status=None,
sas_address=None,
- device_protocol='NVMe-MI1.0')
+ device_protocol='NVMe-MI1.0',
+ bus='3E')
mock_requests.post(
'https://1.2.3.4:443/wsman',
@@ -593,29 +809,157 @@ def test_delete_virtual_disk_fail(self, mock_requests,
exceptions.DRACOperationFailed,
self.drac_client.delete_virtual_disk, 'disk1')
+ @mock.patch.object(dracclient.client.WSManClient, 'invoke',
+ spec_set=True, autospec=True)
+ def test_reset_raid_config(self, mock_requests, mock_invoke):
+ expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
+ 'CreationClassName': 'DCIM_RAIDService',
+ 'SystemName': 'DCIM:ComputerSystem',
+ 'Name': 'DCIM:RAIDService'}
+ expected_properties = {'Target': self.raid_controller_fqdd}
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.RAIDInvocations[uris.DCIM_RAIDService][
+ 'ResetConfig']['ok'])
+ result = self.drac_client.reset_raid_config(self.raid_controller_fqdd)
+ self.assertEqual({'is_commit_required': True,
+ 'is_reboot_required':
+ constants.RebootRequired.optional},
+ result)
+ mock_invoke.assert_called_once_with(
+ mock.ANY, uris.DCIM_RAIDService, 'ResetConfig',
+ expected_selectors, expected_properties,
+ expected_return_value=utils.RET_SUCCESS)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_reset_raid_config_fail(self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDInvocations[
+ uris.DCIM_RAIDService]['ResetConfig']['error'])
+
+ self.assertRaises(
+ exceptions.DRACOperationFailed,
+ self.drac_client.reset_raid_config, self.raid_controller_fqdd)
+
+ @mock.patch.object(dracclient.client.WSManClient, 'invoke',
+ spec_set=True, autospec=True)
+ def test_clear_foreign_config(self, mock_requests, mock_invoke):
+ expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
+ 'CreationClassName': 'DCIM_RAIDService',
+ 'SystemName': 'DCIM:ComputerSystem',
+ 'Name': 'DCIM:RAIDService'}
+ expected_properties = {'Target': self.raid_controller_fqdd}
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.RAIDInvocations[uris.DCIM_RAIDService][
+ 'ClearForeignConfig']['ok'])
+
+ result = self.drac_client.clear_foreign_config(
+ self.raid_controller_fqdd)
+ self.assertEqual({'is_commit_required': True,
+ 'is_reboot_required':
+ constants.RebootRequired.optional},
+ result)
+ mock_invoke.assert_called_once_with(
+ mock.ANY, uris.DCIM_RAIDService, 'ClearForeignConfig',
+ expected_selectors, expected_properties,
+ check_return_value=False)
+
+ @mock.patch.object(dracclient.client.WSManClient, 'invoke',
+ spec_set=True, autospec=True)
+ def test_clear_foreign_config_with_no_foreign_drive(self,
+ mock_requests,
+ mock_invoke):
+ expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
+ 'CreationClassName': 'DCIM_RAIDService',
+ 'SystemName': 'DCIM:ComputerSystem',
+ 'Name': 'DCIM:RAIDService'}
+ expected_properties = {'Target': self.raid_controller_fqdd}
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.RAIDInvocations[uris.DCIM_RAIDService][
+ 'ClearForeignConfig']['no_foreign_drive'])
+
+ result = self.drac_client.clear_foreign_config(
+ self.raid_controller_fqdd)
+ self.assertEqual({'is_commit_required': False,
+ 'is_reboot_required':
+ constants.RebootRequired.false},
+ result)
+ mock_invoke.assert_called_once_with(
+ mock.ANY, uris.DCIM_RAIDService, 'ClearForeignConfig',
+ expected_selectors, expected_properties,
+ check_return_value=False)
+
+ @mock.patch.object(dracclient.client.WSManClient, 'invoke',
+ spec_set=True, autospec=True)
+ def test_clear_foreign_config_with_operation_not_supported(self,
+ mock_requests,
+ mock_invoke):
+ expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
+ 'CreationClassName': 'DCIM_RAIDService',
+ 'SystemName': 'DCIM:ComputerSystem',
+ 'Name': 'DCIM:RAIDService'}
+ expected_properties = {'Target': self.boss_controller_fqdd}
+ mock_invoke.return_value = lxml.etree.fromstring(
+ test_utils.RAIDInvocations[uris.DCIM_RAIDService][
+ 'ClearForeignConfig']['foreign_drive_operation_not_supported'])
+
+ result = self.drac_client.clear_foreign_config(
+ self.boss_controller_fqdd)
+ self.assertEqual({'is_commit_required': False,
+ 'is_reboot_required':
+ constants.RebootRequired.false},
+ result)
+ mock_invoke.assert_called_once_with(
+ mock.ANY, uris.DCIM_RAIDService, 'ClearForeignConfig',
+ expected_selectors, expected_properties,
+ check_return_value=False)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_clear_foreign_config_with_invalid_controller_id(
+ self,
+ mock_requests,
+ mock_wait_until_idrac_is_ready):
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDInvocations[
+ uris.DCIM_RAIDService]['ClearForeignConfig']
+ ['invalid_controller_id'])
+
+ self.assertRaises(
+ exceptions.DRACOperationFailed,
+ self.drac_client.clear_foreign_config, 'bad')
+
@mock.patch.object(dracclient.resources.job.JobManagement,
'create_config_job', spec_set=True, autospec=True)
def test_commit_pending_raid_changes(self, mock_requests,
mock_create_config_job):
- self.drac_client.commit_pending_raid_changes('controller')
+ self.drac_client.commit_pending_raid_changes('controller',
+ realtime=False)
mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller', reboot=False,
- start_time='TIME_NOW')
+ start_time='TIME_NOW', realtime=False)
@mock.patch.object(dracclient.resources.job.JobManagement,
'create_config_job', spec_set=True, autospec=True)
def test_commit_pending_raid_changes_with_reboot(self, mock_requests,
mock_create_config_job):
- self.drac_client.commit_pending_raid_changes('controller', reboot=True)
+ self.drac_client.commit_pending_raid_changes('controller',
+ reboot=True,
+ realtime=False)
mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller', reboot=True,
- start_time='TIME_NOW')
+ start_time='TIME_NOW', realtime=False)
@mock.patch.object(dracclient.resources.job.JobManagement,
'create_config_job', spec_set=True, autospec=True)
@@ -624,13 +968,14 @@ def test_commit_pending_raid_changes_with_start_time(
mock_create_config_job):
timestamp = '20140924140201'
self.drac_client.commit_pending_raid_changes('controller',
- start_time=timestamp)
+ start_time=timestamp,
+ realtime=False)
mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller', reboot=False,
- start_time=timestamp)
+ start_time=timestamp, realtime=False)
@mock.patch.object(dracclient.resources.job.JobManagement,
'create_config_job', spec_set=True, autospec=True)
@@ -640,13 +985,31 @@ def test_commit_pending_raid_changes_with_reboot_and_start_time(
timestamp = '20140924140201'
self.drac_client.commit_pending_raid_changes('controller',
reboot=True,
- start_time=timestamp)
+ start_time=timestamp,
+ realtime=False)
mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller', reboot=True,
- start_time=timestamp)
+ start_time=timestamp, realtime=False)
+
+ @mock.patch.object(dracclient.resources.job.JobManagement,
+ 'create_config_job', spec_set=True, autospec=True)
+ def test_commit_pending_raid_changes_with_realtime(
+ self, mock_requests,
+ mock_create_config_job):
+ timestamp = '20140924140201'
+ self.drac_client.commit_pending_raid_changes('controller',
+ reboot=False,
+ start_time=timestamp,
+ realtime=True)
+
+ mock_create_config_job.assert_called_once_with(
+ mock.ANY, resource_uri=uris.DCIM_RAIDService,
+ cim_creation_class_name='DCIM_RAIDService',
+ cim_name='DCIM:RAIDService', target='controller', reboot=False,
+ start_time=timestamp, realtime=True)
@mock.patch.object(dracclient.resources.job.JobManagement,
'delete_pending_config', spec_set=True, autospec=True)
@@ -659,6 +1022,17 @@ def test_abandon_pending_raid_changes(self, mock_requests,
cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller')
+ @mock.patch.object(dracclient.resources.job.JobManagement,
+ 'delete_pending_config', spec_set=True, autospec=True)
+ def test_abandon_pending_raid_changes_realtime(self, mock_requests,
+ mock_delete_pending_config):
+ self.drac_client.abandon_pending_raid_changes('controller')
+
+ mock_delete_pending_config.assert_called_once_with(
+ mock.ANY, resource_uri=uris.DCIM_RAIDService,
+ cim_creation_class_name='DCIM_RAIDService',
+ cim_name='DCIM:RAIDService', target='controller')
+
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
@@ -773,17 +1147,67 @@ def test_raid_controller_jbod_ex_no_match(self,
exceptions.DRACOperationFailed,
self.drac_client.is_jbod_capable, self.raid_controller_fqdd)
- def test_is_raid_controller(self, mock_requests):
+ def test_is_raid_controller_raid(self, mock_requests):
self.assertTrue(self.drac_client
.is_raid_controller("RAID.Integrated.1-1"))
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_is_raid_controller_boss(self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok'])
+ self.assertTrue(self.drac_client
+ .is_raid_controller("AHCI.Integrated.1-1"))
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_is_raid_controller_fail(self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok'])
self.assertFalse(self.drac_client
.is_raid_controller("notRAID.Integrated.1-1"))
- def test_is_boss_controller(self, mock_requests):
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_is_boss_controller(self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok'])
self.assertTrue(self.drac_client
.is_boss_controller("AHCI.Integrated.1-1"))
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_is_not_boss_controller(self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok'])
self.assertFalse(self.drac_client
- .is_boss_controller("notAHCI.Integrated.1-1"))
+ .is_boss_controller("notAHCI.Integrated.1-1"),
+ None)
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
+ autospec=True)
+ def test_is_boss_controller_with_cntl_list(self, mock_requests,
+ mock_wait_until_idrac_is_ready):
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok'])
+ controllers = self.drac_client.list_raid_controllers()
+ self.assertTrue(self.drac_client
+ .is_boss_controller("AHCI.Integrated.1-1",
+ controllers))
def test_check_disks_status_no_controllers(self, mock_requests):
physical_disks = [self.disk_1, self.disk_2, self.disk_3, self.disk_4]
@@ -815,13 +1239,13 @@ def test_check_disks_status_bad(self, mock_requests):
raid_mgt._check_disks_status,
mode,
physical_disks,
- self.controllers_to_physical_disk_ids.copy())
+ self.controllers_to_physical_disk_ids)
mode = constants.RaidStatus.jbod
self.assertRaises(ValueError,
raid_mgt._check_disks_status,
mode,
physical_disks,
- self.controllers_to_physical_disk_ids.copy())
+ self.controllers_to_physical_disk_ids)
def test_check_disks_status_fail(self, mock_requests):
mode = constants.RaidStatus.raid
@@ -833,13 +1257,13 @@ def test_check_disks_status_fail(self, mock_requests):
raid_mgt._check_disks_status,
mode,
physical_disks,
- self.controllers_to_physical_disk_ids.copy())
+ self.controllers_to_physical_disk_ids)
mode = constants.RaidStatus.jbod
self.assertRaises(ValueError,
raid_mgt._check_disks_status,
mode,
physical_disks,
- self.controllers_to_physical_disk_ids.copy())
+ self.controllers_to_physical_disk_ids)
def test_check_disks_status_no_change(self, mock_requests):
raid_mgt = self.drac_client._raid_mgmt
@@ -847,11 +1271,8 @@ def test_check_disks_status_no_change(self, mock_requests):
physical_disks = [self.disk_1, self.disk_2,
self.disk_3, self.disk_4]
- raid_cntl_to_phys_disk_ids = (self.controllers_to_physical_disk_ids.
- copy())
-
- raid_mgt._check_disks_status(mode, physical_disks,
- raid_cntl_to_phys_disk_ids)
+ raid_cntl_to_phys_disk_ids = raid_mgt._check_disks_status(
+ mode, physical_disks, self.controllers_to_physical_disk_ids)
raid_len = len(raid_cntl_to_phys_disk_ids['RAID.Integrated.1-1'])
self.assertEqual(raid_len, 0)
@@ -861,10 +1282,8 @@ def test_check_disks_status_no_change(self, mock_requests):
physical_disks = [disk_1_non_raid, disk_2_non_raid,
self.disk_3, self.disk_4]
- jbod_cntl_to_phys_disk_ids = (self.controllers_to_physical_disk_ids.
- copy())
- raid_mgt._check_disks_status(mode, physical_disks,
- jbod_cntl_to_phys_disk_ids)
+ jbod_cntl_to_phys_disk_ids = raid_mgt._check_disks_status(
+ mode, physical_disks, self.controllers_to_physical_disk_ids)
jbod_len = len(jbod_cntl_to_phys_disk_ids['RAID.Integrated.1-1'])
self.assertEqual(jbod_len, 0)
@@ -873,11 +1292,8 @@ def test_check_disks_status_change_state(self, mock_requests):
mode = constants.RaidStatus.jbod
physical_disks = [self.disk_1, self.disk_2, self.disk_3, self.disk_4]
- jbod_cntl_to_phys_disk_ids = (self.controllers_to_physical_disk_ids.
- copy())
-
- raid_mgt._check_disks_status(mode, physical_disks,
- jbod_cntl_to_phys_disk_ids)
+ jbod_cntl_to_phys_disk_ids = raid_mgt._check_disks_status(
+ mode, physical_disks, self.controllers_to_physical_disk_ids)
jbod_len = len(jbod_cntl_to_phys_disk_ids['RAID.Integrated.1-1'])
self.assertEqual(jbod_len, 2)
@@ -886,10 +1302,8 @@ def test_check_disks_status_change_state(self, mock_requests):
disk_2_non_raid = self.disk_2._replace(raid_status='non-RAID')
physical_disks = [disk_1_non_raid, disk_2_non_raid,
self.disk_3, self.disk_4]
- raid_cntl_to_phys_disk_ids = (self.controllers_to_physical_disk_ids.
- copy())
- raid_mgt._check_disks_status(mode, physical_disks,
- raid_cntl_to_phys_disk_ids)
+ raid_cntl_to_phys_disk_ids = raid_mgt._check_disks_status(
+ mode, physical_disks, self.controllers_to_physical_disk_ids)
raid_len = len(raid_cntl_to_phys_disk_ids['RAID.Integrated.1-1'])
self.assertEqual(raid_len, 2)
@@ -904,13 +1318,13 @@ def test_check_disks_status_bad_and_fail(self, mock_requests):
raid_mgt._check_disks_status,
mode,
physical_disks,
- self.controllers_to_physical_disk_ids.copy())
+ self.controllers_to_physical_disk_ids)
mode = constants.RaidStatus.jbod
self.assertRaises(ValueError,
raid_mgt._check_disks_status,
mode,
physical_disks,
- self.controllers_to_physical_disk_ids.copy())
+ self.controllers_to_physical_disk_ids)
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
@@ -926,16 +1340,22 @@ def test_change_physical_disk_state_jbod(
mock_requests.post(
'https://1.2.3.4:443/wsman',
text=test_utils.RAIDEnumerations[uris.DCIM_PhysicalDiskView]['ok'])
- mock_convert_physical_disks.return_value = {'commit_required': True,
- 'is_commit_required': True,
- 'is_reboot_required':
- constants.RebootRequired
- .true}
- cntl_to_phys_d_ids = self.controllers_to_physical_disk_ids
+ cvt_phys_disks_return_value = {'commit_required': True,
+ 'is_commit_required': True,
+ 'is_reboot_required': constants.
+ RebootRequired.true}
+ mock_convert_physical_disks.return_value = cvt_phys_disks_return_value
+
+ expected_return_value = {'RAID.Integrated.1-1':
+ cvt_phys_disks_return_value,
+ 'AHCI.Integrated.1-1':
+ cvt_phys_disks_return_value}
results = self.drac_client.change_physical_disk_state(
- mode, cntl_to_phys_d_ids)
+ mode, self.controllers_to_physical_disk_ids)
self.assertTrue(results["is_reboot_required"])
self.assertEqual(len(results["commit_required_ids"]), 2)
+ self.assertEqual(results['conversion_results'],
+ expected_return_value)
@mock.patch.object(dracclient.resources.raid.RAIDManagement,
'list_physical_disks', spec_set=True,
@@ -953,40 +1373,44 @@ def test_change_physical_disk_state_raid(
physical_disks = [disk_1_non_raid, disk_2_non_raid,
self.disk_3, self.disk_4]
mock_list_physical_disks.return_value = physical_disks
- mock_convert_physical_disks.return_value = {'commit_required': True,
- 'is_commit_required': True,
- 'is_reboot_required':
- constants.RebootRequired
- .true}
- cntl_to_phys_d_ids = self.controllers_to_physical_disk_ids
+ boss_return_value = {'is_commit_required': False,
+ 'is_reboot_required':
+ constants.RebootRequired.false}
+ raid_return_value = {'is_commit_required': True,
+ 'is_reboot_required':
+ constants.RebootRequired.true}
+ mock_convert_physical_disks.return_value = raid_return_value
+
results = self.drac_client.change_physical_disk_state(
- mode, cntl_to_phys_d_ids)
+ mode, self.controllers_to_physical_disk_ids)
self.assertTrue(results["is_reboot_required"])
self.assertEqual(len(results["commit_required_ids"]), 1)
+ self.assertEqual(len(results['conversion_results']), 2)
+ self.assertEqual(results['conversion_results']['AHCI.Integrated.1-1'],
+ boss_return_value)
+ self.assertEqual(results['conversion_results']['RAID.Integrated.1-1'],
+ raid_return_value)
@mock.patch.object(dracclient.resources.raid.RAIDManagement,
'list_physical_disks', spec_set=True,
autospec=True)
- @mock.patch.object(dracclient.resources.raid.RAIDManagement,
- 'convert_physical_disks', spec_set=True,
- autospec=True)
def test_change_physical_disk_state_none(
self, mock_requests,
- mock_convert_physical_disks,
mock_list_physical_disks):
mode = constants.RaidStatus.raid
physical_disks = [self.disk_1, self.disk_2, self.disk_3, self.disk_4]
- mock_convert_physical_disks.return_value = {'commit_required': True,
- 'is_commit_required': True,
- 'is_reboot_required':
- constants.RebootRequired
- .true}
mock_list_physical_disks.return_value = physical_disks
- cntl_to_phys_d_ids = self.controllers_to_physical_disk_ids
+ expected_return_value = {'is_commit_required': False,
+ 'is_reboot_required':
+ constants.RebootRequired.false}
results = self.drac_client.change_physical_disk_state(
- mode, cntl_to_phys_d_ids)
+ mode, self.controllers_to_physical_disk_ids)
self.assertFalse(results["is_reboot_required"])
self.assertEqual(len(results["commit_required_ids"]), 0)
+ self.assertEqual(results['conversion_results']['RAID.Integrated.1-1'],
+ expected_return_value)
+ self.assertEqual(results['conversion_results']['AHCI.Integrated.1-1'],
+ expected_return_value)
@mock.patch.object(dracclient.resources.raid.RAIDManagement,
'list_physical_disks', spec_set=True,
@@ -1006,11 +1430,17 @@ def test_change_physical_disk_state_not_supported(
physical_disks = [disk_1_non_raid, disk_2_non_raid,
self.disk_3, self.disk_4]
mock_list_physical_disks.return_value = physical_disks
- cntl_to_phys_d_ids = self.controllers_to_physical_disk_ids
+ expected_return_value = {'is_commit_required': False,
+ 'is_reboot_required':
+ constants.RebootRequired.false}
results = self.drac_client.change_physical_disk_state(
- mode, cntl_to_phys_d_ids)
+ mode, self.controllers_to_physical_disk_ids)
self.assertFalse(results["is_reboot_required"])
self.assertEqual(len(results["commit_required_ids"]), 0)
+ self.assertEqual(results['conversion_results']['RAID.Integrated.1-1'],
+ expected_return_value)
+ self.assertEqual(results['conversion_results']['AHCI.Integrated.1-1'],
+ expected_return_value)
@mock.patch.object(dracclient.resources.raid.RAIDManagement,
'list_physical_disks', spec_set=True,
@@ -1030,12 +1460,12 @@ def test_change_physical_disk_state_raise_drac_operation_other(
physical_disks = [disk_1_non_raid, disk_2_non_raid,
self.disk_3, self.disk_4]
mock_list_physical_disks.return_value = physical_disks
- cntl_to_phys_d_ids = self.controllers_to_physical_disk_ids
self.assertRaisesRegexp(
exceptions.DRACOperationFailed,
"OTHER_MESSAGE",
self.drac_client.change_physical_disk_state,
- mode, cntl_to_phys_d_ids)
+ mode,
+ self.controllers_to_physical_disk_ids)
@mock.patch.object(dracclient.resources.raid.RAIDManagement,
'list_physical_disks', spec_set=True,
@@ -1054,11 +1484,12 @@ def test_change_physical_disk_state_raise_other(
physical_disks = [disk_1_non_raid, disk_2_non_raid,
self.disk_3, self.disk_4]
mock_list_physical_disks.return_value = physical_disks
- cntl_to_phys_d_ids = self.controllers_to_physical_disk_ids
self.assertRaisesRegexp(
- Exception, "SOMETHING_BAD_HAPPENED",
+ Exception,
+ "SOMETHING_BAD_HAPPENED",
self.drac_client.change_physical_disk_state,
- mode, cntl_to_phys_d_ids)
+ mode,
+ self.controllers_to_physical_disk_ids)
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
@@ -1116,40 +1547,31 @@ def test_change_physical_disk_state_with_no_raid_or_boss_card_match(
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
- @mock.patch.object(dracclient.resources.raid.RAIDManagement,
- 'list_physical_disks', spec_set=True,
- autospec=True)
- @mock.patch.object(dracclient.resources.raid.RAIDManagement,
- 'convert_physical_disks', spec_set=True,
+ def test_is_realtime_supported_with_realtime_controller(
+ self,
+ mock_requests,
+ mock_wait_until_idrac_is_ready):
+ expected_raid_controller = 'RAID.Integrated.1-1'
+
+ mock_requests.post(
+ 'https://1.2.3.4:443/wsman',
+ text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok'])
+
+ self.assertTrue(
+ self.drac_client.is_realtime_supported(expected_raid_controller))
+
+ @mock.patch.object(dracclient.client.WSManClient,
+ 'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
- def test_change_physical_disk_state_conversion_return_values(
- self, mock_requests,
- mock_convert_physical_disks,
- mock_list_physical_disks,
+ def test_is_realtime_supported_with_non_realtime_controller(
+ self,
+ mock_requests,
mock_wait_until_idrac_is_ready):
+ expected_raid_controller = 'AHCI.Integrated.1-1'
+
mock_requests.post(
'https://1.2.3.4:443/wsman',
text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok'])
- mode = constants.RaidStatus.jbod
- physical_disks = [self.disk_1, self.disk_2, self.disk_3, self.disk_4]
- '''Test all logic branches for 100% coverage, it is unlikely
- convert_physical_disks() will return empty dict but we do check
- for this case in change_physical_disk_state()'''
- mock_convert_physical_disks.return_value = {}
- mock_list_physical_disks.return_value = physical_disks
- results = self.drac_client.change_physical_disk_state(mode)
- self.assertFalse(results["is_reboot_required"])
- self.assertEqual(len(results["commit_required_ids"]), 0)
- '''Where convert_physical_disks() does not require a commit after
- executing, unlikely case but provides 100% code coverage of all
- logic branches.'''
- mock_convert_physical_disks.return_value = {'commit_required':
- True,
- 'is_commit_required':
- False,
- 'is_reboot_required':
- constants.RebootRequired
- .false}
- results = self.drac_client.change_physical_disk_state(mode)
- self.assertFalse(results["is_reboot_required"])
- self.assertEqual(len(results["commit_required_ids"]), 0)
+
+ self.assertFalse(
+ self.drac_client.is_realtime_supported(expected_raid_controller))
diff --git a/dracclient/tests/utils.py b/dracclient/tests/utils.py
index 0336119..4e4ee11 100644
--- a/dracclient/tests/utils.py
+++ b/dracclient/tests/utils.py
@@ -133,6 +133,14 @@ def load_wsman_xml(name):
'error': load_wsman_xml(
'bios_service-invoke-delete_pending_configuration-error'),
},
+ },
+ uris.DCIM_LCService: {
+ 'CreateConfigJob': {
+ 'ok': load_wsman_xml(
+ 'lc_service-invoke-create_config_job-ok'),
+ 'error': load_wsman_xml(
+ 'lc_service-invoke-create_config_job-error'),
+ },
}
}
@@ -192,7 +200,15 @@ def load_wsman_xml(name):
'GetRemoteServicesAPIStatus': {
'is_ready': load_wsman_xml('lc_getremoteservicesapistatus_ready'),
'is_not_ready': load_wsman_xml(
- 'lc_getremoteservicesapistatus_not_ready')
+ 'lc_getremoteservicesapistatus_not_ready'),
+ 'is_recovery': load_wsman_xml(
+ 'lc_getremoteservicesapistatus_recovery'),
+ },
+ 'SetAttributes': {
+ 'ok': load_wsman_xml(
+ 'lc_service-invoke-set_attributes-ok'),
+ 'error': load_wsman_xml(
+ 'lc_service-invoke-set_attributes-error'),
}
}
}
@@ -230,7 +246,18 @@ def load_wsman_xml(name):
'ok': load_wsman_xml('physical_disk_view-enum-ok')
},
uris.DCIM_VirtualDiskView: {
+ 'Raid_Status_ok': load_wsman_xml(
+ 'virtual_disk_view-enum-with-raid-status-ok'),
'ok': load_wsman_xml('virtual_disk_view-enum-ok')
+ },
+ uris.DCIM_RAIDEnumeration: {
+ 'ok': load_wsman_xml('raid_enumeration-enum-ok')
+ },
+ uris.DCIM_RAIDString: {
+ 'ok': load_wsman_xml('raid_string-enum-ok')
+ },
+ uris.DCIM_RAIDInteger: {
+ 'ok': load_wsman_xml('raid_integer-enum-ok')
}
}
@@ -253,6 +280,28 @@ def load_wsman_xml(name):
'raid_service-invoke-convert_physical_disks-ok'),
'error': load_wsman_xml(
'raid_service-invoke-convert_physical_disks-error'),
+ },
+ 'ResetConfig': {
+ 'ok': load_wsman_xml(
+ 'raid_service-invoke-reset_raid_config-ok'),
+ 'error': load_wsman_xml(
+ 'raid_service-invoke-reset_raid_config-error'),
+ },
+ 'ClearForeignConfig': {
+ 'ok': load_wsman_xml(
+ 'raid_service-invoke-clear_foreign_config-ok'),
+ 'no_foreign_drive': load_wsman_xml(
+ 'raid_service-invoke-clear_foreign_config-no_foreign_drive'),
+ 'invalid_controller_id': load_wsman_xml(
+ 'raid_service-invoke-clear_foreign_config-invalid_controller'),
+ 'foreign_drive_operation_not_supported': load_wsman_xml(
+ 'raid_service-invoke-clear_foreign_config-not_supported'),
+ },
+ 'SetAttributes': {
+ 'ok': load_wsman_xml(
+ 'raid_service-invoke-set_attributes-ok'),
+ 'error': load_wsman_xml(
+ 'raid_service-invoke-set_attributes-error'),
}
}
}
diff --git a/dracclient/tests/wsman_mocks/controller_view-enum-ok.xml b/dracclient/tests/wsman_mocks/controller_view-enum-ok.xml
index 2188685..069a0d8 100644
--- a/dracclient/tests/wsman_mocks/controller_view-enum-ok.xml
+++ b/dracclient/tests/wsman_mocks/controller_view-enum-ok.xml
@@ -43,6 +43,7 @@
0
1
PERC H710 Mini
+ 1
1
5B083FE0D2D0F200
1
@@ -82,6 +83,7 @@
0
1
BOSS-S1
+ 0
1
5B083FE0D2D0F201
1
diff --git a/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_recovery.xml b/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_recovery.xml
new file mode 100644
index 0000000..97b3a3a
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_recovery.xml
@@ -0,0 +1,19 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/GetRemoteServicesAPIStatusResponse
+ uuid:18745811-2782-4d30-a288-8f001a895215
+ uuid:9ec203ba-4fc0-1fc0-8094-98d61742a844
+
+
+
+ 4
+ Lifecycle Controller Remote Services is not ready.
+ LC060
+ 0
+ 0
+ 7
+ 1
+
+
+
diff --git a/dracclient/tests/wsman_mocks/lc_service-invoke-create_config_job-error.xml b/dracclient/tests/wsman_mocks/lc_service-invoke-create_config_job-error.xml
new file mode 100644
index 0000000..c375bb7
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/lc_service-invoke-create_config_job-error.xml
@@ -0,0 +1,17 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/CreateConfigJobResponse
+ uuid:80cf5e1b-b109-4ef5-87c8-5b03ce6ba117
+ uuid:e57fa514-2189-1189-8ec1-a36fc6fe83b0
+
+
+
+ Configuration job already created, cannot create another config job on specified target until existing job is completed or is cancelled
+ LC007
+ 2
+
+
+
diff --git a/dracclient/tests/wsman_mocks/lc_service-invoke-create_config_job-ok.xml b/dracclient/tests/wsman_mocks/lc_service-invoke-create_config_job-ok.xml
new file mode 100644
index 0000000..b7ec83c
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/lc_service-invoke-create_config_job-ok.xml
@@ -0,0 +1,28 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/CreateConfigJobResponse
+ uuid:fc2fdae5-6ac2-4338-9b2e-e69b813af829
+ uuid:d7d89957-2189-1189-8ec0-a36fc6fe83b0
+
+
+
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LifecycleJob
+
+ JID_442507917525
+ root/dcim
+
+
+
+
+ 4096
+
+
+
diff --git a/dracclient/tests/wsman_mocks/lc_service-invoke-set_attributes-error.xml b/dracclient/tests/wsman_mocks/lc_service-invoke-set_attributes-error.xml
new file mode 100644
index 0000000..c2c0b75
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/lc_service-invoke-set_attributes-error.xml
@@ -0,0 +1,21 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/SetAttributesResponse
+
+ uuid:bf8adefe-6fc0-456d-b97c-fd8d4aca2d6c
+
+ uuid:84abf7b9-7176-1176-a11c-a53ffbd9bed4
+
+
+
+
+ Invalid AttributeName.
+ LC057
+ 2
+
+
+
diff --git a/dracclient/tests/wsman_mocks/lc_service-invoke-set_attributes-ok.xml b/dracclient/tests/wsman_mocks/lc_service-invoke-set_attributes-ok.xml
new file mode 100644
index 0000000..7c4ff98
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/lc_service-invoke-set_attributes-ok.xml
@@ -0,0 +1,24 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/SetAttributesResponse
+
+ uuid:bf8adefe-6fc0-456d-b97c-fd8d4aca2d6c
+
+ uuid:84abf7b9-7176-1176-a11c-a53ffbd9bed4
+
+
+
+
+ LC001
+ The command was successful
+ 0
+ No
+ Set PendingValue
+
+
+
+
diff --git a/dracclient/tests/wsman_mocks/physical_disk_view-enum-ok.xml b/dracclient/tests/wsman_mocks/physical_disk_view-enum-ok.xml
index 1ebf03e..791fa59 100644
--- a/dracclient/tests/wsman_mocks/physical_disk_view-enum-ok.xml
+++ b/dracclient/tests/wsman_mocks/physical_disk_view-enum-ok.xml
@@ -201,6 +201,7 @@
7
+ 3E
PCIe SSD in Slot 20 in Bay 1
NVMe-MI1.0
2
diff --git a/dracclient/tests/wsman_mocks/raid_enumeration-enum-ok.xml b/dracclient/tests/wsman_mocks/raid_enumeration-enum-ok.xml
new file mode 100644
index 0000000..f031e64
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_enumeration-enum-ok.xml
@@ -0,0 +1,2347 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse
+ uuid:41a4f623-7f99-43b9-b240-4a773aa39860
+ uuid:3b204fe0-9caa-1caa-a2f1-614a498fd94c
+
+
+
+
+
+ RAIDSupportedRAIDLevels
+ 2(RAID-0)
+ 4(RAID-1)
+ 64(RAID-5)
+ 128(RAID-6)
+ 2048(RAID-10)
+ 8192(RAID-50)
+ 16384(RAID-60)
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDSupportedRAIDLevels
+ true
+
+ 2(RAID-0)
+ 4(RAID-1)
+ 64(RAID-5)
+ 128(RAID-6)
+ 2048(RAID-10)
+ 8192(RAID-50)
+ 16384(RAID-60)
+
+
+ RAIDSupportedDiskProt
+ SAS
+ SATA
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDSupportedDiskProt
+ true
+
+ SAS
+ SATA
+
+
+ RAIDSupportedInitTypes
+ Fast
+ Full
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDSupportedInitTypes
+ true
+
+ Fast
+ Full
+
+
+ RAIDloadBalancedMode
+ Automatic
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDloadBalancedMode
+ false
+
+ Automatic
+ Disabled
+
+
+ RAIDccMode
+ Normal
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDccMode
+ false
+
+ Normal
+ Stop on Error
+
+
+ RAIDprMode
+ Automatic
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDprMode
+ false
+
+ Disabled
+ Automatic
+ Manual
+
+
+ RAIDPatrolReadUnconfiguredArea
+ Enabled
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDPatrolReadUnconfiguredArea
+ false
+
+ Disabled
+ Enabled
+
+
+ RAIDcopybackMode
+ On
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDcopybackMode
+ false
+
+ On
+ On with SMART
+ Off
+
+
+ RAIDEnhancedAutoImportForeignConfig
+ Disabled
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDEnhancedAutoImportForeignConfig
+ false
+
+ Disabled
+ Enabled
+
+
+ RAIDControllerBootMode
+ Headless Mode Continue On Error
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDControllerBootMode
+ false
+
+ User Mode
+ Continue Boot On Error
+ Headless Mode Continue On Error
+ Headless Safe Mode
+
+
+ RAIDCurrentControllerMode
+ RAID
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDCurrentControllerMode
+ true
+
+ RAID
+ Enhanced HBA
+
+
+ RAIDRequestedControllerMode
+ None
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDRequestedControllerMode
+ false
+
+ RAID
+ Enhanced HBA
+ None
+
+
+ RAIDMode
+ None
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDMode
+ true
+
+ None
+ Linux
+ Windows
+ Mixed
+
+
+ RAIDpersistentHotspare
+ Disabled
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDpersistentHotspare
+ false
+
+ Disabled
+ Enabled
+
+
+ RAIDMaxCapableSpeed
+ 12_GBS
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDMaxCapableSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDSupportedInitTypes
+ None
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDSupportedInitTypes
+ true
+
+ None
+
+
+ RAIDMode
+ None
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDMode
+ true
+
+ None
+ Linux
+ Windows
+ Mixed
+
+
+ RAIDSupportedInitTypes
+ None
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDSupportedInitTypes
+ true
+
+ None
+
+
+ RAIDMode
+ None
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDMode
+ true
+
+ None
+ Linux
+ Windows
+ Mixed
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.0:RAID.Integrated.1-1
+ Disk.Virtual.0:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.0:RAID.Integrated.1-1
+ Disk.Virtual.0:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.0:RAID.Integrated.1-1
+ Disk.Virtual.0:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.0:RAID.Integrated.1-1
+ Disk.Virtual.0:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.0:RAID.Integrated.1-1
+ Disk.Virtual.0:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.1:RAID.Integrated.1-1
+ Disk.Virtual.1:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.1:RAID.Integrated.1-1
+ Disk.Virtual.1:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.1:RAID.Integrated.1-1
+ Disk.Virtual.1:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.1:RAID.Integrated.1-1
+ Disk.Virtual.1:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.1:RAID.Integrated.1-1
+ Disk.Virtual.1:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.2:RAID.Integrated.1-1
+ Disk.Virtual.2:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.2:RAID.Integrated.1-1
+ Disk.Virtual.2:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.2:RAID.Integrated.1-1
+ Disk.Virtual.2:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.2:RAID.Integrated.1-1
+ Disk.Virtual.2:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.2:RAID.Integrated.1-1
+ Disk.Virtual.2:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.3:RAID.Integrated.1-1
+ Disk.Virtual.3:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.3:RAID.Integrated.1-1
+ Disk.Virtual.3:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.3:RAID.Integrated.1-1
+ Disk.Virtual.3:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.3:RAID.Integrated.1-1
+ Disk.Virtual.3:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.3:RAID.Integrated.1-1
+ Disk.Virtual.3:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.4:RAID.Integrated.1-1
+ Disk.Virtual.4:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.4:RAID.Integrated.1-1
+ Disk.Virtual.4:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.4:RAID.Integrated.1-1
+ Disk.Virtual.4:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.4:RAID.Integrated.1-1
+ Disk.Virtual.4:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.4:RAID.Integrated.1-1
+ Disk.Virtual.4:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.5:RAID.Integrated.1-1
+ Disk.Virtual.5:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.5:RAID.Integrated.1-1
+ Disk.Virtual.5:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.5:RAID.Integrated.1-1
+ Disk.Virtual.5:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.5:RAID.Integrated.1-1
+ Disk.Virtual.5:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.5:RAID.Integrated.1-1
+ Disk.Virtual.5:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.6:RAID.Integrated.1-1
+ Disk.Virtual.6:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.6:RAID.Integrated.1-1
+ Disk.Virtual.6:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.6:RAID.Integrated.1-1
+ Disk.Virtual.6:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.6:RAID.Integrated.1-1
+ Disk.Virtual.6:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.6:RAID.Integrated.1-1
+ Disk.Virtual.6:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.7:RAID.Integrated.1-1
+ Disk.Virtual.7:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.7:RAID.Integrated.1-1
+ Disk.Virtual.7:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.7:RAID.Integrated.1-1
+ Disk.Virtual.7:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.7:RAID.Integrated.1-1
+ Disk.Virtual.7:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.7:RAID.Integrated.1-1
+ Disk.Virtual.7:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.8:RAID.Integrated.1-1
+ Disk.Virtual.8:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.8:RAID.Integrated.1-1
+ Disk.Virtual.8:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.8:RAID.Integrated.1-1
+ Disk.Virtual.8:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.8:RAID.Integrated.1-1
+ Disk.Virtual.8:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.8:RAID.Integrated.1-1
+ Disk.Virtual.8:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.9:RAID.Integrated.1-1
+ Disk.Virtual.9:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.9:RAID.Integrated.1-1
+ Disk.Virtual.9:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.9:RAID.Integrated.1-1
+ Disk.Virtual.9:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.9:RAID.Integrated.1-1
+ Disk.Virtual.9:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.9:RAID.Integrated.1-1
+ Disk.Virtual.9:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.10:RAID.Integrated.1-1
+ Disk.Virtual.10:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.10:RAID.Integrated.1-1
+ Disk.Virtual.10:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.10:RAID.Integrated.1-1
+ Disk.Virtual.10:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.10:RAID.Integrated.1-1
+ Disk.Virtual.10:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.10:RAID.Integrated.1-1
+ Disk.Virtual.10:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.11:RAID.Integrated.1-1
+ Disk.Virtual.11:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.11:RAID.Integrated.1-1
+ Disk.Virtual.11:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.11:RAID.Integrated.1-1
+ Disk.Virtual.11:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.11:RAID.Integrated.1-1
+ Disk.Virtual.11:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.11:RAID.Integrated.1-1
+ Disk.Virtual.11:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.12:RAID.Integrated.1-1
+ Disk.Virtual.12:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.12:RAID.Integrated.1-1
+ Disk.Virtual.12:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.12:RAID.Integrated.1-1
+ Disk.Virtual.12:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.12:RAID.Integrated.1-1
+ Disk.Virtual.12:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.12:RAID.Integrated.1-1
+ Disk.Virtual.12:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.13:RAID.Integrated.1-1
+ Disk.Virtual.13:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.13:RAID.Integrated.1-1
+ Disk.Virtual.13:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Enabled
+ Disk.Virtual.13:RAID.Integrated.1-1
+ Disk.Virtual.13:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.13:RAID.Integrated.1-1
+ Disk.Virtual.13:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.13:RAID.Integrated.1-1
+ Disk.Virtual.13:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.14:RAID.Integrated.1-1
+ Disk.Virtual.14:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.14:RAID.Integrated.1-1
+ Disk.Virtual.14:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Enabled
+ Disk.Virtual.14:RAID.Integrated.1-1
+ Disk.Virtual.14:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.14:RAID.Integrated.1-1
+ Disk.Virtual.14:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.14:RAID.Integrated.1-1
+ Disk.Virtual.14:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.15:RAID.Integrated.1-1
+ Disk.Virtual.15:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.15:RAID.Integrated.1-1
+ Disk.Virtual.15:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Enabled
+ Disk.Virtual.15:RAID.Integrated.1-1
+ Disk.Virtual.15:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.15:RAID.Integrated.1-1
+ Disk.Virtual.15:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.15:RAID.Integrated.1-1
+ Disk.Virtual.15:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.16:RAID.Integrated.1-1
+ Disk.Virtual.16:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.16:RAID.Integrated.1-1
+ Disk.Virtual.16:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Enabled
+ Disk.Virtual.16:RAID.Integrated.1-1
+ Disk.Virtual.16:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.16:RAID.Integrated.1-1
+ Disk.Virtual.16:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.16:RAID.Integrated.1-1
+ Disk.Virtual.16:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.17:RAID.Integrated.1-1
+ Disk.Virtual.17:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.17:RAID.Integrated.1-1
+ Disk.Virtual.17:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.17:RAID.Integrated.1-1
+ Disk.Virtual.17:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.17:RAID.Integrated.1-1
+ Disk.Virtual.17:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.17:RAID.Integrated.1-1
+ Disk.Virtual.17:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDdefaultWritePolicy
+ WriteBack
+ Disk.Virtual.18:RAID.Integrated.1-1
+ Disk.Virtual.18:RAID.Integrated.1-1:RAIDdefaultWritePolicy
+ false
+
+ WriteThrough
+ WriteBack
+ WriteBackForce
+
+
+ RAIDdefaultReadPolicy
+ ReadAhead
+ Disk.Virtual.18:RAID.Integrated.1-1
+ Disk.Virtual.18:RAID.Integrated.1-1:RAIDdefaultReadPolicy
+ false
+
+ NoReadAhead
+ ReadAhead
+ AdaptiveReadAhead
+
+
+ DiskCachePolicy
+ Disabled
+ Disk.Virtual.18:RAID.Integrated.1-1
+ Disk.Virtual.18:RAID.Integrated.1-1:DiskCachePolicy
+ false
+
+ Default
+ Enabled
+ Disabled
+
+
+ T10PIStatus
+ Disabled
+ Disk.Virtual.18:RAID.Integrated.1-1
+ Disk.Virtual.18:RAID.Integrated.1-1:T10PIStatus
+ true
+
+ Disabled
+ Enabled
+
+
+ RAIDStripeSize
+ 512(256 KB)
+ Disk.Virtual.18:RAID.Integrated.1-1
+ Disk.Virtual.18:RAID.Integrated.1-1:RAIDStripeSize
+ true
+
+ 0
+ 1(512 Bytes)
+ 2(1 KB)
+ 4(2 KB)
+ 8(4 KB)
+ 16(8 KB)
+ 32(16 KB)
+ 64(32 KB)
+ 128(64 KB)
+ 256(128 KB)
+ 512(256 KB)
+ 1024(512 KB)
+ 2048(1024 KB)
+ 4096(2048 KB)
+ 8192(4096 KB)
+ 16384(8192 KB)
+ 32768(16384 KB)
+
+
+ RAIDMultipath
+ Off
+ Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDMultipath
+ true
+
+ Off
+ On
+
+
+ BackplaneType
+ Not Shared
+ Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Enclosure.Internal.0-1:RAID.Integrated.1-1:BackplaneType
+ true
+
+ Not Shared
+ Shared
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.7:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.7:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.7:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.7:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.7:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.7:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.8:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.8:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.8:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.8:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.8:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.8:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.9:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.9:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.9:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.9:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.9:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.9:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.10:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.10:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.10:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.10:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.10:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.10:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.11:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.11:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.11:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.11:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.11:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.11:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.12:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.12:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.12:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.12:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 6_GBS
+ Disk.Bay.12:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.12:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.13:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.13:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.13:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.13:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 6_GBS
+ Disk.Bay.13:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.13:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.14:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.14:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.14:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.14:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 6_GBS
+ Disk.Bay.14:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.14:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.15:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.15:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.15:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.15:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 6_GBS
+ Disk.Bay.15:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.15:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.16:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.16:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.16:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.16:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.16:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.16:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.17:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.17:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.17:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.17:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.17:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.17:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.18:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.18:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.18:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.18:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.18:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.18:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+ RAIDPDState
+ Online
+ Disk.Bay.19:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.19:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDPDState
+ true
+
+ Unknown
+ Ready
+ Online
+ Foreign
+ Blocked
+ Failed
+ Non-RAID
+ Missing
+ Offline
+
+
+ RAIDHotSpareStatus
+ No
+ Disk.Bay.19:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.19:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDHotSpareStatus
+ true
+
+ No
+ Dedicated
+ Global
+
+
+ RAIDNegotiatedSpeed
+ 12_GBS
+ Disk.Bay.19:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.19:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNegotiatedSpeed
+ true
+
+ 1_5_GBS
+ 3_GBS
+ 6_GBS
+ 12_GBS
+
+
+
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_integer-enum-ok.xml b/dracclient/tests/wsman_mocks/raid_integer-enum-ok.xml
new file mode 100644
index 0000000..27c610c
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_integer-enum-ok.xml
@@ -0,0 +1,416 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse
+ uuid:40206465-1566-46e3-bf05-9952ba57ec3c
+ uuid:6af777f7-9ef1-1ef1-b067-84d3878fd94c
+
+
+
+
+
+ RAIDmaxSupportedVD
+ 240
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDmaxSupportedVD
+ true
+ 0
+
+ 0
+
+
+ RAIDmaxPDsInSpan
+ 32
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDmaxPDsInSpan
+ true
+ 0
+
+ 0
+
+
+ RAIDmaxSpansInVD
+ 8
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDmaxSpansInVD
+ true
+ 0
+
+ 0
+
+
+ RAIDrebuildRate
+ 30
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDrebuildRate
+ false
+ 0
+
+ 100
+
+
+ RAIDccRate
+ 30
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDccRate
+ false
+ 0
+
+ 100
+
+
+ RAIDreconstructRate
+ 30
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDreconstructRate
+ false
+ 0
+
+ 100
+
+
+ RAIDbgiRate
+ 30
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDbgiRate
+ false
+ 0
+
+ 100
+
+
+ RAIDprRate
+ 30
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDprRate
+ true
+ 0
+
+ 100
+
+
+ RAIDspinDownIdleTime
+ 30
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDspinDownIdleTime
+ true
+ 0
+
+ 65535
+
+
+ RAIDprIterations
+ 0
+ RAID.Integrated.1-1
+ RAID.Integrated.1-1:RAIDprIterations
+ true
+ 1
+
+ 4294967295
+
+
+ RAIDmaxSupportedVD
+ 0
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDmaxSupportedVD
+ true
+ 0
+
+ 0
+
+
+ RAIDmaxPDsInSpan
+ 0
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDmaxPDsInSpan
+ true
+ 0
+
+ 0
+
+
+ RAIDmaxSpansInVD
+ 0
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDmaxSpansInVD
+ true
+ 0
+
+ 0
+
+
+ RAIDrebuildRate
+ 255
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDrebuildRate
+ true
+ 0
+
+ 100
+
+
+ RAIDccRate
+ 255
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDccRate
+ true
+ 0
+
+ 100
+
+
+ RAIDreconstructRate
+ 255
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDreconstructRate
+ true
+ 0
+
+ 100
+
+
+ RAIDbgiRate
+ 255
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDbgiRate
+ true
+ 0
+
+ 100
+
+
+ RAIDprRate
+ 255
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDprRate
+ true
+ 0
+
+ 100
+
+
+ RAIDspinDownIdleTime
+ 0
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDspinDownIdleTime
+ true
+ 0
+
+ 65535
+
+
+ RAIDprIterations
+ 0
+ AHCI.Embedded.2-1
+ AHCI.Embedded.2-1:RAIDprIterations
+ true
+ 1
+
+ 4294967295
+
+
+ RAIDmaxSupportedVD
+ 0
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDmaxSupportedVD
+ true
+ 0
+
+ 0
+
+
+ RAIDmaxPDsInSpan
+ 0
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDmaxPDsInSpan
+ true
+ 0
+
+ 0
+
+
+ RAIDmaxSpansInVD
+ 0
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDmaxSpansInVD
+ true
+ 0
+
+ 0
+
+
+ RAIDrebuildRate
+ 255
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDrebuildRate
+ true
+ 0
+
+ 100
+
+
+ RAIDccRate
+ 255
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDccRate
+ true
+ 0
+
+ 100
+
+
+ RAIDreconstructRate
+ 255
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDreconstructRate
+ true
+ 0
+
+ 100
+
+
+ RAIDbgiRate
+ 255
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDbgiRate
+ true
+ 0
+
+ 100
+
+
+ RAIDprRate
+ 255
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDprRate
+ true
+ 0
+
+ 100
+
+
+ RAIDspinDownIdleTime
+ 0
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDspinDownIdleTime
+ true
+ 0
+
+ 65535
+
+
+ RAIDprIterations
+ 0
+ AHCI.Embedded.1-1
+ AHCI.Embedded.1-1:RAIDprIterations
+ true
+ 1
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.7:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.7:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.8:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.8:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+ RAIDNominalMediumRotationRate
+ 10000
+ Disk.Bay.9:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.9:Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDNominalMediumRotationRate
+ true
+ 2
+
+ 4294967295
+
+
+
+
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-invalid_controller.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-invalid_controller.xml
new file mode 100644
index 0000000..d60acb2
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-invalid_controller.xml
@@ -0,0 +1,17 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ClearForeignConfigResponse
+ uuid:f9487fcf-103a-103a-8002-fd0aa2bdb228
+ uuid:000852e6-1040-1040-8997-a36fc6fe83b0
+
+
+
+ Controller not found
+ STOR030
+ 2
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-no_foreign_drive.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-no_foreign_drive.xml
new file mode 100644
index 0000000..6ab74d7
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-no_foreign_drive.xml
@@ -0,0 +1,17 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ClearForeignConfigResponse
+ uuid:f9487fcf-103a-103a-8002-fd0aa2bdb228
+ uuid:000852e6-1040-1040-8997-a36fc6fe83b0
+
+
+
+ No foreign drives detected
+ STOR018
+ 2
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-not_supported.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-not_supported.xml
new file mode 100644
index 0000000..898e739
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-not_supported.xml
@@ -0,0 +1,18 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ClearForeignConfigResponse
+ uuid:473f8ede-9a1a-441a-aaf6-699c1476aa97
+ uuid:55d91de0-90a1-10a1-8147-8c0c498fd94c
+
+
+
+ The operation cannot be completed either because the operation is not supported on the target device,
+ or the RAIDType of "MD Software RAID" does not allow the operation.
+ STOR058
+ 2
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-ok.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-ok.xml
new file mode 100644
index 0000000..dc303c5
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-ok.xml
@@ -0,0 +1,16 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ClearForeignConfigResponse
+ uuid:fefa06de-103a-103a-8002-fd0aa2bdb228
+ uuid:05bc00f4-1040-1040-899d-a36fc6fe83b0
+
+
+
+ OPTIONAL
+ 0
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-error.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-error.xml
index c964a6b..37d5da2 100644
--- a/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-error.xml
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-error.xml
@@ -14,4 +14,4 @@
2
-
\ No newline at end of file
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-ok.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-ok.xml
index 0b3eff2..b1035c3 100644
--- a/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-ok.xml
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-ok.xml
@@ -13,4 +13,4 @@
0
-
\ No newline at end of file
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-error.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-error.xml
new file mode 100644
index 0000000..cad10be
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-error.xml
@@ -0,0 +1,17 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ResetConfigResponse
+ uuid:f9487fcf-103a-103a-8002-fd0aa2bdb228
+ uuid:000852e6-1040-1040-8997-a36fc6fe83b0
+
+
+
+ Virtual Disk not found
+ STOR028
+ 2
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-ok.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-ok.xml
new file mode 100644
index 0000000..867f54a
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-ok.xml
@@ -0,0 +1,16 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ResetConfigResponse
+ uuid:fefa06de-103a-103a-8002-fd0aa2bdb228
+ uuid:05bc00f4-1040-1040-899d-a36fc6fe83b0
+
+
+
+ OPTIONAL
+ 0
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-set_attributes-error.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-set_attributes-error.xml
new file mode 100644
index 0000000..e79807b
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-set_attributes-error.xml
@@ -0,0 +1,21 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/SetAttributesResponse
+
+ uuid:bf8adefe-6fc0-456d-b97c-fd8d4aca2d6c
+
+ uuid:84abf7b9-7176-1176-a11c-a53ffbd9bed4
+
+
+
+
+ Invalid parameter value
+ STOR004
+ 2
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-set_attributes-ok.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-set_attributes-ok.xml
new file mode 100644
index 0000000..50d5fd4
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_service-invoke-set_attributes-ok.xml
@@ -0,0 +1,24 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+ http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/SetAttributesResponse
+
+ uuid:bf8adefe-6fc0-456d-b97c-fd8d4aca2d6c
+
+ uuid:84abf7b9-7176-1176-a11c-a53ffbd9bed4
+
+
+
+
+ STOR001
+ The command was successful for all attributes
+ 0
+ Yes
+ Set PendingValue
+
+
+
+
diff --git a/dracclient/tests/wsman_mocks/raid_string-enum-ok.xml b/dracclient/tests/wsman_mocks/raid_string-enum-ok.xml
new file mode 100644
index 0000000..866961f
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/raid_string-enum-ok.xml
@@ -0,0 +1,49 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse
+ uuid:6f1e7eae-511a-4268-9913-c1ce1bb414be
+ uuid:6da65cf0-9cbb-1cbb-9773-deda878fd94c
+
+
+
+
+
+ Name
+ Virtual Disk 0
+ Disk.Virtual.0:RAID.Integrated.1-1
+ Disk.Virtual.0:RAID.Integrated.1-1:Name
+ true
+ 129
+ 0
+
+
+
+ Name
+ Virtual Disk 1
+ Disk.Virtual.1:RAID.Integrated.1-1
+ Disk.Virtual.1:RAID.Integrated.1-1:Name
+ true
+ 129
+ 0
+
+
+
+ RAIDEffectiveSASAddress
+ 500056B3239C1AFD
+ Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Enclosure.Internal.0-1:RAID.Integrated.1-1:RAIDEffectiveSASAddress
+ true
+ 16
+ 16
+
+
+
+
+
+
diff --git a/dracclient/tests/wsman_mocks/virtual_disk_view-enum-with-raid-status-ok.xml b/dracclient/tests/wsman_mocks/virtual_disk_view-enum-with-raid-status-ok.xml
new file mode 100644
index 0000000..c8e3151
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/virtual_disk_view-enum-with-raid-status-ok.xml
@@ -0,0 +1,55 @@
+
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse
+ uuid:b182f1ee-103a-103a-8002-fd0aa2bdb228
+ uuid:b80f21ed-103f-103f-8992-a36fc6fe83b0
+
+
+
+
+
+ 512
+ 6
+ 0
+ Virtual Disk 0 on Integrated RAID Controller 1
+ 1024
+ Disk.Virtual.0:RAID.Integrated.1-1
+ Disk.Virtual.0:RAID.Integrated.1-1
+ 20150301200527.000000+000
+ 20150301200527.000000+000
+ 0
+ 1
+ disk 0
+ 0
+ Background Intialization
+ 8
+ 0
+ Disk.Bay.4:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ Disk.Bay.5:Enclosure.Internal.0-1:RAID.Integrated.1-1
+ 1
+ 2
+ 4
+ 16
+ 1
+ 1
+ 599550590976
+ 1
+ 2
+ 0
+ 128
+ 0
+ 0
+ 2
+
+
+
+
+
+
+
diff --git a/dracclient/utils.py b/dracclient/utils.py
index a985c51..22a5832 100644
--- a/dracclient/utils.py
+++ b/dracclient/utils.py
@@ -251,7 +251,7 @@ def validate_integer_value(value, attr_name, error_msgs):
def list_settings(client, namespaces, by_name=True, fqdd_filter=None,
- name_formatter=None):
+ name_formatter=None, wait_for_idrac=True):
"""List the configuration settings
:param client: an instance of WSManClient.
@@ -263,6 +263,9 @@ def list_settings(client, namespaces, by_name=True, fqdd_filter=None,
:param name_formatter: a method used to format the keys in the
returned dictionary. By default,
attribute.name will be used.
+ :param wait_for_idrac: indicates whether or not to wait for the
+ iDRAC to be ready to accept commands before
+ issuing the command.
:returns: a dictionary with the settings using name or instance_id as
the key.
:raises: WSManRequestFailure on request failures
@@ -274,7 +277,7 @@ def list_settings(client, namespaces, by_name=True, fqdd_filter=None,
result = {}
for (namespace, attr_cls) in namespaces:
attribs = _get_config(client, namespace, attr_cls, by_name,
- fqdd_filter, name_formatter)
+ fqdd_filter, name_formatter, wait_for_idrac)
if not set(result).isdisjoint(set(attribs)):
raise exceptions.DRACOperationFailed(
drac_messages=('Colliding attributes %r' % (
@@ -284,10 +287,10 @@ def list_settings(client, namespaces, by_name=True, fqdd_filter=None,
def _get_config(client, resource, attr_cls, by_name, fqdd_filter,
- name_formatter):
+ name_formatter, wait_for_idrac):
result = {}
- doc = client.enumerate(resource)
+ doc = client.enumerate(resource, wait_for_idrac=wait_for_idrac)
items = doc.find('.//{%s}Items' % wsman.NS_WSMAN)
for item in items:
@@ -316,7 +319,9 @@ def set_settings(settings_type,
cim_name,
target,
name_formatter=None,
- include_commit_required=False):
+ include_commit_required=False,
+ wait_for_idrac=True,
+ by_name=True):
"""Generically handles setting various types of settings on the iDRAC
This method pulls the current list of settings from the iDRAC then compares
@@ -339,6 +344,11 @@ def set_settings(settings_type,
attribute.name will be used.
:parm include_commit_required: Indicates if the deprecated commit_required
should be returned in the result.
+ :param wait_for_idrac: indicates whether or not to wait for the
+ iDRAC to be ready to accept commands before issuing
+ the command
+ :param by_name: Controls whether returned dictionary uses RAID
+ attribute name or instance_id as key.
:returns: a dictionary containing:
- The commit_required key with a boolean value indicating
whether a config job must be created for the values to be
@@ -359,9 +369,9 @@ def set_settings(settings_type,
:raises: DRACUnexpectedReturnValue on return value mismatch
:raises: InvalidParameterValue on invalid new setting
"""
-
- current_settings = list_settings(client, namespaces, by_name=True,
- name_formatter=name_formatter)
+ current_settings = list_settings(client, namespaces, by_name=by_name,
+ name_formatter=name_formatter,
+ wait_for_idrac=wait_for_idrac)
unknown_keys = set(new_settings) - set(current_settings)
if unknown_keys:
@@ -376,11 +386,18 @@ def set_settings(settings_type,
candidates = set(new_settings)
for attr in candidates:
- if str(new_settings[attr]) == str(
- current_settings[attr].current_value):
- unchanged_attribs.append(attr)
- elif current_settings[attr].read_only:
+ # There are RAID settings that can have multiple values,
+ # however these are all read-only attributes.
+ # Filter out all read-only attributes first so that we exclude
+ # these settings from further consideration
+ current_setting_value = current_settings[attr].current_value
+ if type(current_setting_value) is list:
+ current_setting_value = current_setting_value[0]
+
+ if current_settings[attr].read_only:
read_only_keys.append(attr)
+ elif str(new_settings[attr]) == str(current_setting_value):
+ unchanged_attribs.append(attr)
else:
validation_msg = current_settings[attr].validate(
new_settings[attr])
@@ -421,12 +438,25 @@ def set_settings(settings_type,
'Name': cim_name,
'SystemCreationClassName': 'DCIM_ComputerSystem',
'SystemName': 'DCIM:ComputerSystem'}
+
properties = {'Target': target,
- 'AttributeName': attrib_names,
'AttributeValue': [new_settings[attr] for attr
in attrib_names]}
+ # To set RAID settings, above we fetched list raid settings using
+ # instance_id to retrieve attribute values. When we pass instance_id in
+ # setattribute method for setting any new RAID settings, wsman raises
+ # an error. So another approach to set those settings is to list raid
+ # settings using instance_id and for settings new settings, pass the
+ # attribute names in list to SetAttributes method along with the target.
+ # That's the reason, we need to handle RAID specific settings like below
+ if settings_type == 'RAID':
+ properties['AttributeName'] = [current_settings[attr].name for
+ attr in attrib_names]
+ else:
+ properties['AttributeName'] = attrib_names
doc = client.invoke(resource_uri, 'SetAttributes',
- selectors, properties)
+ selectors, properties,
+ wait_for_idrac=wait_for_idrac)
return build_return_dict(doc, resource_uri,
include_commit_required=include_commit_required)
diff --git a/dracclient/wsman.py b/dracclient/wsman.py
index e0f4476..55cf548 100644
--- a/dracclient/wsman.py
+++ b/dracclient/wsman.py
@@ -163,8 +163,11 @@ def enumerate(self, resource_uri, optimization=True, max_elems=100,
resp_xml = ElementTree.fromstring(resp.content)
except ElementTree.XMLSyntaxError:
LOG.warning('Received invalid content from iDRAC. Filtering out '
- 'non-ASCII characters: ' + repr(resp.content))
- resp_xml = ElementTree.fromstring(re.sub(six.b('[^\x00-\x7f]'),
+ 'unprintable characters: ' + repr(resp.content))
+
+ # Filter out everything except for printable ASCII characters and
+ # tab
+ resp_xml = ElementTree.fromstring(re.sub(six.b('[^\x20-\x7e\t]'),
six.b(''),
resp.content))
diff --git a/setup.cfg b/setup.cfg
index 841d530..c52195d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,7 +3,7 @@ name = python-dracclient
summary = Library for managing machines with Dell iDRAC cards
description-file = README.rst
maintainer = DracClient Team
-maintainer_email = openstack-dev@lists.openstack.org
+author-email = openstack-discuss@lists.openstack.org
home-page = https://launchpad.net/python-dracclient
license = Apache-2
classifier =
diff --git a/test-requirements.txt b/test-requirements.txt
index 89121f4..1c12173 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -7,5 +7,3 @@ doc8
hacking>=0.11.0,<0.12
mock>=2.0
requests-mock>=1.0
-sphinx>=1.2.1,!=1.3b1,<1.3
-oslosphinx>=2.5.0,!=3.4.0
diff --git a/tox.ini b/tox.ini
index 32a72b6..f77993e 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,7 +3,7 @@ envlist = py35,py27,pep8
[testenv]
usedevelop = True
-install_command = pip install -U -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
+install_command = pip install -U -c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/openstack/requirements/raw/branch/stable/stein/upper-constraints.txt} {opts} {packages}
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
@@ -22,7 +22,12 @@ commands =
doc8 README.rst CONTRIBUTING.rst doc/source
[testenv:docs]
-commands = python setup.py build_sphinx
+deps =
+ -c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/openstack/requirements/raw/branch/stable/stein/upper-constraints.txt}
+ -r{toxinidir}/requirements.txt
+ -r{toxinidir}/doc/requirements.txt
+commands =
+ sphinx-build -b html doc/source doc/build/html
[flake8]
max-complexity=15
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
new file mode 100644
index 0000000..cb26e39
--- /dev/null
+++ b/zuul.d/project.yaml
@@ -0,0 +1,4 @@
+- project:
+ templates:
+ - openstack-python-jobs
+ - openstack-python35-jobs