198 lines
7.5 KiB
Python
198 lines
7.5 KiB
Python
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
|
#
|
|
# 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.
|
|
|
|
__author__ = 'HPE'
|
|
|
|
from six.moves.urllib import parse
|
|
import sushy
|
|
|
|
from proliantutils import exception
|
|
from proliantutils.ilo import operations
|
|
from proliantutils import log
|
|
|
|
|
|
"""
|
|
Class specific for Redfish APIs.
|
|
"""
|
|
|
|
GET_POWER_STATE_MAP = {
|
|
sushy.SYSTEM_POWER_STATE_ON: 'ON',
|
|
sushy.SYSTEM_POWER_STATE_POWERING_ON: 'ON',
|
|
sushy.SYSTEM_POWER_STATE_OFF: 'OFF',
|
|
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__)
|
|
|
|
|
|
class RedfishOperations(operations.IloOperations):
|
|
"""Operations supported on redfish based hardware.
|
|
|
|
This is the list of 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 ---
|
|
|
|
"""
|
|
|
|
def __init__(self, redfish_controller_ip, username, password,
|
|
bios_password=None, cacert=None, root_prefix='/redfish/v1/'):
|
|
"""A class representing supported RedfishOperations
|
|
|
|
:param redfish_controller_ip: The ip address of the Redfish controller.
|
|
:param username: User account with admin/server-profile access
|
|
privilege
|
|
:param password: User account password
|
|
:param bios_password: bios password
|
|
:param cacert: a path to a CA_BUNDLE file or directory with
|
|
certificates of trusted CAs. If set to None, the driver will
|
|
ignore verifying the SSL certificate; if it's a path the driver
|
|
will use the specified certificate or one of the certificates in
|
|
the directory. Defaults to None.
|
|
:param root_prefix: The default URL prefix. This part includes
|
|
the root service and version. Defaults to /redfish/v1
|
|
"""
|
|
super(RedfishOperations, self).__init__()
|
|
address = ('https://' + redfish_controller_ip)
|
|
LOG.debug('Redfish address: %s', address)
|
|
verify = False if cacert is None else cacert
|
|
|
|
# for error reporting purpose
|
|
self.host = redfish_controller_ip
|
|
self._root_prefix = root_prefix
|
|
|
|
try:
|
|
self._sushy = sushy.Sushy(
|
|
address, username=username, password=password,
|
|
root_prefix=root_prefix, verify=verify)
|
|
except sushy.exceptions.SushyError as e:
|
|
msg = (self._('The Redfish controller at "%(controller)s" has '
|
|
'thrown error. Error %(error)s') %
|
|
{'controller': address, 'error': str(e)})
|
|
LOG.debug(msg)
|
|
raise exception.IloConnectionError(msg)
|
|
|
|
def _get_system_collection_path(self):
|
|
"""Helper function to find the SystemCollection path"""
|
|
systems_col = self._sushy.json.get('Systems')
|
|
if not systems_col:
|
|
raise exception.MissingAttributeError(attribute='Systems',
|
|
resource=self._root_prefix)
|
|
return systems_col.get('@odata.id')
|
|
|
|
def _get_sushy_system(self, system_id):
|
|
"""Get the sushy system for system_id
|
|
|
|
:param system_id: The identity of the System resource
|
|
:returns: the Sushy system instance
|
|
:raises: IloError
|
|
"""
|
|
system_url = parse.urljoin(self._get_system_collection_path(),
|
|
system_id)
|
|
try:
|
|
return self._sushy.get_system(system_url)
|
|
except sushy.exceptions.SushyError as e:
|
|
msg = (self._('The Redfish System "%(system)s" was not found. '
|
|
'Error %(error)s') %
|
|
{'system': system_id, 'error': str(e)})
|
|
LOG.debug(msg)
|
|
raise exception.IloError(msg)
|
|
|
|
def get_product_name(self):
|
|
"""Gets the product name of the server.
|
|
|
|
: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')
|
|
|
|
def get_host_power_status(self):
|
|
"""Request the power state of the server.
|
|
|
|
: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)
|
|
|
|
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)
|