Initial redfish commit
This patch is again targeted towards support of consuming Redfish APIs. This introduces the initial commit for redfish related files. Till now, the redfish code base is **not** yet instrumented to be called from ``ilo.client.IloClient`` object. A separate patch will be submitted to instrument this redfish code for Gen10. Till that this patch turns out to be a pre-enablement of redfish on proliantutils. Change-Id: Ib7f7596053543c3ebfa115ace3b56979ea5d6a36 Partial-Bug: 1646685
This commit is contained in:
parent
967a7447d8
commit
61aa195a5a
|
@ -200,3 +200,20 @@ class HpsumOperationError(ProliantUtilsException):
|
|||
message = self.message % kwargs
|
||||
|
||||
super(HpsumOperationError, self).__init__(message)
|
||||
|
||||
|
||||
class RedfishError(ProliantUtilsException):
|
||||
"""Basic exception for errors raised by Redfish operations."""
|
||||
|
||||
message = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
if self.message and kwargs:
|
||||
self.message = self.message % kwargs
|
||||
|
||||
super(RedfishError, self).__init__(self.message)
|
||||
|
||||
|
||||
class MissingAttributeError(RedfishError):
|
||||
message = ('The attribute %(attribute)s is missing from the '
|
||||
'resource %(resource)s')
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
# 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
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.ilo import operations
|
||||
from proliantutils import log
|
||||
from proliantutils import rest
|
||||
|
||||
|
||||
"""
|
||||
Class specific for Redfish APIs.
|
||||
"""
|
||||
|
||||
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__()
|
||||
self._conn = rest.RestConnectorBase(redfish_controller_ip, username,
|
||||
password, bios_password, cacert)
|
||||
self._root_prefix = root_prefix
|
||||
# Fetch the ServiceRoot response
|
||||
self._fetch_root_resources()
|
||||
|
||||
def _fetch_root_resources(self):
|
||||
"""Fetches the service root resources
|
||||
|
||||
Retrieves/fetches the resources at ServiceRoot
|
||||
:raises: IloConnectionError
|
||||
"""
|
||||
status, headers, service_root_resp = (
|
||||
self._conn._rest_get(self._root_prefix))
|
||||
self._root_resp = service_root_resp
|
||||
|
||||
def _get_system_collection_path(self):
|
||||
"""Helper function to find the SystemCollection path"""
|
||||
systems_col = self._root_resp.get('Systems')
|
||||
if not systems_col:
|
||||
raise exception.MissingAttributeError(attribute='Systems',
|
||||
resource=self._root_prefix)
|
||||
return systems_col.get('@odata.id')
|
||||
|
||||
def _get_system_details(self, system_id):
|
||||
"""Get the system details.
|
||||
|
||||
:param system_id: The identity of the System resource
|
||||
:raises: IloError
|
||||
:raises: MissingAttributeError
|
||||
"""
|
||||
system_url = parse.urljoin(self._get_system_collection_path(),
|
||||
system_id)
|
||||
status, headers, system = self._conn._rest_get(system_url)
|
||||
return system
|
||||
|
||||
def get_product_name(self):
|
||||
"""Gets the product name of the server.
|
||||
|
||||
:returns: server model name.
|
||||
:raises: IloError, on an error from iLO.
|
||||
:raises: MissingAttributeError
|
||||
"""
|
||||
# Assuming only one system present as part of collection,
|
||||
# as we are dealing with iLO's here.
|
||||
system = self._get_system_details('1')
|
||||
return system['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.
|
||||
:raises: MissingAttributeError
|
||||
"""
|
||||
# Assuming only one system present as part of collection,
|
||||
# as we are dealing with iLO's here.
|
||||
system = self._get_system_details('1')
|
||||
return system['PowerState'].upper()
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#ServiceRoot",
|
||||
"@odata.etag": "W/\"06F9101D\"",
|
||||
"@odata.id": "/redfish/v1/",
|
||||
"@odata.type": "#ServiceRoot.v1_1_0.ServiceRoot",
|
||||
"AccountService": {
|
||||
"@odata.id": "/redfish/v1/AccountService/"
|
||||
},
|
||||
"Chassis": {
|
||||
"@odata.id": "/redfish/v1/Chassis/"
|
||||
},
|
||||
"EventService": {
|
||||
"@odata.id": "/redfish/v1/EventService/"
|
||||
},
|
||||
"Id": "v1",
|
||||
"JsonSchemas": {
|
||||
"@odata.id": "/redfish/v1/Schemas/"
|
||||
},
|
||||
"Links": {
|
||||
"Sessions": {
|
||||
"@odata.id": "/redfish/v1/SessionService/Sessions/"
|
||||
}
|
||||
},
|
||||
"Managers": {
|
||||
"@odata.id": "/redfish/v1/Managers/"
|
||||
},
|
||||
"Name": "HPE RESTful Root Service",
|
||||
"Oem": {
|
||||
"Hpe": {
|
||||
"@odata.type": "#HpeiLOServiceExt.v2_0_0.HpeiLOServiceExt",
|
||||
"Links": {
|
||||
"ResourceDirectory": {
|
||||
"@odata.id": "/redfish/v1/ResourceDirectory/"
|
||||
},
|
||||
"ViewClassService": {
|
||||
"@odata.id": "/redfish/v1/Views/"
|
||||
}
|
||||
},
|
||||
"Manager": [
|
||||
{
|
||||
"DefaultLanguage": "en",
|
||||
"FQDN": "ILO.asiapacific.hpqcorp.net",
|
||||
"HostName": "ILO",
|
||||
"Languages": [
|
||||
{
|
||||
"Language": "en",
|
||||
"TranslationName": "English",
|
||||
"Version": "1.10"
|
||||
}
|
||||
],
|
||||
"ManagerFirmwareVersion": "1.10",
|
||||
"ManagerType": "iLO 5"
|
||||
}
|
||||
],
|
||||
"Sessions": {
|
||||
"CertCommonName": "ILO.asiapacific.hpqcorp.net",
|
||||
"CertificateLoginEnabled": false,
|
||||
"KerberosEnabled": false,
|
||||
"LDAPAuthLicenced": true,
|
||||
"LDAPEnabled": false,
|
||||
"LocalLoginEnabled": true,
|
||||
"LoginFailureDelay": 0,
|
||||
"LoginHint": {
|
||||
"Hint": "POST to /Sessions to login using the following JSON object:",
|
||||
"HintPOSTData": {
|
||||
"Password": "password",
|
||||
"UserName": "username"
|
||||
}
|
||||
},
|
||||
"SecurityOverride": false,
|
||||
"ServerName": ""
|
||||
},
|
||||
"Time": "2017-03-30T12:13:38Z"
|
||||
}
|
||||
},
|
||||
"RedfishVersion": "1.0.0",
|
||||
"Registries": {
|
||||
"@odata.id": "/redfish/v1/Registries/"
|
||||
},
|
||||
"SessionService": {
|
||||
"@odata.id": "/redfish/v1/SessionService/"
|
||||
},
|
||||
"Systems": {
|
||||
"@odata.id": "/redfish/v1/Systems/"
|
||||
},
|
||||
"UUID": "7704b47b-2fbe-5920-99a5-b766dd84cc28",
|
||||
"UpdateService": {
|
||||
"@odata.id": "/redfish/v1/UpdateService/"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Systems/Members/$entity",
|
||||
"@odata.etag": "W/\"0E79655D\"",
|
||||
"@odata.id": "/redfish/v1/Systems/1/",
|
||||
"@odata.type": "#ComputerSystem.v1_2_0.ComputerSystem",
|
||||
"Actions": {
|
||||
"#ComputerSystem.Reset": {
|
||||
"ResetType@Redfish.AllowableValues": [
|
||||
"On",
|
||||
"ForceOff",
|
||||
"ForceRestart",
|
||||
"Nmi",
|
||||
"PushPowerButton"
|
||||
],
|
||||
"target": "/redfish/v1/Systems/1/Actions/ComputerSystem.Reset/"
|
||||
}
|
||||
},
|
||||
"AssetTag": "",
|
||||
"Bios": {
|
||||
"@odata.id": "/redfish/v1/systems/1/bios/"
|
||||
},
|
||||
"BiosVersion": "U31 v1.00 (03/11/2017)",
|
||||
"Boot": {
|
||||
"BootSourceOverrideEnabled": "Disabled",
|
||||
"BootSourceOverrideMode": "UEFI",
|
||||
"BootSourceOverrideTarget": "None",
|
||||
"BootSourceOverrideTarget@Redfish.AllowableValues": [
|
||||
"None",
|
||||
"Cd",
|
||||
"Hdd",
|
||||
"Usb",
|
||||
"SDCard",
|
||||
"Utilities",
|
||||
"Diags",
|
||||
"BiosSetup",
|
||||
"Pxe",
|
||||
"UefiShell",
|
||||
"UefiHttp",
|
||||
"UefiTarget"
|
||||
],
|
||||
"UefiTargetBootSourceOverride": "None",
|
||||
"UefiTargetBootSourceOverride@Redfish.AllowableValues": [
|
||||
"HD(1,GPT,7F14DF43-6600-420A-9950-C028836F6A5D,0x800,0x64000)/\\EFI\\centos\\shim.efi",
|
||||
"UsbClass(0xFFFF,0xFFFF,0xFF,0xFF,0xFF)",
|
||||
"PciRoot(0x0)/Pci(0x17,0x0)/Sata(0x3,0x0,0x0)"
|
||||
]
|
||||
},
|
||||
"HostName": "",
|
||||
"Id": "1",
|
||||
"IndicatorLED": "Off",
|
||||
"Links": {
|
||||
"Chassis": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/1/"
|
||||
}
|
||||
],
|
||||
"ManagedBy": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Managers/1/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"LogServices": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/LogServices/"
|
||||
},
|
||||
"Manufacturer": "HPE",
|
||||
"Memory": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/Memory/"
|
||||
},
|
||||
"MemorySummary": {
|
||||
"Status": {
|
||||
"HealthRollup": "OK"
|
||||
},
|
||||
"TotalSystemMemoryGiB": 8
|
||||
},
|
||||
"Model": "ProLiant DL180 Gen10",
|
||||
"Name": "Computer System",
|
||||
"Oem": {
|
||||
"Hpe": {
|
||||
"@odata.type": "#HpeComputerSystemExt.v2_1_0.HpeComputerSystemExt",
|
||||
"Actions": {
|
||||
"#HpeComputerSystemExt.PowerButton": {
|
||||
"PushType@Redfish.AllowableValues": [
|
||||
"Press",
|
||||
"PressAndHold"
|
||||
],
|
||||
"target": "/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.PowerButton/"
|
||||
},
|
||||
"#HpeComputerSystemExt.SystemReset": {
|
||||
"ResetType@Redfish.AllowableValues": [
|
||||
"ColdBoot"
|
||||
],
|
||||
"target": "/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.SystemReset/"
|
||||
}
|
||||
},
|
||||
"AggregateHealthStatus": {
|
||||
"AgentlessManagementService": "Unavailable",
|
||||
"BiosOrHardwareHealth": {
|
||||
"Status": {
|
||||
"Health": "OK"
|
||||
}
|
||||
},
|
||||
"FanRedundancy": "Redundant",
|
||||
"Fans": {
|
||||
"Status": {
|
||||
"Health": "OK"
|
||||
}
|
||||
},
|
||||
"Memory": {
|
||||
"Status": {
|
||||
"Health": "OK"
|
||||
}
|
||||
},
|
||||
"PowerSupplies": {
|
||||
"PowerSuppliesMismatch": false,
|
||||
"Status": {
|
||||
"Health": "OK"
|
||||
}
|
||||
},
|
||||
"Processors": {
|
||||
"Status": {
|
||||
"Health": "OK"
|
||||
}
|
||||
},
|
||||
"Storage": {
|
||||
"Status": {
|
||||
"Health": "OK"
|
||||
}
|
||||
},
|
||||
"Temperatures": {
|
||||
"Status": {
|
||||
"Health": "OK"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Bios": {
|
||||
"Backup": {
|
||||
"Date": "03/11/2017",
|
||||
"Family": "U31",
|
||||
"VersionString": "U31 v1.00 (03/11/2017)"
|
||||
},
|
||||
"Current": {
|
||||
"Date": "03/11/2017",
|
||||
"Family": "U31",
|
||||
"VersionString": "U31 v1.00 (03/11/2017)"
|
||||
},
|
||||
"UefiClass": 2
|
||||
},
|
||||
"DeviceDiscoveryComplete": {
|
||||
"AMSDeviceDiscovery": "NoAMS",
|
||||
"DeviceDiscovery": "DataIncomplete",
|
||||
"SmartArrayDiscovery": "Complete"
|
||||
},
|
||||
"EndOfPostDelaySeconds": null,
|
||||
"Links": {
|
||||
"NetworkAdapters": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/NetworkAdapters/"
|
||||
},
|
||||
"PCIDevices": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/PCIDevices/"
|
||||
},
|
||||
"PCISlots": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/PCISlots/"
|
||||
},
|
||||
"SmartStorage": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/SmartStorage/"
|
||||
},
|
||||
"USBPorts": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/USBPorts/"
|
||||
}
|
||||
},
|
||||
"PCAPartNumber": "",
|
||||
"PCASerialNumber": "847012-001",
|
||||
"PostDiscoveryCompleteTimeStamp": "2017-03-13T11:11:48Z",
|
||||
"PostDiscoveryMode": null,
|
||||
"PostMode": null,
|
||||
"PostState": "FinishedPost",
|
||||
"PowerAllocationLimit": 500,
|
||||
"PowerAutoOn": "Restore",
|
||||
"PowerOnDelay": "Minimum",
|
||||
"PowerRegulatorMode": "Dynamic",
|
||||
"PowerRegulatorModesSupported": [
|
||||
"OSControl",
|
||||
"Dynamic",
|
||||
"Max",
|
||||
"Min"
|
||||
],
|
||||
"SMBIOS": {
|
||||
"extref": "/smbios"
|
||||
},
|
||||
"VirtualProfile": "Inactive"
|
||||
}
|
||||
},
|
||||
"PowerState": "On",
|
||||
"ProcessorSummary": {
|
||||
"Count": 2,
|
||||
"Model": "Intel(R) Genuine processor",
|
||||
"Status": {
|
||||
"HealthRollup": "OK"
|
||||
}
|
||||
},
|
||||
"Processors": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/Processors/"
|
||||
},
|
||||
"SKU": " ",
|
||||
"SecureBoot": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/SecureBoot/"
|
||||
},
|
||||
"SerialNumber": " ",
|
||||
"Status": {
|
||||
"Health": "OK",
|
||||
"State": "Enabled"
|
||||
},
|
||||
"Storage": {
|
||||
"@odata.id": "/redfish/v1/Systems/1/Storage/"
|
||||
},
|
||||
"SystemType": "Physical",
|
||||
"TrustedModules": [
|
||||
{
|
||||
"Status": {
|
||||
"State": "Absent"
|
||||
}
|
||||
}
|
||||
],
|
||||
"UUID": "00000000-0000-0000-0000-000000000000"
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
# 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 import redfish
|
||||
from proliantutils import rest
|
||||
|
||||
|
||||
class RedfishOperationsTestCase(testtools.TestCase):
|
||||
|
||||
@mock.patch.object(rest, 'RestConnectorBase', autospec=True)
|
||||
def setUp(self, rest_connector_mock):
|
||||
super(RedfishOperationsTestCase, self).setUp()
|
||||
self.conn = mock.MagicMock()
|
||||
rest_connector_mock.return_value = self.conn
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/root.json', 'r') as f:
|
||||
self.conn._rest_get.return_value = 200, None, json.loads(f.read())
|
||||
|
||||
self.rf_client = redfish.RedfishOperations(
|
||||
'1.2.3.4', username='foo', password='bar')
|
||||
rest_connector_mock.assert_called_once_with(
|
||||
'1.2.3.4', 'foo', 'bar', None, None)
|
||||
|
||||
def test__fetch_root_resources(self):
|
||||
rf_client = self.rf_client
|
||||
rf_client._fetch_root_resources()
|
||||
self.assertEqual('HPE RESTful Root Service',
|
||||
rf_client._root_resp.get('Name'))
|
||||
self.assertEqual('1.0.0', rf_client._root_resp.get('RedfishVersion'))
|
||||
self.assertEqual('7704b47b-2fbe-5920-99a5-b766dd84cc28',
|
||||
rf_client._root_resp.get('UUID'))
|
||||
for resource in ['Systems', 'Managers', 'Chassis']:
|
||||
self.assertTrue(resource in rf_client._root_resp)
|
||||
|
||||
def test__get_system_collection_path(self):
|
||||
self.assertEqual('/redfish/v1/Systems/',
|
||||
self.rf_client._get_system_collection_path())
|
||||
|
||||
def test__get_system_collection_path_missing_systems_attr(self):
|
||||
self.rf_client._root_resp.pop('Systems')
|
||||
self.assertRaisesRegex(
|
||||
exception.MissingAttributeError,
|
||||
'The attribute Systems is missing',
|
||||
self.rf_client._get_system_collection_path)
|
||||
|
||||
def test_get_product_name(self):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/system.json', 'r') as f:
|
||||
self.conn._rest_get.return_value = 200, None, json.loads(f.read())
|
||||
product_name = self.rf_client.get_product_name()
|
||||
self.assertEqual('ProLiant DL180 Gen10', product_name)
|
||||
|
||||
def test_get_host_power_status(self):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/system.json', 'r') as f:
|
||||
self.conn._rest_get.return_value = 200, None, json.loads(f.read())
|
||||
power_state = self.rf_client.get_host_power_status()
|
||||
self.assertEqual('ON', power_state)
|
Loading…
Reference in New Issue