From 90a52931ddfa1f65a57cd488e2890d0df02fc38b Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 2 Nov 2015 15:30:31 -0500 Subject: [PATCH] iboot: add wait loop for pstate to activate Add a short retry loop so that power state changes can have some time to become active on iboot devices with remote switches. Closes bug: #1512478 Change-Id: Ifad4b6a22f0289b2bcec25528566326a2688e76b --- ironic/drivers/modules/iboot.py | 21 ++++++++++++------- .../tests/unit/drivers/modules/test_iboot.py | 16 ++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/ironic/drivers/modules/iboot.py b/ironic/drivers/modules/iboot.py index c784c371c7..7bb534c43e 100644 --- a/ironic/drivers/modules/iboot.py +++ b/ironic/drivers/modules/iboot.py @@ -151,6 +151,18 @@ def _sleep_switch(seconds): time.sleep(seconds) +def _check_power_state(driver_info, pstate): + """Function to check power state is correct. Up to max retries.""" + # always try once + number of retries + for num in range(0, 1 + CONF.iboot.max_retry): + state = _power_status(driver_info) + if state == pstate: + return + if num < CONF.iboot.max_retry: + time.sleep(CONF.iboot.retry_interval) + raise exception.PowerStateFailure(pstate=pstate) + + def _power_status(driver_info): conn = _get_connection(driver_info) relay_id = driver_info['relay_id'] @@ -251,9 +263,7 @@ class IBootPower(base.PowerInterface): _("set_power_state called with invalid " "power state %s.") % pstate) - state = _power_status(driver_info) - if state != pstate: - raise exception.PowerStateFailure(pstate=pstate) + _check_power_state(driver_info, pstate) @task_manager.require_exclusive_lock def reboot(self, task): @@ -272,7 +282,4 @@ class IBootPower(base.PowerInterface): _switch(driver_info, False) _sleep_switch(CONF.iboot.reboot_delay) _switch(driver_info, True) - - state = _power_status(driver_info) - if state != states.POWER_ON: - raise exception.PowerStateFailure(pstate=states.POWER_ON) + _check_power_state(driver_info, states.POWER_ON) diff --git a/ironic/tests/unit/drivers/modules/test_iboot.py b/ironic/tests/unit/drivers/modules/test_iboot.py index fffb21cc05..aa1e565236 100644 --- a/ironic/tests/unit/drivers/modules/test_iboot.py +++ b/ironic/tests/unit/drivers/modules/test_iboot.py @@ -300,6 +300,22 @@ class IBootDriverTestCase(db_base.DbTestCase): mock_switch.assert_called_once_with(self.info, True) mock_power_status.assert_called_once_with(self.info) + @mock.patch.object(iboot, '_power_status', autospec=True) + @mock.patch.object(iboot, '_switch', autospec=True) + def test_set_power_state_retry(self, mock_switch, mock_power_status): + self.config(max_retry=2, group='iboot') + mock_power_status.return_value = states.POWER_OFF + + with task_manager.acquire(self.context, self.node.uuid) as task: + self.assertRaises(exception.PowerStateFailure, + task.driver.power.set_power_state, + task, states.POWER_ON) + + # ensure functions were called with the valid parameters + mock_switch.assert_called_once_with(self.info, True) + # 1 + 2 retries + self.assertEqual(3, mock_power_status.call_count) + @mock.patch.object(iboot, '_power_status', autospec=True) @mock.patch.object(iboot, '_switch', autospec=True) def test_set_power_state_invalid_parameter(self, mock_switch,