Enumerate operations can wait until iDRAC is ready

Web Services Management (WS-Management and WS-Man) Enumerate operations
can fail or return invalid results when issued to an integrated Dell
Remote Access Controller (iDRAC) whose Lifecycle Controller remote
service is not "ready". The following are examples of failures which
have been observed:

+ The result of Enumerate is an error.
+ Enumerate succeeds, but no items are returned when they are known to
exist.
+ Enumerate succeeds, but items for all those known to exist are not
returned.

A Dell technical white paper [0], "Lifecycle Controller Integration --
Best Practices Guide", states that for Lifecycle Controller firmware
1.5.0 and later "The Lifecycle Controller remote service must be in a
'ready' state before running any other WSMAN commands." That applies to
almost all of the workflows and use cases documented by that paper and
supported by this project, openstack/python-dracclient.

This patch defines a new method in class dracclient.client.WSManClient,
enumerate(). It extends its base class's implementation by adding a new
parameter that indicates whether or not it should wait until the iDRAC
is ready to accept commands before issuing the Enumerate command. When
it is true, that method waits until the iDRAC is ready before issuing
the command. Since almost all Enumerate operations require the iDRAC to
be ready, the new parameter's default value is 'True'.

[0]
http://en.community.dell.com/techcenter/extras/m/white_papers/20442332

Change-Id: Ied659a4ee45b1dd55cd3a420301d866d52c838fb
Partial-Bug: #1697558
Related-Bug: #1691808
This commit is contained in:
Richard Pioso 2017-06-30 12:26:57 -04:00
parent deed7d7c1c
commit 3207d9e1bc
9 changed files with 144 additions and 61 deletions

View File

@ -603,6 +603,36 @@ class WSManClient(wsman.Client):
self._ready_retries = ready_retries
self._ready_retry_delay = ready_retry_delay
def enumerate(self, resource_uri, optimization=True, max_elems=100,
auto_pull=True, filter_query=None, filter_dialect='cql',
wait_for_idrac=True):
"""Executes enumerate operation over WS-Man
:param resource_uri: URI of resource to enumerate
:param optimization: flag to enable enumeration optimization. If
disabled, the enumeration returns only an
enumeration context.
:param max_elems: maximum number of elements returned by the operation
:param auto_pull: flag to enable automatic pull on the enumeration
context, merging the items returned
:param filter_query: filter query string
:param filter_dialect: filter dialect. Valid options are: 'cql' and
'wql'.
:param wait_for_idrac: indicates whether or not to wait for the
iDRAC to be ready to accept commands before issuing the
command
:returns: an lxml.etree.Element object of the response received
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
"""
if wait_for_idrac:
self.wait_until_idrac_is_ready(self._ready_retries,
self._ready_retry_delay)
return super(WSManClient, self).enumerate(resource_uri, optimization,
max_elems, auto_pull,
filter_query, filter_dialect)
def invoke(self, resource_uri, method, selectors=None, properties=None,
expected_return_value=None, wait_for_idrac=True):
"""Invokes a remote WS-Man method

View File

@ -29,6 +29,8 @@ from dracclient import utils
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient, 'wait_until_idrac_is_ready',
spec_set=True, autospec=True)
class ClientPowerManagementTestCase(base.BaseTest):
def setUp(self):
@ -36,16 +38,14 @@ class ClientPowerManagementTestCase(base.BaseTest):
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
def test_get_power_state(self, mock_requests):
def test_get_power_state(self, mock_requests,
mock_wait_until_idrac_is_ready):
mock_requests.post(
'https://1.2.3.4:443/wsman',
text=test_utils.BIOSEnumerations[uris.DCIM_ComputerSystem]['ok'])
self.assertEqual('POWER_ON', self.drac_client.get_power_state())
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_set_power_state(self, mock_requests,
mock_wait_until_idrac_is_ready):
mock_requests.post(
@ -55,9 +55,6 @@ class ClientPowerManagementTestCase(base.BaseTest):
self.assertIsNone(self.drac_client.set_power_state('POWER_ON'))
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_set_power_state_fail(self, mock_requests,
mock_wait_until_idrac_is_ready):
mock_requests.post(
@ -68,11 +65,15 @@ class ClientPowerManagementTestCase(base.BaseTest):
self.assertRaises(exceptions.DRACOperationFailed,
self.drac_client.set_power_state, 'POWER_ON')
def test_set_power_state_invalid_target_state(self, mock_requests):
def test_set_power_state_invalid_target_state(
self, mock_requests, mock_wait_until_idrac_is_ready):
self.assertRaises(exceptions.InvalidParameterValue,
self.drac_client.set_power_state, 'foo')
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient, 'wait_until_idrac_is_ready',
spec_set=True, autospec=True)
class ClientBootManagementTestCase(base.BaseTest):
def setUp(self):
@ -80,8 +81,8 @@ class ClientBootManagementTestCase(base.BaseTest):
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
@requests_mock.Mocker()
def test_list_boot_modes(self, mock_requests):
def test_list_boot_modes(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_boot_mode = bios.BootMode(id='IPL', name='BootSeq',
is_current=True, is_next=True)
mock_requests.post(
@ -94,8 +95,8 @@ class ClientBootManagementTestCase(base.BaseTest):
self.assertEqual(5, len(boot_modes))
self.assertIn(expected_boot_mode, boot_modes)
@requests_mock.Mocker()
def test_list_boot_devices(self, mock_requests):
def test_list_boot_devices(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_boot_device = bios.BootDevice(
id=('IPL:BIOS.Setup.1-1#BootSeq#NIC.Embedded.1-1-1#'
'fbeeb18f19fd4e768c941e66af4fc424'),
@ -124,11 +125,11 @@ class ClientBootManagementTestCase(base.BaseTest):
self.assertEqual(
2, boot_devices['IPL'][2].pending_assigned_sequence)
@requests_mock.Mocker()
@mock.patch.object(lifecycle_controller.LifecycleControllerManagement,
'get_version', spec_set=True, autospec=True)
def test_list_boot_devices_11g(self, mock_requests,
mock_get_lifecycle_controller_version):
mock_get_lifecycle_controller_version,
mock_wait_until_idrac_is_ready):
expected_boot_device = bios.BootDevice(
id=('IPL:NIC.Embedded.1-1:082927b7c62a9f52ef0d65a33416d76c'),
boot_mode='IPL',
@ -158,10 +159,6 @@ class ClientBootManagementTestCase(base.BaseTest):
self.assertEqual(
2, boot_devices['IPL'][2].pending_assigned_sequence)
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_change_boot_device_order(self, mock_requests,
mock_wait_until_idrac_is_ready):
mock_requests.post(
@ -175,7 +172,8 @@ class ClientBootManagementTestCase(base.BaseTest):
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_change_boot_device_order_list(self, mock_invoke):
def test_change_boot_device_order_list(self, mock_requests, mock_invoke,
mock_wait_until_idrac_is_ready):
expected_selectors = {'InstanceID': 'IPL'}
expected_properties = {'source': ['foo', 'bar', 'baz']}
mock_invoke.return_value = lxml.etree.fromstring(
@ -190,10 +188,6 @@ class ClientBootManagementTestCase(base.BaseTest):
'ChangeBootOrderByInstanceID', expected_selectors,
expected_properties, expected_return_value=utils.RET_SUCCESS)
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_change_boot_device_order_error(self, mock_requests,
mock_wait_until_idrac_is_ready):
mock_requests.post(
@ -207,6 +201,9 @@ class ClientBootManagementTestCase(base.BaseTest):
self.drac_client.change_boot_device_order, 'IPL', 'foo')
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient, 'wait_until_idrac_is_ready',
spec_set=True, autospec=True)
class ClientBIOSConfigurationTestCase(base.BaseTest):
def setUp(self):
@ -214,8 +211,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
@requests_mock.Mocker()
def test_list_bios_settings_by_instance_id(self, mock_requests):
def test_list_bios_settings_by_instance_id(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_enum_attr = bios.BIOSEnumerableAttribute(
name='MemTest',
instance_id='BIOS.Setup.1-1:MemTest',
@ -264,8 +261,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
self.assertEqual(expected_integer_attr, bios_settings[
'BIOS.Setup.1-1:Proc1NumCores'])
@requests_mock.Mocker()
def test_list_bios_settings_by_name(self, mock_requests):
def test_list_bios_settings_by_name(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_enum_attr = bios.BIOSEnumerableAttribute(
name='MemTest',
instance_id='BIOS.Setup.1-1:MemTest',
@ -312,9 +309,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
self.assertIn('Proc1NumCores', bios_settings)
self.assertEqual(expected_integer_attr, bios_settings['Proc1NumCores'])
@requests_mock.Mocker()
def test_list_bios_settings_by_name_with_colliding_attrs(
self, mock_requests):
self, mock_requests, mock_wait_until_idrac_is_ready):
mock_requests.post('https://1.2.3.4:443/wsman', [
{'text': test_utils.BIOSEnumerations[
uris.DCIM_BIOSEnumeration]['ok']},
@ -326,10 +322,10 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
self.assertRaises(exceptions.DRACOperationFailed,
self.drac_client.list_bios_settings, by_name=True)
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_set_bios_settings(self, mock_requests, mock_invoke):
def test_set_bios_settings(self, mock_requests, mock_invoke,
mock_wait_until_idrac_is_ready):
expected_selectors = {'CreationClassName': 'DCIM_BIOSService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:BIOSService',
@ -356,10 +352,6 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
mock.ANY, uris.DCIM_BIOSService, 'SetAttributes',
expected_selectors, expected_properties)
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_set_bios_settings_error(self, mock_requests,
mock_wait_until_idrac_is_ready):
mock_requests.post('https://1.2.3.4:443/wsman', [
@ -376,8 +368,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
self.drac_client.set_bios_settings,
{'ProcVirtualization': 'Disabled'})
@requests_mock.Mocker()
def test_set_bios_settings_with_unknown_attr(self, mock_requests):
def test_set_bios_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.BIOSEnumerations[
uris.DCIM_BIOSEnumeration]['ok']},
@ -389,8 +381,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
self.assertRaises(exceptions.InvalidParameterValue,
self.drac_client.set_bios_settings, {'foo': 'bar'})
@requests_mock.Mocker()
def test_set_bios_settings_with_unchanged_attr(self, mock_requests):
def test_set_bios_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.BIOSEnumerations[
uris.DCIM_BIOSEnumeration]['ok']},
@ -404,8 +396,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
self.assertEqual({'commit_required': False}, result)
@requests_mock.Mocker()
def test_set_bios_settings_with_readonly_attr(self, mock_requests):
def test_set_bios_settings_with_readonly_attr(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_message = ("Cannot set read-only BIOS attributes: "
"['Proc1NumCores'].")
mock_requests.post('https://1.2.3.4:443/wsman', [
@ -420,8 +412,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
exceptions.DRACOperationFailed, re.escape(expected_message),
self.drac_client.set_bios_settings, {'Proc1NumCores': 42})
@requests_mock.Mocker()
def test_set_bios_settings_with_incorrect_enum_value(self, mock_requests):
def test_set_bios_settings_with_incorrect_enum_value(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_message = ("Attribute 'MemTest' cannot be set to value "
"'foo'. It must be in ['Enabled', 'Disabled'].")
mock_requests.post('https://1.2.3.4:443/wsman', [
@ -436,8 +428,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
exceptions.DRACOperationFailed, re.escape(expected_message),
self.drac_client.set_bios_settings, {'MemTest': 'foo'})
@requests_mock.Mocker()
def test_set_bios_settings_with_incorrect_regexp(self, mock_requests):
def test_set_bios_settings_with_incorrect_regexp(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_message = ("Attribute 'SystemModelName' cannot be set to "
"value 'bar.' It must match regex 'foo'.")
mock_requests.post('https://1.2.3.4:443/wsman', [
@ -452,8 +444,8 @@ class ClientBIOSConfigurationTestCase(base.BaseTest):
exceptions.DRACOperationFailed, re.escape(expected_message),
self.drac_client.set_bios_settings, {'SystemModelName': 'bar'})
@requests_mock.Mocker()
def test_set_bios_settings_with_out_of_bounds_value(self, mock_requests):
def test_set_bios_settings_with_out_of_bounds_value(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_message = ('Attribute Proc1NumCores cannot be set to value '
'-42. It must be between 0 and 65535.')
mock_requests.post('https://1.2.3.4:443/wsman', [

View File

@ -25,12 +25,31 @@ from dracclient.tests import utils as test_utils
@requests_mock.Mocker()
class WSManClientTestCase(base.BaseTest):
def test_enumerate(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_enumerate(self, mock_requests, mock_wait_until_idrac_is_ready):
mock_requests.post('https://1.2.3.4:443/wsman',
text='<result>yay!</result>')
client = dracclient.client.WSManClient(**test_utils.FAKE_ENDPOINT)
resp = client.enumerate('http://resource')
mock_wait_until_idrac_is_ready.assert_called_once_with(
client, constants.DEFAULT_IDRAC_IS_READY_RETRIES,
constants.DEFAULT_IDRAC_IS_READY_RETRY_DELAY_SEC)
self.assertEqual('yay!', resp.text)
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_enumerate_without_wait_for_idrac(
self, mock_requests, mock_wait_until_idrac_is_ready):
mock_requests.post('https://1.2.3.4:443/wsman',
text='<result>yay!</result>')
client = dracclient.client.WSManClient(**test_utils.FAKE_ENDPOINT)
resp = client.enumerate('http://resource', wait_for_idrac=False)
self.assertFalse(mock_wait_until_idrac_is_ready.called)
self.assertEqual('yay!', resp.text)
@mock.patch.object(dracclient.client.WSManClient,

View File

@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import requests_mock
import dracclient.client
@ -28,7 +29,11 @@ class ClientiDRACCardConfigurationTestCase(base.BaseTest):
**test_utils.FAKE_ENDPOINT)
@requests_mock.Mocker()
def test_list_idrac_settings(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_list_idrac_settings(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_enum_attr = idrac_card.iDRACCardEnumerableAttribute(
name='Type',
instance_id='iDRAC.Embedded.1#Info.1#Type',

View File

@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import requests_mock
import dracclient.client
@ -22,6 +23,8 @@ from dracclient.tests import utils as test_utils
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient, 'wait_until_idrac_is_ready',
spec_set=True, autospec=True)
class ClientInventoryManagementTestCase(base.BaseTest):
def setUp(self):
@ -29,7 +32,7 @@ class ClientInventoryManagementTestCase(base.BaseTest):
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
def test_list_cpus(self, mock_requests):
def test_list_cpus(self, mock_requests, mock_wait_until_idrac_is_ready):
expected_cpu = [inventory.CPU(
id='CPU.Socket.1',
cores=6,
@ -49,7 +52,8 @@ class ClientInventoryManagementTestCase(base.BaseTest):
expected_cpu,
self.drac_client.list_cpus())
def test_list_cpus_with_missing_flags(self, mock_requests):
def test_list_cpus_with_missing_flags(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_cpu = [inventory.CPU(
id='CPU.Socket.1',
cores=8,
@ -70,7 +74,7 @@ class ClientInventoryManagementTestCase(base.BaseTest):
expected_cpu,
self.drac_client.list_cpus())
def test_list_memory(self, mock_requests):
def test_list_memory(self, mock_requests, mock_wait_until_idrac_is_ready):
expected_memory = [inventory.Memory(
id='DIMM.Socket.A1',
size_mb=16384,
@ -87,7 +91,7 @@ class ClientInventoryManagementTestCase(base.BaseTest):
expected_memory,
self.drac_client.list_memory())
def test_list_nics(self, mock_requests):
def test_list_nics(self, mock_requests, mock_wait_until_idrac_is_ready):
expected_nics = [
inventory.NIC(
id='NIC.Embedded.1-1-1',

View File

@ -32,7 +32,10 @@ class ClientJobManagementTestCase(base.BaseTest):
**test_utils.FAKE_ENDPOINT)
@requests_mock.Mocker()
def test_list_jobs(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_list_jobs(self, mock_requests, mock_wait_until_idrac_is_ready):
mock_requests.post(
'https://1.2.3.4:443/wsman',
text=test_utils.JobEnumerations[uris.DCIM_LifecycleJob]['ok'])

View File

@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import requests_mock
import dracclient.client
@ -28,7 +29,11 @@ class ClientLifecycleControllerManagementTestCase(base.BaseTest):
**test_utils.FAKE_ENDPOINT)
@requests_mock.Mocker()
def test_get_lifecycle_controller_version(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_get_lifecycle_controller_version(self, mock_requests,
mock_wait_until_idrac_is_ready):
mock_requests.post(
'https://1.2.3.4:443/wsman',
text=test_utils.LifecycleControllerEnumerations[
@ -47,7 +52,11 @@ class ClientLCConfigurationTestCase(base.BaseTest):
**test_utils.FAKE_ENDPOINT)
@requests_mock.Mocker()
def test_list_lifecycle_settings(self, mock_requests):
@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):
expected_enum_attr = lifecycle_controller.LCEnumerableAttribute(
name='Lifecycle Controller State',
instance_id='LifecycleController.Embedded.1#LCAttributes.1#LifecycleControllerState', # noqa

View File

@ -34,7 +34,11 @@ class ClientRAIDManagementTestCase(base.BaseTest):
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
def test_list_raid_controllers(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_list_raid_controllers(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_raid_controller = raid.RAIDController(
id='RAID.Integrated.1-1',
description='Integrated RAID Controller 1',
@ -50,7 +54,11 @@ class ClientRAIDManagementTestCase(base.BaseTest):
self.assertIn(expected_raid_controller,
self.drac_client.list_raid_controllers())
def test_list_virtual_disks(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_list_virtual_disks(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',
@ -75,7 +83,11 @@ class ClientRAIDManagementTestCase(base.BaseTest):
self.assertIn(expected_virtual_disk,
self.drac_client.list_virtual_disks())
def test_list_physical_disks(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_list_physical_disks(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_physical_disk = raid.PhysicalDisk(
id='Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1',
description=('Disk 1 in Backplane 1 of '
@ -99,7 +111,11 @@ class ClientRAIDManagementTestCase(base.BaseTest):
self.assertIn(expected_physical_disk,
self.drac_client.list_physical_disks())
def test_list_physical_disks_direct(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_list_physical_disks_direct(self, mock_requests,
mock_wait_until_idrac_is_ready):
expected_physical_disk = raid.PhysicalDisk(
id='Disk.Direct.2:RAID.Integrated.1-1',
description=('Disk 2 on '

View File

@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import requests_mock
import dracclient.client
@ -28,7 +29,11 @@ class ClientSystemConfigurationTestCase(base.BaseTest):
**test_utils.FAKE_ENDPOINT)
@requests_mock.Mocker()
def test_list_system_settings(self, mock_requests):
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_list_system_settings(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_enum_attr = system.SystemEnumerableAttribute(
name='ChassisLEDState',
instance_id='System.Embedded.1#ChassisPwrState.1#ChassisLEDState', # noqa