summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Dearborn <Christopher_Dearborn@dell.com>2017-05-19 14:05:50 -0400
committerChristopher Dearborn <Christopher_Dearborn@dell.com>2017-05-30 16:42:02 -0400
commit39253bb272a7d4cfcc161c19708b8c6949a21240 (patch)
tree9dd3fe388a895d351d0cf67f9fa46168f7d435af
parentf49efaa1bfd20eb7d94366f0665df01d9b0d10b4 (diff)
Added ability to determine if an iDRAC is ready1.2.0
This patch adds the ability to determine if an iDRAC is ready to accept commands. Change-Id: I929deada3dda7b09a6f29033fff89d9b0382aef8 Partial-Bug: 1691808
Notes
Notes (review): Code-Review+2: Richard G. Pioso <richard.pioso@dell.com> Code-Review+2: Dmitry Tantsur <divius.inside@gmail.com> Workflow+1: Dmitry Tantsur <divius.inside@gmail.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Thu, 01 Jun 2017 16:14:25 +0000 Reviewed-on: https://review.openstack.org/466371 Project: openstack/python-dracclient Branch: refs/heads/master
-rw-r--r--dracclient/client.py48
-rw-r--r--dracclient/resources/lifecycle_controller.py33
-rw-r--r--dracclient/tests/test_lifecycle_controller.py46
-rw-r--r--dracclient/tests/utils.py10
-rw-r--r--dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_not_ready.xml19
-rw-r--r--dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_ready.xml19
6 files changed, 175 insertions, 0 deletions
diff --git a/dracclient/client.py b/dracclient/client.py
index 04cafa1..7358c86 100644
--- a/dracclient/client.py
+++ b/dracclient/client.py
@@ -16,6 +16,7 @@ Wrapper for pywsman.Client
16""" 16"""
17 17
18import logging 18import logging
19import time
19 20
20from dracclient import exceptions 21from dracclient import exceptions
21from dracclient.resources import bios 22from dracclient.resources import bios
@@ -496,6 +497,53 @@ class DRACClient(object):
496 497
497 return self._inventory_mgmt.list_nics() 498 return self._inventory_mgmt.list_nics()
498 499
500 def is_idrac_ready(self):
501 """Indicates if the iDRAC is ready to accept commands
502
503 Returns a boolean indicating if the iDRAC is ready to accept
504 commands.
505
506 :returns: Boolean indicating iDRAC readiness
507 :raises: WSManRequestFailure on request failures
508 :raises: WSManInvalidResponse when receiving invalid response
509 :raises: DRACOperationFailed on error reported back by the DRAC
510 interface
511 :raises: DRACUnexpectedReturnValue on return value mismatch
512 """
513
514 return self._lifecycle_cfg.is_idrac_ready()
515
516 def wait_until_idrac_is_ready(self, retries=24, retry_delay=10):
517 """Waits until the iDRAC is in a ready state
518
519 :param retries: The number of times to check if the iDRAC is ready
520 :param retry_delay: The number of seconds to wait between retries
521
522 :raises: WSManRequestFailure on request failures
523 :raises: WSManInvalidResponse when receiving invalid response
524 :raises: DRACOperationFailed on error reported back by the DRAC
525 interface or timeout
526 :raises: DRACUnexpectedReturnValue on return value mismatch
527 """
528
529 # Try every 10 seconds over 4 minutes for the iDRAC to become ready
530 while retries > 0:
531 LOG.debug("Checking to see if the iDRAC is ready")
532
533 if self.is_idrac_ready():
534 LOG.debug("The iDRAC is ready")
535 return
536
537 LOG.debug("The iDRAC is not ready")
538 retries -= 1
539 if retries > 0:
540 time.sleep(retry_delay)
541
542 if retries == 0:
543 err_msg = "Timed out waiting for the iDRAC to become ready"
544 LOG.error(err_msg)
545 raise exceptions.DRACOperationFailed(drac_messages=err_msg)
546
499 547
500class WSManClient(wsman.Client): 548class WSManClient(wsman.Client):
501 """Wrapper for wsman.Client with return value checking""" 549 """Wrapper for wsman.Client with return value checking"""
diff --git a/dracclient/resources/lifecycle_controller.py b/dracclient/resources/lifecycle_controller.py
index d0a1c54..35c86b9 100644
--- a/dracclient/resources/lifecycle_controller.py
+++ b/dracclient/resources/lifecycle_controller.py
@@ -15,6 +15,8 @@ from dracclient.resources import uris
15from dracclient import utils 15from dracclient import utils
16from dracclient import wsman 16from dracclient import wsman
17 17
18IDRAC_IS_READY = "LC061"
19
18 20
19class LifecycleControllerManagement(object): 21class LifecycleControllerManagement(object):
20 22
@@ -85,6 +87,37 @@ class LCConfiguration(object):
85 87
86 return result 88 return result
87 89
90 def is_idrac_ready(self):
91 """Indicates if the iDRAC is ready to accept commands
92
93 Returns a boolean indicating if the iDRAC is ready to accept
94 commands.
95
96 :returns: Boolean indicating iDRAC readiness
97 :raises: WSManRequestFailure on request failures
98 :raises: WSManInvalidResponse when receiving invalid response
99 :raises: DRACOperationFailed on error reported back by the DRAC
100 interface
101 :raises: DRACUnexpectedReturnValue on return value mismatch
102 """
103
104 selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
105 'SystemName': 'DCIM:ComputerSystem',
106 'CreationClassName': 'DCIM_LCService',
107 'Name': 'DCIM:LCService'}
108
109 result = self.client.invoke(uris.DCIM_LCService,
110 'GetRemoteServicesAPIStatus',
111 selectors,
112 {},
113 expected_return_value=utils.RET_SUCCESS)
114
115 message_id = utils.find_xml(result,
116 'MessageID',
117 uris.DCIM_LCService).text
118
119 return message_id == IDRAC_IS_READY
120
88 121
89class LCAttribute(object): 122class LCAttribute(object):
90 """Generic LC attribute class""" 123 """Generic LC attribute class"""
diff --git a/dracclient/tests/test_lifecycle_controller.py b/dracclient/tests/test_lifecycle_controller.py
index 8498e90..ad13431 100644
--- a/dracclient/tests/test_lifecycle_controller.py
+++ b/dracclient/tests/test_lifecycle_controller.py
@@ -11,9 +11,11 @@
11# License for the specific language governing permissions and limitations 11# License for the specific language governing permissions and limitations
12# under the License. 12# under the License.
13 13
14import mock
14import requests_mock 15import requests_mock
15 16
16import dracclient.client 17import dracclient.client
18from dracclient import exceptions
17from dracclient.resources import lifecycle_controller 19from dracclient.resources import lifecycle_controller
18from dracclient.resources import uris 20from dracclient.resources import uris
19from dracclient.tests import base 21from dracclient.tests import base
@@ -84,3 +86,47 @@ class ClientLCConfigurationTestCase(base.BaseTest):
84 lifecycle_settings) 86 lifecycle_settings)
85 self.assertEqual(expected_string_attr, 87 self.assertEqual(expected_string_attr,
86 lifecycle_settings['LifecycleController.Embedded.1#LCAttributes.1#SystemID']) # noqa 88 lifecycle_settings['LifecycleController.Embedded.1#LCAttributes.1#SystemID']) # noqa
89
90 @requests_mock.Mocker()
91 def test_is_idrac_ready_ready(self, mock_requests):
92 expected_text = test_utils.LifecycleControllerInvocations[
93 uris.DCIM_LCService]['GetRemoteServicesAPIStatus']['is_ready']
94 mock_requests.post('https://1.2.3.4:443/wsman',
95 text=expected_text)
96
97 self.assertTrue(self.drac_client.is_idrac_ready())
98
99 @requests_mock.Mocker()
100 def test_is_idrac_ready_not_ready(self, mock_requests):
101 expected_text = test_utils.LifecycleControllerInvocations[
102 uris.DCIM_LCService]['GetRemoteServicesAPIStatus']['is_not_ready']
103 mock_requests.post('https://1.2.3.4:443/wsman',
104 text=expected_text)
105
106 self.assertFalse(self.drac_client.is_idrac_ready())
107
108 @requests_mock.Mocker()
109 def test_wait_until_idrac_is_ready_ready(self, mock_requests):
110 expected_text = test_utils.LifecycleControllerInvocations[
111 uris.DCIM_LCService]['GetRemoteServicesAPIStatus']['is_ready']
112 mock_requests.post('https://1.2.3.4:443/wsman',
113 text=expected_text)
114
115 try:
116 self.drac_client.wait_until_idrac_is_ready()
117 except exceptions.DRACOperationFailed:
118 self.fail('wait_until_idrac_is_ready() timed out when it should '
119 'not have!')
120
121 @requests_mock.Mocker()
122 @mock.patch('time.sleep', autospec=True)
123 def test_wait_until_idrac_is_ready_timeout(self,
124 mock_requests,
125 mock_ts):
126 expected_text = test_utils.LifecycleControllerInvocations[
127 uris.DCIM_LCService]['GetRemoteServicesAPIStatus']['is_not_ready']
128 mock_requests.post('https://1.2.3.4:443/wsman',
129 text=expected_text)
130
131 self.assertRaises(exceptions.DRACOperationFailed,
132 self.drac_client.wait_until_idrac_is_ready)
diff --git a/dracclient/tests/utils.py b/dracclient/tests/utils.py
index 4ce55db..e7ebad8 100644
--- a/dracclient/tests/utils.py
+++ b/dracclient/tests/utils.py
@@ -159,6 +159,16 @@ LifecycleControllerEnumerations = {
159 } 159 }
160} 160}
161 161
162LifecycleControllerInvocations = {
163 uris.DCIM_LCService: {
164 'GetRemoteServicesAPIStatus': {
165 'is_ready': load_wsman_xml('lc_getremoteservicesapistatus_ready'),
166 'is_not_ready': load_wsman_xml(
167 'lc_getremoteservicesapistatus_not_ready')
168 }
169 }
170}
171
162RAIDEnumerations = { 172RAIDEnumerations = {
163 uris.DCIM_ControllerView: { 173 uris.DCIM_ControllerView: {
164 'ok': load_wsman_xml('controller_view-enum-ok') 174 'ok': load_wsman_xml('controller_view-enum-ok')
diff --git a/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_not_ready.xml b/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_not_ready.xml
new file mode 100644
index 0000000..accd14f
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_not_ready.xml
@@ -0,0 +1,19 @@
1<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">
2 <s:Header>
3 <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
4 <wsa:Action>http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/GetRemoteServicesAPIStatusResponse</wsa:Action>
5 <wsa:RelatesTo>uuid:3ef0c018-3169-4184-9d81-ee1a73059940</wsa:RelatesTo>
6 <wsa:MessageID>uuid:9d5ff7cc-4fc0-1fc0-8090-98d61742a844</wsa:MessageID>
7 </s:Header>
8 <s:Body>
9 <n1:GetRemoteServicesAPIStatus_OUTPUT>
10 <n1:LCStatus>5</n1:LCStatus>
11 <n1:Message>Lifecycle Controller Remote Services is not ready.</n1:Message>
12 <n1:MessageID>LC060</n1:MessageID>
13 <n1:RTStatus>0</n1:RTStatus>
14 <n1:ReturnValue>0</n1:ReturnValue>
15 <n1:ServerStatus>2</n1:ServerStatus>
16 <n1:Status>1</n1:Status>
17 </n1:GetRemoteServicesAPIStatus_OUTPUT>
18 </s:Body>
19</s:Envelope>
diff --git a/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_ready.xml b/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_ready.xml
new file mode 100644
index 0000000..c7dd1c9
--- /dev/null
+++ b/dracclient/tests/wsman_mocks/lc_getremoteservicesapistatus_ready.xml
@@ -0,0 +1,19 @@
1<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">
2 <s:Header>
3 <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
4 <wsa:Action>http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_LCService/GetRemoteServicesAPIStatusResponse</wsa:Action>
5 <wsa:RelatesTo>uuid:18745811-2782-4d30-a288-8f001a895215</wsa:RelatesTo>
6 <wsa:MessageID>uuid:9ec203ba-4fc0-1fc0-8094-98d61742a844</wsa:MessageID>
7 </s:Header>
8 <s:Body>
9 <n1:GetRemoteServicesAPIStatus_OUTPUT>
10 <n1:LCStatus>0</n1:LCStatus>
11 <n1:Message>Lifecycle Controller Remote Services is ready.</n1:Message>
12 <n1:MessageID>LC061</n1:MessageID>
13 <n1:RTStatus>0</n1:RTStatus>
14 <n1:ReturnValue>0</n1:ReturnValue>
15 <n1:ServerStatus>2</n1:ServerStatus>
16 <n1:Status>0</n1:Status>
17 </n1:GetRemoteServicesAPIStatus_OUTPUT>
18 </s:Body>
19</s:Envelope>