diff --git a/watcher/applier/actions/change_node_power_state.py b/watcher/applier/actions/change_node_power_state.py index 1a085e95e..aa027fd8b 100644 --- a/watcher/applier/actions/change_node_power_state.py +++ b/watcher/applier/actions/change_node_power_state.py @@ -18,6 +18,7 @@ # import enum +import time from watcher._i18n import _ from watcher.applier.actions import base @@ -87,25 +88,39 @@ class ChangeNodePowerState(base.BaseAction): target_state = NodeState.POWERON.value return self._node_manage_power(target_state) - def _node_manage_power(self, state): + def _node_manage_power(self, state, retry=60): if state is None: raise exception.IllegalArgumentException( message=_("The target state is not defined")) - result = False ironic_client = self.osc.ironic() nova_client = self.osc.nova() + current_state = ironic_client.node.get(self.node_uuid).power_state + # power state: 'power on' or 'power off', if current node state + # is the same as state, just return True + if state in current_state: + return True + if state == NodeState.POWEROFF.value: node_info = ironic_client.node.get(self.node_uuid).to_dict() compute_node_id = node_info['extra']['compute_node_id'] compute_node = nova_client.hypervisors.get(compute_node_id) compute_node = compute_node.to_dict() if (compute_node['running_vms'] == 0): - result = ironic_client.node.set_power_state( + ironic_client.node.set_power_state( self.node_uuid, state) else: - result = ironic_client.node.set_power_state(self.node_uuid, state) - return result + ironic_client.node.set_power_state(self.node_uuid, state) + + ironic_node = ironic_client.node.get(self.node_uuid) + while ironic_node.power_state == current_state and retry: + time.sleep(10) + retry -= 1 + ironic_node = ironic_client.node.get(self.node_uuid) + if retry > 0: + return True + else: + return False def pre_condition(self): pass diff --git a/watcher/tests/applier/actions/test_change_node_power_state.py b/watcher/tests/applier/actions/test_change_node_power_state.py index ca6099595..343416a67 100644 --- a/watcher/tests/applier/actions/test_change_node_power_state.py +++ b/watcher/tests/applier/actions/test_change_node_power_state.py @@ -90,7 +90,14 @@ class TestChangeNodePowerState(base.TestCase): def test_execute_node_service_state_with_poweron_target( self, mock_ironic, mock_nova): mock_irclient = mock_ironic.return_value - self.action.execute() + self.action.input_parameters["state"] = ( + change_node_power_state.NodeState.POWERON.value) + mock_irclient.node.get.side_effect = [ + mock.MagicMock(power_state='power off'), + mock.MagicMock(power_state='power on')] + + result = self.action.execute() + self.assertTrue(result) mock_irclient.node.set_power_state.assert_called_once_with( COMPUTE_NODE, change_node_power_state.NodeState.POWERON.value) @@ -104,7 +111,12 @@ class TestChangeNodePowerState(base.TestCase): mock_nvclient.hypervisors.get.return_value = mock_get self.action.input_parameters["state"] = ( change_node_power_state.NodeState.POWEROFF.value) - self.action.execute() + mock_irclient.node.get.side_effect = [ + mock.MagicMock(power_state='power on'), + mock.MagicMock(power_state='power on'), + mock.MagicMock(power_state='power off')] + result = self.action.execute() + self.assertTrue(result) mock_irclient.node.set_power_state.assert_called_once_with( COMPUTE_NODE, change_node_power_state.NodeState.POWEROFF.value) @@ -118,6 +130,10 @@ class TestChangeNodePowerState(base.TestCase): mock_nvclient.hypervisors.get.return_value = mock_get self.action.input_parameters["state"] = ( change_node_power_state.NodeState.POWERON.value) + mock_irclient.node.get.side_effect = [ + mock.MagicMock(power_state='power on'), + mock.MagicMock(power_state='power on'), + mock.MagicMock(power_state='power off')] self.action.revert() mock_irclient.node.set_power_state.assert_called_once_with( @@ -128,6 +144,9 @@ class TestChangeNodePowerState(base.TestCase): mock_irclient = mock_ironic.return_value self.action.input_parameters["state"] = ( change_node_power_state.NodeState.POWEROFF.value) + mock_irclient.node.get.side_effect = [ + mock.MagicMock(power_state='power off'), + mock.MagicMock(power_state='power on')] self.action.revert() mock_irclient.node.set_power_state.assert_called_once_with(