Redfish: Add 'iscsi_boot' capability
This commit adds support to add the new server capability 'iscsi_boot' Change-Id: Ia6cc56586143d651ad672206b3d97f2292ed99aa
This commit is contained in:
parent
8e8d261d9b
commit
8f48ebaf76
|
@ -667,7 +667,11 @@ class RedfishOperations(operations.IloOperations):
|
|||
or tpm_state == sys_cons.TPM_PRESENT_DISABLED)),
|
||||
('secure_boot',
|
||||
GET_SECUREBOOT_CURRENT_BOOT_MAP.get(
|
||||
sushy_system.secure_boot.current_boot)),) if value})
|
||||
sushy_system.secure_boot.current_boot)),
|
||||
('iscsi_boot',
|
||||
(sushy_system.bios_settings.iscsi_settings.
|
||||
is_iscsi_boot_supported())),
|
||||
) if value})
|
||||
|
||||
except sushy.exceptions.SushyError as e:
|
||||
msg = (self._("The Redfish controller is unable to get "
|
||||
|
|
|
@ -18,6 +18,7 @@ from sushy.resources import base
|
|||
from proliantutils import exception
|
||||
from proliantutils import log
|
||||
from proliantutils.redfish.resources.system import constants as sys_cons
|
||||
from proliantutils.redfish.resources.system import iscsi
|
||||
from proliantutils.redfish.resources.system import mappings
|
||||
from proliantutils.redfish import utils
|
||||
|
||||
|
@ -44,6 +45,8 @@ class BIOSSettings(base.ResourceBase):
|
|||
cpu_vt = base.MappedField(["Attributes", "ProcVirtualization"],
|
||||
mappings.CPUVT_MAP)
|
||||
|
||||
_iscsi_settings = None
|
||||
|
||||
_pending_settings = None
|
||||
_boot_settings = None
|
||||
_base_configs = None
|
||||
|
@ -80,6 +83,22 @@ class BIOSSettings(base.ResourceBase):
|
|||
|
||||
return self._boot_settings
|
||||
|
||||
@property
|
||||
def iscsi_settings(self):
|
||||
"""Property to provide reference to bios iscsi instance
|
||||
|
||||
It is calculated once when the first time it is queried. On refresh,
|
||||
this property gets reset.
|
||||
"""
|
||||
if self._iscsi_settings is None:
|
||||
self._iscsi_settings = iscsi.ISCSISettings(
|
||||
self._conn,
|
||||
utils.get_subresource_path_by(
|
||||
self, ["Oem", "Hpe", "Links", "iScsi"]),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
return self._iscsi_settings
|
||||
|
||||
def _get_base_configs(self):
|
||||
"""Method that returns object of bios base configs."""
|
||||
if self._base_configs is None:
|
||||
|
@ -100,6 +119,7 @@ class BIOSSettings(base.ResourceBase):
|
|||
self._pending_settings = None
|
||||
self._boot_settings = None
|
||||
self._base_configs = None
|
||||
self._iscsi_settings = None
|
||||
|
||||
|
||||
class BIOSBaseConfigs(base.ResourceBase):
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# 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.
|
||||
|
||||
from sushy.resources import base
|
||||
|
||||
from proliantutils.redfish import utils
|
||||
|
||||
|
||||
class ISCSISettings(base.ResourceBase):
|
||||
"""Class that represents the iSCSI settings resource.
|
||||
|
||||
This class extends the functionality of base resource class
|
||||
from sushy.
|
||||
"""
|
||||
|
||||
def is_iscsi_boot_supported(self):
|
||||
"""Checks whether iscsi boot is supported or not.
|
||||
|
||||
To find the iscsi boot support, check whether the PATCH
|
||||
operation is allowed on the iscsi 'settings' uri.
|
||||
:returns: True if it is supported else False
|
||||
"""
|
||||
return utils.is_operation_allowed(
|
||||
'PATCH', self,
|
||||
['@Redfish.Settings', 'SettingsObject'])
|
|
@ -81,3 +81,30 @@ def get_supported_boot_mode(supported_boot_mode):
|
|||
|
||||
return SupportedBootModes(boot_mode_bios=boot_mode_bios,
|
||||
boot_mode_uefi=boot_mode_uefi)
|
||||
|
||||
|
||||
def get_allowed_operations(resource, subresouce_path):
|
||||
"""Helper function to get the HTTP allowed methods.
|
||||
|
||||
:param resource: ResourceBase instance from which the path is loaded.
|
||||
:param subresource_path: JSON field to fetch the value from.
|
||||
Either a string, or a list of strings in case of a nested field.
|
||||
:returns: A list of allowed HTTP methods.
|
||||
"""
|
||||
uri = get_subresource_path_by(resource, subresouce_path)
|
||||
response = resource._conn.get(path=uri)
|
||||
return response.headers['Allow']
|
||||
|
||||
|
||||
def is_operation_allowed(method, resource, subresouce_path):
|
||||
"""Checks whether the operation is allowed for the resource.
|
||||
|
||||
This method checks whether a HTTP method is allowed to be
|
||||
performed on the given sub resource path.
|
||||
:param method: A HTTP method. example: GET, PATCH, POST
|
||||
:param resource: ResourceBase instance from which the path is loaded.
|
||||
:param subresource_path: JSON field to fetch the value from.
|
||||
Either a string, or a list of strings in case of a nested field.
|
||||
:returns: True if the operation is allowed else False
|
||||
"""
|
||||
return method in get_allowed_operations(resource, subresouce_path)
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
|
||||
|
||||
{
|
||||
"@Redfish.Settings":
|
||||
{
|
||||
"@odata.type": "#Settings.v1_0_0.Settings",
|
||||
"ETag": "",
|
||||
"Messages":
|
||||
[
|
||||
{
|
||||
"MessageId": "Base.1.0.Success"
|
||||
}
|
||||
],
|
||||
"SettingsObject":
|
||||
{
|
||||
"@odata.id": "/redfish/v1/systems/1/bios/iscsi/settings/"
|
||||
},
|
||||
"Time": ""
|
||||
},
|
||||
"@odata.context": "/redfish/v1/$metadata#HpeiSCSISoftwareInitiator.HpeiSCSISoftwareInitiator",
|
||||
"@odata.etag": "W/\"A772A3CF45F53A3A3A285057B9B505F1\"",
|
||||
"@odata.id": "/redfish/v1/systems/1/bios/iscsi/",
|
||||
"@odata.type": "#HpeiSCSISoftwareInitiator.v2_0_0.HpeiSCSISoftwareInitiator",
|
||||
"Id": "iscsi",
|
||||
"Name": "iSCSI Software Initiator Current Settings",
|
||||
"Oem":
|
||||
{
|
||||
"Hpe":
|
||||
{
|
||||
"@odata.type": "#HpeBiosExt.v2_0_0.HpeBiosExt",
|
||||
"Links":
|
||||
{
|
||||
"BaseConfigs":
|
||||
{
|
||||
"@odata.id": "/redfish/v1/systems/1/bios/iscsi/baseconfigs/"
|
||||
}
|
||||
},
|
||||
"SettingsObject":
|
||||
{
|
||||
"UnmodifiedETag": "W/\"F92FCCF7BBE885858530538BD89804A4\""
|
||||
}
|
||||
}
|
||||
},
|
||||
"iSCSIInitiatorName": "iqn.2015-02.com.hpe:uefi-U31",
|
||||
"iSCSISources":
|
||||
[
|
||||
{
|
||||
"StructuredBootString": null,
|
||||
"UEFIDevicePath": null,
|
||||
"iSCSIAttemptInstance": 0,
|
||||
"iSCSIAttemptName": "",
|
||||
"iSCSIAuthenticationMethod": "None",
|
||||
"iSCSIChapSecret": null,
|
||||
"iSCSIChapType": "OneWay",
|
||||
"iSCSIChapUsername": null,
|
||||
"iSCSIConnectRetry": 3,
|
||||
"iSCSIConnectTimeoutMS": 20000,
|
||||
"iSCSIConnection": "Disabled",
|
||||
"iSCSIInitiatorGateway": "0.0.0.0",
|
||||
"iSCSIInitiatorInfoViaDHCP": true,
|
||||
"iSCSIInitiatorIpAddress": "0.0.0.0",
|
||||
"iSCSIInitiatorNetmask": "0.0.0.0",
|
||||
"iSCSIIpAddressType": "IPv4",
|
||||
"iSCSILUN": "0",
|
||||
"iSCSINicSource": null,
|
||||
"iSCSIReverseChapSecret": null,
|
||||
"iSCSIReverseChapUsername": null,
|
||||
"iSCSITargetInfoViaDHCP": true,
|
||||
"iSCSITargetIpAddress": "0.0.0.0",
|
||||
"iSCSITargetName": "",
|
||||
"iSCSITargetTcpPort": 3260
|
||||
},
|
||||
{
|
||||
"StructuredBootString": null,
|
||||
"UEFIDevicePath": null,
|
||||
"iSCSIAttemptInstance": 0,
|
||||
"iSCSIAttemptName": "",
|
||||
"iSCSIAuthenticationMethod": "None",
|
||||
"iSCSIChapSecret": null,
|
||||
"iSCSIChapType": "OneWay",
|
||||
"iSCSIChapUsername": null,
|
||||
"iSCSIConnectRetry": 3,
|
||||
"iSCSIConnectTimeoutMS": 20000,
|
||||
"iSCSIConnection": "Disabled",
|
||||
"iSCSIInitiatorGateway": "0.0.0.0",
|
||||
"iSCSIInitiatorInfoViaDHCP": true,
|
||||
"iSCSIInitiatorIpAddress": "0.0.0.0",
|
||||
"iSCSIInitiatorNetmask": "0.0.0.0",
|
||||
"iSCSIIpAddressType": "IPv4",
|
||||
"iSCSILUN": "0",
|
||||
"iSCSINicSource": null,
|
||||
"iSCSIReverseChapSecret": null,
|
||||
"iSCSIReverseChapUsername": null,
|
||||
"iSCSITargetInfoViaDHCP": true,
|
||||
"iSCSITargetIpAddress": "0.0.0.0",
|
||||
"iSCSITargetName": "",
|
||||
"iSCSITargetTcpPort": 3260
|
||||
},
|
||||
{
|
||||
"StructuredBootString": null,
|
||||
"UEFIDevicePath": null,
|
||||
"iSCSIAttemptInstance": 0,
|
||||
"iSCSIAttemptName": "",
|
||||
"iSCSIAuthenticationMethod": "None",
|
||||
"iSCSIChapSecret": null,
|
||||
"iSCSIChapType": "OneWay",
|
||||
"iSCSIChapUsername": null,
|
||||
"iSCSIConnectRetry": 3,
|
||||
"iSCSIConnectTimeoutMS": 20000,
|
||||
"iSCSIConnection": "Disabled",
|
||||
"iSCSIInitiatorGateway": "0.0.0.0",
|
||||
"iSCSIInitiatorInfoViaDHCP": true,
|
||||
"iSCSIInitiatorIpAddress": "0.0.0.0",
|
||||
"iSCSIInitiatorNetmask": "0.0.0.0",
|
||||
"iSCSIIpAddressType": "IPv4",
|
||||
"iSCSILUN": "0",
|
||||
"iSCSINicSource": null,
|
||||
"iSCSIReverseChapSecret": null,
|
||||
"iSCSIReverseChapUsername": null,
|
||||
"iSCSITargetInfoViaDHCP": true,
|
||||
"iSCSITargetIpAddress": "0.0.0.0",
|
||||
"iSCSITargetName": "",
|
||||
"iSCSITargetTcpPort": 3260
|
||||
},
|
||||
{
|
||||
"StructuredBootString": null,
|
||||
"UEFIDevicePath": null,
|
||||
"iSCSIAttemptInstance": 0,
|
||||
"iSCSIAttemptName": "",
|
||||
"iSCSIAuthenticationMethod": "None",
|
||||
"iSCSIChapSecret": null,
|
||||
"iSCSIChapType": "OneWay",
|
||||
"iSCSIChapUsername": null,
|
||||
"iSCSIConnectRetry": 3,
|
||||
"iSCSIConnectTimeoutMS": 20000,
|
||||
"iSCSIConnection": "Disabled",
|
||||
"iSCSIInitiatorGateway": "0.0.0.0",
|
||||
"iSCSIInitiatorInfoViaDHCP": true,
|
||||
"iSCSIInitiatorIpAddress": "0.0.0.0",
|
||||
"iSCSIInitiatorNetmask": "0.0.0.0",
|
||||
"iSCSIIpAddressType": "IPv4",
|
||||
"iSCSILUN": "0",
|
||||
"iSCSINicSource": null,
|
||||
"iSCSIReverseChapSecret": null,
|
||||
"iSCSIReverseChapUsername": null,
|
||||
"iSCSITargetInfoViaDHCP": true,
|
||||
"iSCSITargetIpAddress": "0.0.0.0",
|
||||
"iSCSITargetName": "",
|
||||
"iSCSITargetTcpPort": 3260
|
||||
}
|
||||
]
|
||||
}
|
|
@ -22,6 +22,7 @@ import testtools
|
|||
from proliantutils import exception
|
||||
from proliantutils.redfish.resources.system import bios
|
||||
from proliantutils.redfish.resources.system import constants as sys_cons
|
||||
from proliantutils.redfish.resources.system import iscsi
|
||||
|
||||
|
||||
class BIOSSettingsTestCase(testtools.TestCase):
|
||||
|
@ -82,6 +83,24 @@ class BIOSSettingsTestCase(testtools.TestCase):
|
|||
self.bios_inst.boot_settings)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_iscsi_settings(self):
|
||||
self.assertIsNone(self.bios_inst._iscsi_settings)
|
||||
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/bios_boot.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = (
|
||||
json.loads(f.read())['Default'])
|
||||
actual_settings = self.bios_inst.iscsi_settings
|
||||
self.assertIsInstance(actual_settings,
|
||||
iscsi.ISCSISettings)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
self.assertIs(actual_settings,
|
||||
self.bios_inst.iscsi_settings)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test__get_base_configs(self):
|
||||
self.assertIsNone(self.bios_inst._base_configs)
|
||||
with open('proliantutils/tests/redfish/'
|
||||
|
@ -140,6 +159,29 @@ class BIOSSettingsTestCase(testtools.TestCase):
|
|||
self.assertIsInstance(actual_settings,
|
||||
bios.BIOSBootSettings)
|
||||
|
||||
def test_iscsi_settings_on_refresh(self):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/bios_boot.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = (
|
||||
json.loads(f.read())['Default'])
|
||||
actual_settings = self.bios_inst.iscsi_settings
|
||||
self.assertIsInstance(actual_settings,
|
||||
iscsi.ISCSISettings)
|
||||
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/bios.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = (
|
||||
json.loads(f.read())['Default'])
|
||||
self.bios_inst.refresh()
|
||||
self.assertIsNone(self.bios_inst._iscsi_settings)
|
||||
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/bios_boot.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = (
|
||||
json.loads(f.read())['Default'])
|
||||
self.assertIsInstance(actual_settings,
|
||||
iscsi.ISCSISettings)
|
||||
|
||||
def test__get_base_configs_on_refresh(self):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/bios_base_configs.json', 'r') as f:
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# 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 ddt
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from proliantutils.redfish.resources.system import iscsi
|
||||
from proliantutils.redfish import utils
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ISCSISettingsTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ISCSISettingsTestCase, self).setUp()
|
||||
self.conn = mock.MagicMock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/iscsi.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = (
|
||||
json.loads(f.read()))
|
||||
|
||||
self.iscsi_inst = iscsi.ISCSISettings(
|
||||
self.conn, '/redfish/v1/Systems/1/bios/iscsi',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
@ddt.data((['GET', 'PATCH', 'POST', 'HEAD'], True),
|
||||
(['GET', 'HEAD'], False))
|
||||
@ddt.unpack
|
||||
@mock.patch.object(utils, 'get_allowed_operations')
|
||||
def test_is_iscsi_boot_supported(self, allowed_method,
|
||||
expected, get_method_mock):
|
||||
get_method_mock.return_value = allowed_method
|
||||
ret_val = self.iscsi_inst.is_iscsi_boot_supported()
|
||||
self.assertEqual(ret_val, expected)
|
|
@ -30,6 +30,7 @@ from proliantutils.redfish.resources.manager import manager
|
|||
from proliantutils.redfish.resources.manager import virtual_media
|
||||
from proliantutils.redfish.resources.system import bios
|
||||
from proliantutils.redfish.resources.system import constants as sys_cons
|
||||
from proliantutils.redfish.resources.system import iscsi
|
||||
from proliantutils.redfish.resources.system import pci_device
|
||||
from proliantutils.redfish.resources.system import system as pro_sys
|
||||
from sushy.resources.system import system
|
||||
|
@ -690,6 +691,10 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
|||
tpm_mock)
|
||||
type(get_system_mock.return_value).supported_boot_mode = (
|
||||
sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI)
|
||||
iscsi_mock = mock.MagicMock(spec=iscsi.ISCSISettings)
|
||||
iscsi_mock.is_iscsi_boot_supported = mock.MagicMock(return_value=True)
|
||||
type(get_system_mock.return_value.bios_settings).iscsi_settings = (
|
||||
iscsi_mock)
|
||||
actual = self.rf_client.get_server_capabilities()
|
||||
expected = {'pci_gpu_devices': 1, 'sriov_enabled': 'true',
|
||||
'secure_boot': 'true', 'cpu_vt': 'true',
|
||||
|
@ -699,7 +704,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
|||
'trusted_boot': 'true',
|
||||
'server_model': 'ProLiant DL180 Gen10',
|
||||
'boot_mode_bios': 'true',
|
||||
'boot_mode_uefi': 'true'}
|
||||
'boot_mode_uefi': 'true', 'iscsi_boot': 'true'}
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_system')
|
||||
|
@ -733,6 +738,10 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
|||
tpm_mock)
|
||||
type(get_system_mock.return_value).supported_boot_mode = (
|
||||
sys_cons.SUPPORTED_UEFI_ONLY)
|
||||
iscsi_mock = mock.MagicMock(spec=iscsi.ISCSISettings)
|
||||
iscsi_mock.is_iscsi_boot_supported = mock.MagicMock(return_value=False)
|
||||
type(get_system_mock.return_value.bios_settings).iscsi_settings = (
|
||||
iscsi_mock)
|
||||
actual = self.rf_client.get_server_capabilities()
|
||||
expected = {'pci_gpu_devices': 1,
|
||||
'rom_firmware_version': 'U31 v1.00 (03/11/2017)',
|
||||
|
|
|
@ -82,3 +82,25 @@ class UtilsTestCase(testtools.TestCase):
|
|||
expected_boot_modes):
|
||||
actual_boot_modes = utils.get_supported_boot_mode(boot_mode)
|
||||
self.assertEqual(expected_boot_modes, actual_boot_modes)
|
||||
|
||||
@ddt.data(('SecureBoot', ['HEAD', 'GET', 'PATCH', 'POST']),
|
||||
('Bios', ['GET', 'HEAD']))
|
||||
@ddt.unpack
|
||||
def test_get_allowed_operations(self, subresource_path, expected):
|
||||
response_mock = mock.MagicMock()
|
||||
response_mock.headers = {'Allow': expected}
|
||||
self.conn.get.return_value = response_mock
|
||||
ret_val = utils.get_allowed_operations(self.sys_inst, subresource_path)
|
||||
self.assertEqual(ret_val, expected)
|
||||
|
||||
@ddt.data(('PATCH', 'SecureBoot', ['HEAD', 'GET', 'PATCH', 'POST'], True),
|
||||
('POST', 'Bios', ['GET', 'HEAD'], False))
|
||||
@ddt.unpack
|
||||
@mock.patch.object(utils, 'get_allowed_operations')
|
||||
def test_is_operation_allowed(self, method, subresource_path,
|
||||
allowed_operations, expected,
|
||||
get_method_mock):
|
||||
get_method_mock.return_value = allowed_operations
|
||||
ret_val = utils.is_operation_allowed(method, self.sys_inst,
|
||||
subresource_path)
|
||||
self.assertEqual(ret_val, expected)
|
||||
|
|
Loading…
Reference in New Issue