Redfish: Add system push power button operations
This patch adds system power operations in proliantutils via redfish way. These 2 methods are introduced on redfish ops: 1) press_pwr_btn 2) hold_pwr_btn Change-Id: Ie6281b9ad608e50fc274a8e1b32d539b6a174e5d Partial-Bug: 1691955
This commit is contained in:
parent
840f7d72f7
commit
e2f1bb4167
|
@ -62,6 +62,8 @@ SUPPORTED_REDFISH_METHODS = [
|
|||
'get_host_power_status',
|
||||
'set_host_power',
|
||||
'reset_server',
|
||||
'press_pwr_btn',
|
||||
'hold_pwr_btn',
|
||||
]
|
||||
|
||||
LOG = log.get_logger(__name__)
|
||||
|
|
|
@ -21,7 +21,7 @@ from proliantutils import exception
|
|||
from proliantutils.ilo import operations
|
||||
from proliantutils import log
|
||||
from proliantutils.redfish import main
|
||||
|
||||
from proliantutils.redfish.resources.system import constants as sys_cons
|
||||
|
||||
"""
|
||||
Class specific for Redfish APIs.
|
||||
|
@ -39,6 +39,8 @@ POWER_RESET_MAP = {
|
|||
'OFF': sushy.RESET_FORCE_OFF,
|
||||
}
|
||||
|
||||
# Assuming only one sushy_system present as part of collection,
|
||||
# as we are dealing with iLO's here.
|
||||
PROLIANT_SYSTEM_ID = '1'
|
||||
|
||||
LOG = log.get_logger(__name__)
|
||||
|
@ -47,17 +49,11 @@ LOG = log.get_logger(__name__)
|
|||
class RedfishOperations(operations.IloOperations):
|
||||
"""Operations supported on redfish based hardware.
|
||||
|
||||
This is the list of APIs which are currently supported via Redfish mode
|
||||
This class holds APIs which are currently supported via Redfish mode
|
||||
of operation. This is a growing list which needs to be updated as and when
|
||||
the existing API/s (of its cousin RIS and RIBCL interfaces) are migrated.
|
||||
|
||||
--- START ---
|
||||
|
||||
* get_product_name(self)
|
||||
* get_host_power_status(self)
|
||||
|
||||
--- END ---
|
||||
|
||||
For operations currently supported on the client object, please refer:
|
||||
*proliantutils.ilo.client.SUPPORTED_REDFISH_METHODS*
|
||||
"""
|
||||
|
||||
def __init__(self, redfish_controller_ip, username, password,
|
||||
|
@ -129,8 +125,6 @@ class RedfishOperations(operations.IloOperations):
|
|||
:returns: server model name.
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
# 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)
|
||||
return sushy_system.json.get('Model')
|
||||
|
||||
|
@ -140,8 +134,6 @@ class RedfishOperations(operations.IloOperations):
|
|||
:returns: Power State of the server, 'ON' or 'OFF'
|
||||
: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)
|
||||
return GET_POWER_STATE_MAP.get(sushy_system.power_state)
|
||||
|
||||
|
@ -150,8 +142,6 @@ class RedfishOperations(operations.IloOperations):
|
|||
|
||||
: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)
|
||||
|
@ -185,8 +175,6 @@ class RedfishOperations(operations.IloOperations):
|
|||
"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])
|
||||
|
@ -196,3 +184,34 @@ class RedfishOperations(operations.IloOperations):
|
|||
{'target_value': target_value, 'error': str(e)})
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
|
||||
def press_pwr_btn(self):
|
||||
"""Simulates a physical press of the server power button.
|
||||
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID)
|
||||
try:
|
||||
sushy_system.push_power_button(sys_cons.PUSH_POWER_BUTTON_PRESS)
|
||||
except sushy.exceptions.SushyError as e:
|
||||
msg = (self._('The Redfish controller failed to press power button'
|
||||
' of server. Error %(error)s') %
|
||||
{'error': str(e)})
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
|
||||
def hold_pwr_btn(self):
|
||||
"""Simulate a physical press and hold of the server power button.
|
||||
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID)
|
||||
try:
|
||||
sushy_system.push_power_button(
|
||||
sys_cons.PUSH_POWER_BUTTON_PRESS_AND_HOLD)
|
||||
except sushy.exceptions.SushyError as e:
|
||||
msg = (self._('The Redfish controller failed to press and hold '
|
||||
'power button of server. Error %(error)s') %
|
||||
{'error': str(e)})
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# Push power button action constants
|
||||
|
||||
PUSH_POWER_BUTTON_PRESS = 'press'
|
||||
PUSH_POWER_BUTTON_PRESS_AND_HOLD = 'press and hold'
|
|
@ -0,0 +1,27 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from sushy import utils
|
||||
|
||||
from proliantutils.redfish.resources.system import constants
|
||||
|
||||
PUSH_POWER_BUTTON_VALUE_MAP = {
|
||||
'Press': constants.PUSH_POWER_BUTTON_PRESS,
|
||||
'PressAndHold': constants.PUSH_POWER_BUTTON_PRESS_AND_HOLD,
|
||||
}
|
||||
|
||||
PUSH_POWER_BUTTON_VALUE_MAP_REV = (
|
||||
utils.revert_dictionary(PUSH_POWER_BUTTON_VALUE_MAP))
|
|
@ -14,8 +14,27 @@
|
|||
|
||||
__author__ = 'HPE'
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources.system import system
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils import log
|
||||
from proliantutils.redfish.resources.system import mappings
|
||||
|
||||
LOG = log.get_logger(__name__)
|
||||
|
||||
|
||||
class PowerButtonActionField(base.CompositeField):
|
||||
allowed_values = base.Field('PushType@Redfish.AllowableValues',
|
||||
adapter=list)
|
||||
|
||||
target_uri = base.Field('target', required=True)
|
||||
|
||||
|
||||
class HpeActionsField(base.CompositeField):
|
||||
computer_system_ext_powerbutton = (
|
||||
PowerButtonActionField('#HpeComputerSystemExt.PowerButton'))
|
||||
|
||||
|
||||
class HPESystem(system.System):
|
||||
"""Class that extends the functionality of System resource class
|
||||
|
@ -23,3 +42,37 @@ class HPESystem(system.System):
|
|||
This class extends the functionality of System resource class
|
||||
from sushy
|
||||
"""
|
||||
|
||||
_hpe_actions = HpeActionsField(['Oem', 'Hpe', 'Actions'], required=True)
|
||||
"""Oem specific system extensibility actions"""
|
||||
|
||||
def _get_hpe_push_power_button_action_element(self):
|
||||
push_action = self._hpe_actions.computer_system_ext_powerbutton
|
||||
if not push_action:
|
||||
raise exception.MissingAttributeError(
|
||||
attribute='Oem/Hpe/Actions/#HpeComputerSystemExt.PowerButton',
|
||||
resource=self.path)
|
||||
|
||||
return push_action
|
||||
|
||||
def push_power_button(self, target_value):
|
||||
"""Reset the system in hpe exclusive manner.
|
||||
|
||||
:param target_value: The target value to be set.
|
||||
:raises: InvalidInputError, if the target value is not
|
||||
allowed.
|
||||
:raises: SushyError, on an error from iLO.
|
||||
"""
|
||||
if target_value not in mappings.PUSH_POWER_BUTTON_VALUE_MAP_REV:
|
||||
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': (
|
||||
mappings.PUSH_POWER_BUTTON_VALUE_MAP_REV.keys())})
|
||||
raise exception.InvalidInputError(msg)
|
||||
|
||||
value = mappings.PUSH_POWER_BUTTON_VALUE_MAP_REV[target_value]
|
||||
target_uri = (
|
||||
self._get_hpe_push_power_button_action_element().target_uri)
|
||||
|
||||
self._conn.post(target_uri, data={'PushType': value})
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.redfish.resources.system import constants as sys_cons
|
||||
from proliantutils.redfish.resources.system import system
|
||||
|
||||
|
||||
class HPESystemTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(HPESystemTestCase, self).setUp()
|
||||
self.conn = mock.MagicMock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/system.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.sys_inst = system.HPESystem(
|
||||
self.conn, '/redfish/v1/Systems/1',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__get_hpe_push_power_button_action_element(self):
|
||||
value = self.sys_inst._get_hpe_push_power_button_action_element()
|
||||
self.assertEqual("/redfish/v1/Systems/1/Actions/Oem/Hpe/"
|
||||
"HpeComputerSystemExt.PowerButton/",
|
||||
value.target_uri)
|
||||
self.assertEqual(["Press", "PressAndHold"], value.allowed_values)
|
||||
|
||||
def test__get_hpe_push_power_button_action_element_missing_action(self):
|
||||
self.sys_inst._hpe_actions.computer_system_ext_powerbutton = None
|
||||
self.assertRaisesRegex(
|
||||
exception.MissingAttributeError,
|
||||
'Oem/Hpe/Actions/#HpeComputerSystemExt.PowerButton is missing',
|
||||
self.sys_inst._get_hpe_push_power_button_action_element)
|
||||
|
||||
def test_push_power_button(self):
|
||||
self.sys_inst.push_power_button(
|
||||
sys_cons.PUSH_POWER_BUTTON_PRESS)
|
||||
self.sys_inst._conn.post.assert_called_once_with(
|
||||
'/redfish/v1/Systems/1/Actions/Oem/Hpe/'
|
||||
'HpeComputerSystemExt.PowerButton/',
|
||||
data={'PushType': 'Press'})
|
||||
|
||||
def test_push_power_button_invalid_value(self):
|
||||
self.assertRaises(exception.InvalidInputError,
|
||||
self.sys_inst.push_power_button, 'invalid-value')
|
|
@ -22,6 +22,7 @@ import testtools
|
|||
from proliantutils import exception
|
||||
from proliantutils.redfish import main
|
||||
from proliantutils.redfish import redfish
|
||||
from proliantutils.redfish.resources.system import constants as sys_cons
|
||||
|
||||
|
||||
class RedfishOperationsTestCase(testtools.TestCase):
|
||||
|
@ -122,3 +123,29 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
|||
self.rf_client.set_host_power('ON')
|
||||
self.sushy.get_system().reset_system.assert_called_once_with(
|
||||
sushy.RESET_ON)
|
||||
|
||||
def test_press_pwr_btn(self):
|
||||
self.rf_client.press_pwr_btn()
|
||||
self.sushy.get_system().push_power_button.assert_called_once_with(
|
||||
sys_cons.PUSH_POWER_BUTTON_PRESS)
|
||||
|
||||
def test_press_pwr_btn_fail(self):
|
||||
self.sushy.get_system().push_power_button.side_effect = (
|
||||
sushy.exceptions.SushyError)
|
||||
self.assertRaisesRegex(
|
||||
exception.IloError,
|
||||
'The Redfish controller failed to press power button',
|
||||
self.rf_client.press_pwr_btn)
|
||||
|
||||
def test_hold_pwr_btn(self):
|
||||
self.rf_client.hold_pwr_btn()
|
||||
self.sushy.get_system().push_power_button.assert_called_once_with(
|
||||
sys_cons.PUSH_POWER_BUTTON_PRESS_AND_HOLD)
|
||||
|
||||
def test_hold_pwr_btn_fail(self):
|
||||
self.sushy.get_system().push_power_button.side_effect = (
|
||||
sushy.exceptions.SushyError)
|
||||
self.assertRaisesRegex(
|
||||
exception.IloError,
|
||||
'The Redfish controller failed to press and hold power button',
|
||||
self.rf_client.hold_pwr_btn)
|
||||
|
|
Loading…
Reference in New Issue