Added ability to determine if an iDRAC is ready

This patch adds the ability to determine if an iDRAC is ready to accept
commands.

Change-Id: I929deada3dda7b09a6f29033fff89d9b0382aef8
Partial-Bug: 1691808
This commit is contained in:
Christopher Dearborn 2017-05-19 14:05:50 -04:00
parent f49efaa1bf
commit 39253bb272
6 changed files with 175 additions and 0 deletions

View File

@ -16,6 +16,7 @@ Wrapper for pywsman.Client
"""
import logging
import time
from dracclient import exceptions
from dracclient.resources import bios
@ -496,6 +497,53 @@ class DRACClient(object):
return self._inventory_mgmt.list_nics()
def is_idrac_ready(self):
"""Indicates if the iDRAC is ready to accept commands
Returns a boolean indicating if the iDRAC is ready to accept
commands.
:returns: Boolean indicating iDRAC readiness
: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._lifecycle_cfg.is_idrac_ready()
def wait_until_idrac_is_ready(self, retries=24, retry_delay=10):
"""Waits until the iDRAC is in a ready state
:param retries: The number of times to check if the iDRAC is ready
:param retry_delay: The number of seconds to wait between retries
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the DRAC
interface or timeout
:raises: DRACUnexpectedReturnValue on return value mismatch
"""
# Try every 10 seconds over 4 minutes for the iDRAC to become ready
while retries > 0:
LOG.debug("Checking to see if the iDRAC is ready")
if self.is_idrac_ready():
LOG.debug("The iDRAC is ready")
return
LOG.debug("The iDRAC is not ready")
retries -= 1
if retries > 0:
time.sleep(retry_delay)
if retries == 0:
err_msg = "Timed out waiting for the iDRAC to become ready"
LOG.error(err_msg)
raise exceptions.DRACOperationFailed(drac_messages=err_msg)
class WSManClient(wsman.Client):
"""Wrapper for wsman.Client with return value checking"""

View File

@ -15,6 +15,8 @@ from dracclient.resources import uris
from dracclient import utils
from dracclient import wsman
IDRAC_IS_READY = "LC061"
class LifecycleControllerManagement(object):
@ -85,6 +87,37 @@ class LCConfiguration(object):
return result
def is_idrac_ready(self):
"""Indicates if the iDRAC is ready to accept commands
Returns a boolean indicating if the iDRAC is ready to accept
commands.
:returns: Boolean indicating iDRAC readiness
: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',
'SystemName': 'DCIM:ComputerSystem',
'CreationClassName': 'DCIM_LCService',
'Name': 'DCIM:LCService'}
result = self.client.invoke(uris.DCIM_LCService,
'GetRemoteServicesAPIStatus',
selectors,
{},
expected_return_value=utils.RET_SUCCESS)
message_id = utils.find_xml(result,
'MessageID',
uris.DCIM_LCService).text
return message_id == IDRAC_IS_READY
class LCAttribute(object):
"""Generic LC attribute class"""

View File

@ -11,9 +11,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import requests_mock
import dracclient.client
from dracclient import exceptions
from dracclient.resources import lifecycle_controller
from dracclient.resources import uris
from dracclient.tests import base
@ -84,3 +86,47 @@ class ClientLCConfigurationTestCase(base.BaseTest):
lifecycle_settings)
self.assertEqual(expected_string_attr,
lifecycle_settings['LifecycleController.Embedded.1#LCAttributes.1#SystemID']) # noqa
@requests_mock.Mocker()
def test_is_idrac_ready_ready(self, mock_requests):
expected_text = test_utils.LifecycleControllerInvocations[
uris.DCIM_LCService]['GetRemoteServicesAPIStatus']['is_ready']
mock_requests.post('https://1.2.3.4:443/wsman',
text=expected_text)
self.assertTrue(self.drac_client.is_idrac_ready())
@requests_mock.Mocker()
def test_is_idrac_ready_not_ready(self, mock_requests):
expected_text = test_utils.LifecycleControllerInvocations[
uris.DCIM_LCService]['GetRemoteServicesAPIStatus']['is_not_ready']
mock_requests.post('https://1.2.3.4:443/wsman',
text=expected_text)
self.assertFalse(self.drac_client.is_idrac_ready())
@requests_mock.Mocker()
def test_wait_until_idrac_is_ready_ready(self, mock_requests):
expected_text = test_utils.LifecycleControllerInvocations[
uris.DCIM_LCService]['GetRemoteServicesAPIStatus']['is_ready']
mock_requests.post('https://1.2.3.4:443/wsman',
text=expected_text)
try:
self.drac_client.wait_until_idrac_is_ready()
except exceptions.DRACOperationFailed:
self.fail('wait_until_idrac_is_ready() timed out when it should '
'not have!')
@requests_mock.Mocker()
@mock.patch('time.sleep', autospec=True)
def test_wait_until_idrac_is_ready_timeout(self,
mock_requests,
mock_ts):
expected_text = test_utils.LifecycleControllerInvocations[
uris.DCIM_LCService]['GetRemoteServicesAPIStatus']['is_not_ready']
mock_requests.post('https://1.2.3.4:443/wsman',
text=expected_text)
self.assertRaises(exceptions.DRACOperationFailed,
self.drac_client.wait_until_idrac_is_ready)

View File

@ -159,6 +159,16 @@ LifecycleControllerEnumerations = {
}
}
LifecycleControllerInvocations = {
uris.DCIM_LCService: {
'GetRemoteServicesAPIStatus': {
'is_ready': load_wsman_xml('lc_getremoteservicesapistatus_ready'),
'is_not_ready': load_wsman_xml(
'lc_getremoteservicesapistatus_not_ready')
}
}
}
RAIDEnumerations = {
uris.DCIM_ControllerView: {
'ok': load_wsman_xml('controller_view-enum-ok')

View File

@ -0,0 +1,19 @@
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:n1="http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService">
<s:Header>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsa:Action>http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/GetRemoteServicesAPIStatusResponse</wsa:Action>
<wsa:RelatesTo>uuid:3ef0c018-3169-4184-9d81-ee1a73059940</wsa:RelatesTo>
<wsa:MessageID>uuid:9d5ff7cc-4fc0-1fc0-8090-98d61742a844</wsa:MessageID>
</s:Header>
<s:Body>
<n1:GetRemoteServicesAPIStatus_OUTPUT>
<n1:LCStatus>5</n1:LCStatus>
<n1:Message>Lifecycle Controller Remote Services is not ready.</n1:Message>
<n1:MessageID>LC060</n1:MessageID>
<n1:RTStatus>0</n1:RTStatus>
<n1:ReturnValue>0</n1:ReturnValue>
<n1:ServerStatus>2</n1:ServerStatus>
<n1:Status>1</n1:Status>
</n1:GetRemoteServicesAPIStatus_OUTPUT>
</s:Body>
</s:Envelope>

View File

@ -0,0 +1,19 @@
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:n1="http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService">
<s:Header>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsa:Action>http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/GetRemoteServicesAPIStatusResponse</wsa:Action>
<wsa:RelatesTo>uuid:18745811-2782-4d30-a288-8f001a895215</wsa:RelatesTo>
<wsa:MessageID>uuid:9ec203ba-4fc0-1fc0-8094-98d61742a844</wsa:MessageID>
</s:Header>
<s:Body>
<n1:GetRemoteServicesAPIStatus_OUTPUT>
<n1:LCStatus>0</n1:LCStatus>
<n1:Message>Lifecycle Controller Remote Services is ready.</n1:Message>
<n1:MessageID>LC061</n1:MessageID>
<n1:RTStatus>0</n1:RTStatus>
<n1:ReturnValue>0</n1:ReturnValue>
<n1:ServerStatus>2</n1:ServerStatus>
<n1:Status>0</n1:Status>
</n1:GetRemoteServicesAPIStatus_OUTPUT>
</s:Body>
</s:Envelope>