diff --git a/dracclient/client.py b/dracclient/client.py index 1020b55..6f05fb6 100644 --- a/dracclient/client.py +++ b/dracclient/client.py @@ -30,6 +30,8 @@ from dracclient.resources import uris from dracclient import utils from dracclient import wsman +IDRAC_IS_READY = "LC061" + LOG = logging.getLogger(__name__) @@ -528,7 +530,7 @@ class DRACClient(object): :raises: DRACUnexpectedReturnValue on return value mismatch """ - return self._lifecycle_cfg.is_idrac_ready() + return self.client.is_idrac_ready() def wait_until_idrac_is_ready(self, retries=24, retry_delay=10): """Waits until the iDRAC is in a ready state @@ -543,23 +545,7 @@ class DRACClient(object): :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) + return self.client.wait_until_idrac_is_ready(retries, retry_delay) class WSManClient(wsman.Client): @@ -606,3 +592,65 @@ class WSManClient(wsman.Client): actual_return_value=return_value) return resp + + 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.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 + + 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) diff --git a/dracclient/resources/lifecycle_controller.py b/dracclient/resources/lifecycle_controller.py index 35c86b9..d0a1c54 100644 --- a/dracclient/resources/lifecycle_controller.py +++ b/dracclient/resources/lifecycle_controller.py @@ -15,8 +15,6 @@ from dracclient.resources import uris from dracclient import utils from dracclient import wsman -IDRAC_IS_READY = "LC061" - class LifecycleControllerManagement(object): @@ -87,37 +85,6 @@ 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""" diff --git a/dracclient/tests/test_client.py b/dracclient/tests/test_client.py index e9395c8..b9ea44b 100644 --- a/dracclient/tests/test_client.py +++ b/dracclient/tests/test_client.py @@ -11,10 +11,12 @@ # 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 uris from dracclient.tests import base from dracclient.tests import utils as test_utils @@ -83,3 +85,48 @@ class WSManClientTestCase(base.BaseTest): self.assertRaises(exceptions.DRACUnexpectedReturnValue, client.invoke, 'http://resource', 'Foo', expected_return_value='4242') + + 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) + + client = dracclient.client.WSManClient(**test_utils.FAKE_ENDPOINT) + self.assertTrue(client.is_idrac_ready()) + + 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) + + client = dracclient.client.WSManClient(**test_utils.FAKE_ENDPOINT) + self.assertFalse(client.is_idrac_ready()) + + 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) + + client = dracclient.client.WSManClient(**test_utils.FAKE_ENDPOINT) + + try: + client.wait_until_idrac_is_ready() + except exceptions.DRACOperationFailed: + self.fail('wait_until_idrac_is_ready() timed out when it should ' + 'not have!') + + @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) + + client = dracclient.client.WSManClient(**test_utils.FAKE_ENDPOINT) + self.assertRaises(exceptions.DRACOperationFailed, + client.wait_until_idrac_is_ready) diff --git a/dracclient/tests/test_lifecycle_controller.py b/dracclient/tests/test_lifecycle_controller.py index ad13431..8498e90 100644 --- a/dracclient/tests/test_lifecycle_controller.py +++ b/dracclient/tests/test_lifecycle_controller.py @@ -11,11 +11,9 @@ # 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 @@ -86,47 +84,3 @@ 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)