diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index fcc52152..06ad50cf 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -60,6 +60,8 @@ SUPPORTED_RIS_METHODS = [ SUPPORTED_REDFISH_METHODS = [ 'get_product_name', 'get_host_power_status', + 'set_host_power', + 'reset_server', ] LOG = log.get_logger(__name__) diff --git a/proliantutils/redfish/redfish.py b/proliantutils/redfish/redfish.py index 540b97b0..808e26e3 100644 --- a/proliantutils/redfish/redfish.py +++ b/proliantutils/redfish/redfish.py @@ -33,6 +33,11 @@ GET_POWER_STATE_MAP = { sushy.SYSTEM_POWER_STATE_POWERING_OFF: 'OFF' } +POWER_RESET_MAP = { + 'ON': sushy.RESET_ON, + 'OFF': sushy.RESET_FORCE_OFF, +} + PROLIANT_SYSTEM_ID = '1' LOG = log.get_logger(__name__) @@ -138,3 +143,55 @@ class RedfishOperations(operations.IloOperations): # as we are dealing with iLO's here. sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) return GET_POWER_STATE_MAP.get(sushy_system.power_state) + + def reset_server(self): + """Resets the server. + + :raises: IloError, on an error from iLO. + """ + # Assuming only one sushy_system present as part of collection, + # as we are dealing with iLO's here. + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + try: + sushy_system.reset_system(sushy.RESET_FORCE_RESTART) + except sushy.exceptions.SushyError as e: + msg = (self._('The Redfish controller failed to reset server. ' + 'Error %(error)s') % + {'error': str(e)}) + LOG.debug(msg) + raise exception.IloError(msg) + + def set_host_power(self, target_value): + """Sets the power state of the system. + + :param target_value: The target value to be set. Value can be: + 'ON' or 'OFF'. + :raises: IloError, on an error from iLO. + :raises: InvalidInputError, if the target value is not + allowed. + """ + if target_value not in POWER_RESET_MAP: + msg = ('The parameter "%(parameter)s" value "%(target_value)s" is ' + 'invalid. Valid values are: %(valid_power_values)s' % + {'parameter': 'target_value', 'target_value': target_value, + 'valid_power_values': POWER_RESET_MAP.keys()}) + raise exception.InvalidInputError(msg) + + # Check current power status, do not act if it's in requested state. + current_power_status = self.get_host_power_status() + if current_power_status == target_value: + LOG.debug(self._("Node is already in '%(target_value)s' power " + "state."), {'target_value': target_value}) + return + + # Assuming only one system present as part of collection, + # as we are dealing with iLO's here. + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + try: + sushy_system.reset_system(POWER_RESET_MAP[target_value]) + except sushy.exceptions.SushyError as e: + msg = (self._('The Redfish controller failed to set power state ' + 'of server to %(target_value)s. Error %(error)s') % + {'target_value': target_value, 'error': str(e)}) + LOG.debug(msg) + raise exception.IloError(msg) diff --git a/proliantutils/tests/redfish/test_redfish.py b/proliantutils/tests/redfish/test_redfish.py index 0df709b0..3cd32e70 100644 --- a/proliantutils/tests/redfish/test_redfish.py +++ b/proliantutils/tests/redfish/test_redfish.py @@ -78,3 +78,46 @@ class RedfishOperationsTestCase(testtools.TestCase): self.sushy.get_system().power_state = sushy.SYSTEM_POWER_STATE_ON power_state = self.rf_client.get_host_power_status() self.assertEqual('ON', power_state) + + def test_reset_server(self): + self.rf_client.reset_server() + self.sushy.get_system().reset_system.assert_called_once_with( + sushy.RESET_FORCE_RESTART) + + def test_reset_server_invalid_value(self): + self.sushy.get_system().reset_system.side_effect = ( + sushy.exceptions.SushyError) + self.assertRaisesRegex( + exception.IloError, + 'The Redfish controller failed to reset server.', + self.rf_client.reset_server) + + @mock.patch.object(redfish.RedfishOperations, 'get_host_power_status') + def test_set_host_power_no_change(self, get_host_power_status_mock): + get_host_power_status_mock.return_value = 'ON' + self.rf_client.set_host_power('ON') + self.assertTrue(get_host_power_status_mock.called) + self.assertFalse(self.sushy.get_system().reset_system.called) + + @mock.patch.object(redfish.RedfishOperations, 'get_host_power_status') + def test_set_host_power_failure(self, get_host_power_status_mock): + get_host_power_status_mock.return_value = 'OFF' + self.sushy.get_system().reset_system.side_effect = ( + sushy.exceptions.SushyError) + self.assertRaisesRegex( + exception.IloError, + 'The Redfish controller failed to set power state of server to ON', + self.rf_client.set_host_power, 'ON') + + def test_set_host_power_invalid_input(self): + self.assertRaisesRegex( + exception.InvalidInputError, + 'The parameter "target_value" value "Off" is invalid.', + self.rf_client.set_host_power, 'Off') + + @mock.patch.object(redfish.RedfishOperations, 'get_host_power_status') + def test_set_host_power_change(self, get_host_power_status_mock): + get_host_power_status_mock.return_value = 'OFF' + self.rf_client.set_host_power('ON') + self.sushy.get_system().reset_system.assert_called_once_with( + sushy.RESET_ON)