Introduce BIOS API
Add `system` resource to have reference to `bios`. Support patching via @Redfish.Settings settings object resource using new SettingsField. SettingsField is a reusable field that corresponds to @Redfish.Settings in other resources. This SettingsField corresponds to Settings.v1_0_0 field schema, newer versions introduce additional fields that will be added later. Also at least iDRAC does not support anything newer than Settings.v1_0_0 field schema now. In the unit tests, settings.json contains imaginary values for Message, Severity, MessageArgs and Resolution fields as could not find existing samples holding these fields. @Redfish.Settings is a special field (annotation) that does not appear as a property in any schemas of Redfish resources. Theoretically it can be present in any resource. Practically this field is added to resources that support future state of the resource where immediate application of updates is not possible and need to restart system or a service for the values to take effect. So far it has been identified that resources that can have this field are: BIOS, Ethernet Interface and Storage. If @Redfish.Settings is present on the resource, then need to use URI in its subfield SettingsObject to update resource. If it is not present on the resource, then can update the resource directly using the resource's URI. Change-Id: Ib2ef3d6380975ec7b964ebb634575e2b86d51991 Task: 12508 Story: 2001791
This commit is contained in:
parent
44de14add2
commit
fb44452cdd
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for the BIOS resource to the library.
|
|
@ -20,3 +20,10 @@ class ActionField(base.CompositeField):
|
|||
class ResetActionField(ActionField):
|
||||
allowed_values = base.Field('ResetType@Redfish.AllowableValues',
|
||||
adapter=list)
|
||||
|
||||
|
||||
class IdRefField(base.CompositeField):
|
||||
"""Reference to the resource for updating settings"""
|
||||
|
||||
resource_uri = base.Field('@odata.id')
|
||||
"""The unique identifier for a resource"""
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
# 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.
|
||||
|
||||
# This is referred from Redfish standard schema.
|
||||
# http://redfish.dmtf.org/schemas/v1/Settings.v1_0_0.json
|
||||
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
|
||||
|
||||
class MessageListField(base.ListField):
|
||||
"""List of messages with details of settings update status"""
|
||||
|
||||
message_id = base.Field('MessageId', required=True)
|
||||
"""The key for this message which can be used
|
||||
to look up the message in a message registry
|
||||
"""
|
||||
|
||||
message = base.Field('Message')
|
||||
"""Human readable message, if provided"""
|
||||
|
||||
severity = base.Field('Severity')
|
||||
"""Severity of the error"""
|
||||
|
||||
resolution = base.Field('Resolution')
|
||||
"""Used to provide suggestions on how to resolve
|
||||
the situation that caused the error
|
||||
"""
|
||||
|
||||
_related_properties = base.Field('RelatedProperties')
|
||||
"""List of properties described by the message"""
|
||||
|
||||
message_args = base.Field('MessageArgs')
|
||||
"""List of message substitution arguments for the message
|
||||
referenced by `message_id` from the message registry
|
||||
"""
|
||||
|
||||
|
||||
class SettingsField(base.CompositeField):
|
||||
"""The settings of a resource
|
||||
|
||||
Represents the future state and configuration of the resource. The
|
||||
field is added to resources that support future state and
|
||||
configuration.
|
||||
|
||||
This field includes several properties to help clients monitor when
|
||||
the resource is consumed by the service and determine the results of
|
||||
applying the values, which may or may not have been successful.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(SettingsField, self).__init__(path="@Redfish.Settings")
|
||||
|
||||
time = base.Field('Time')
|
||||
"""Indicates the time the settings were applied to the server"""
|
||||
|
||||
_etag = base.Field('ETag')
|
||||
"""The ETag of the resource to which the settings were applied,
|
||||
after the application
|
||||
"""
|
||||
|
||||
_settings_object_idref = common.IdRefField("SettingsObject")
|
||||
"""Reference to the resource the client may PUT/PATCH in order
|
||||
to change this resource
|
||||
"""
|
||||
|
||||
messages = MessageListField("Messages")
|
||||
"""Represents the results of the last time the values of the Settings
|
||||
resource were applied to the server"""
|
||||
|
||||
def commit(self, connector, value, etag=None):
|
||||
"""Commits new settings values
|
||||
|
||||
The new values will be applied when the system or a service
|
||||
restarts.
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param value: Value representing JSON whose structure is specific
|
||||
to each resource and the caller must format it correctly
|
||||
:param etag: Optional ETag of resource version to update. If
|
||||
this ETag is provided and it does not match on server, then
|
||||
the new values will not be committed
|
||||
"""
|
||||
|
||||
connector.patch(self.resource_uri,
|
||||
data=value,
|
||||
headers={'If-Match': etag} if etag else None)
|
||||
|
||||
@property
|
||||
def resource_uri(self):
|
||||
return self._settings_object_idref.resource_uri
|
|
@ -0,0 +1,162 @@
|
|||
# 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.
|
||||
|
||||
# This is referred from Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/Bios.v1_0_3.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
from sushy.resources import settings
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ActionsField(base.CompositeField):
|
||||
change_password = common.ActionField('#Bios.ChangePassword')
|
||||
reset_bios = common.ActionField('#Bios.ResetBios')
|
||||
|
||||
|
||||
class Bios(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The Bios resource identity string"""
|
||||
|
||||
name = base.Field('Name')
|
||||
"""The name of the resource"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""Human-readable description of the BIOS resource"""
|
||||
|
||||
attribute_registry = base.Field('AttributeRegistry')
|
||||
"""The Resource ID of the Attribute Registry
|
||||
for the BIOS Attributes resource
|
||||
"""
|
||||
|
||||
_settings = settings.SettingsField()
|
||||
"""Results of last BIOS attribute update"""
|
||||
|
||||
attributes = base.Field('Attributes')
|
||||
"""Vendor-specific key-value dict of effective BIOS attributes
|
||||
|
||||
Attributes cannot be updated directly.
|
||||
To update use :py:func:`~set_attribute` or :py:func:`~set_attributes`
|
||||
"""
|
||||
|
||||
_actions = ActionsField('Actions')
|
||||
|
||||
_etag = base.Field('@odata.etag')
|
||||
|
||||
_pending_settings_resource = None
|
||||
|
||||
@property
|
||||
def pending_attributes(self):
|
||||
"""Pending BIOS attributes
|
||||
|
||||
BIOS attributes that have been comitted to the system,
|
||||
but for them to take effect system restart is necessary
|
||||
"""
|
||||
|
||||
if not self._pending_settings_resource:
|
||||
self._pending_settings_resource = Bios(
|
||||
self._conn,
|
||||
self._settings.resource_uri,
|
||||
redfish_version=self.redfish_version)
|
||||
self._pending_settings_resource.refresh(force=False)
|
||||
return self._pending_settings_resource.attributes
|
||||
|
||||
def set_attribute(self, key, value):
|
||||
"""Update an attribute
|
||||
|
||||
Attribute update is not immediate but requires system restart.
|
||||
Committed attributes can be checked at :py:attr:`~pending_attributes`
|
||||
property
|
||||
|
||||
:param key: Attribute name
|
||||
:param value: Attribute value
|
||||
"""
|
||||
self.set_attributes({key: value})
|
||||
|
||||
def set_attributes(self, value):
|
||||
"""Update many attributes at once
|
||||
|
||||
Attribute update is not immediate but requires system restart.
|
||||
Committed attributes can be checked at :py:attr:`~pending_attributes`
|
||||
property
|
||||
|
||||
:param value: Key-value pairs for attribute name and value
|
||||
"""
|
||||
self._settings.commit(self._conn,
|
||||
{'Attributes': value},
|
||||
self._etag)
|
||||
if self._pending_settings_resource:
|
||||
self._pending_settings_resource.invalidate()
|
||||
|
||||
def _get_reset_bios_action_element(self):
|
||||
actions = self._actions
|
||||
|
||||
if not actions:
|
||||
raise exceptions.MissingAttributeError(attribute="Actions",
|
||||
resource=self._path)
|
||||
|
||||
reset_bios_action = actions.reset_bios
|
||||
|
||||
if not reset_bios_action:
|
||||
raise exceptions.MissingActionError(action='#Bios.ResetBios',
|
||||
resource=self._path)
|
||||
return reset_bios_action
|
||||
|
||||
def _get_change_password_element(self):
|
||||
actions = self._actions
|
||||
|
||||
if not actions:
|
||||
raise exceptions.MissingAttributeError(attribute="Actions",
|
||||
resource=self._path)
|
||||
|
||||
change_password_action = actions.change_password
|
||||
|
||||
if not change_password_action:
|
||||
raise exceptions.MissingActionError(action='#Bios.ChangePassword',
|
||||
resource=self._path)
|
||||
return change_password_action
|
||||
|
||||
def reset_bios(self):
|
||||
"""Reset the BIOS attributes to default"""
|
||||
|
||||
target_uri = self._get_reset_bios_action_element().target_uri
|
||||
|
||||
LOG.debug('Resetting BIOS attributes %s ...', self.identity)
|
||||
self._conn.post(target_uri)
|
||||
LOG.info('BIOS attributes %s is being reset', self.identity)
|
||||
|
||||
def change_password(self, new_password, old_password, password_name):
|
||||
"""Change BIOS password"""
|
||||
|
||||
target_uri = self._get_change_password_element().target_uri
|
||||
|
||||
LOG.debug('Changing BIOS password %s ...', self.identity)
|
||||
self._conn.post(target_uri, data={'NewPassword': new_password,
|
||||
'OldPassword': old_password,
|
||||
'PasswordName': password_name})
|
||||
LOG.info('BIOS password %s is being changed', self.identity)
|
||||
|
||||
def _do_refresh(self, force=False):
|
||||
"""Do custom resource specific refresh activities
|
||||
|
||||
On refresh, all sub-resources are marked as stale, i.e.
|
||||
greedy-refresh not done for them unless forced by ``force``
|
||||
argument.
|
||||
"""
|
||||
if self._pending_settings_resource is not None:
|
||||
self._pending_settings_resource.invalidate(force)
|
|
@ -18,6 +18,7 @@ import logging
|
|||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
from sushy.resources.system import bios
|
||||
from sushy.resources.system import constants as sys_cons
|
||||
from sushy.resources.system import ethernet_interface
|
||||
from sushy.resources.system import mappings as sys_maps
|
||||
|
@ -130,6 +131,8 @@ class System(base.ResourceBase):
|
|||
|
||||
_ethernet_interfaces = None
|
||||
|
||||
_bios = None
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a ComputerSystem
|
||||
|
||||
|
@ -289,6 +292,23 @@ class System(base.ResourceBase):
|
|||
self._ethernet_interfaces.refresh(force=False)
|
||||
return self._ethernet_interfaces
|
||||
|
||||
@property
|
||||
def bios(self):
|
||||
"""Property to reference `Bios` instance
|
||||
|
||||
It is set once when the first time it is queried. On refresh,
|
||||
this property is marked as stale (greedy-refresh not done).
|
||||
Here the actual refresh of the sub-resource happens, if stale.
|
||||
"""
|
||||
if self._bios is None:
|
||||
self._bios = bios.Bios(
|
||||
self._conn,
|
||||
utils.get_sub_resource_path_by(self, 'Bios'),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
self._bios.refresh(force=False)
|
||||
return self._bios
|
||||
|
||||
def _do_refresh(self, force=False):
|
||||
"""Do custom resource specific refresh activities
|
||||
|
||||
|
@ -300,6 +320,8 @@ class System(base.ResourceBase):
|
|||
self._processors.invalidate(force)
|
||||
if self._ethernet_interfaces is not None:
|
||||
self._ethernet_interfaces.invalidate(force)
|
||||
if self._bios is not None:
|
||||
self._bios.invalidate(force)
|
||||
|
||||
|
||||
class SystemCollection(base.ResourceCollectionBase):
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"@odata.type": "#Bios.v1_0_0.Bios",
|
||||
"Id": "BIOS",
|
||||
"Name": "BIOS Configuration Current Settings",
|
||||
"AttributeRegistry": "BiosAttributeRegistryP89.v1_0_0",
|
||||
"Attributes": {
|
||||
"AdminPhone": "",
|
||||
"BootMode": "Uefi",
|
||||
"EmbeddedSata": "Raid",
|
||||
"NicBoot1": "NetworkBoot",
|
||||
"NicBoot2": "Disabled",
|
||||
"PowerProfile": "MaxPerf",
|
||||
"ProcCoreDisable": 0,
|
||||
"ProcHyperthreading": "Enabled",
|
||||
"ProcTurboMode": "Enabled",
|
||||
"UsbControl": "UsbEnabled"
|
||||
},
|
||||
"@Redfish.Settings": {
|
||||
"@odata.type": "#Settings.v1_0_0.Settings",
|
||||
"ETag": "9234ac83b9700123cc32",
|
||||
"Messages": [
|
||||
{
|
||||
"MessageId": "Base.1.0.SettingsFailed",
|
||||
"RelatedProperties": [
|
||||
"#/Attributes/ProcTurboMode"
|
||||
]
|
||||
}
|
||||
],
|
||||
"SettingsObject": {
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/BIOS/Settings"
|
||||
},
|
||||
"Time": "2016-03-07T14:44.30-05:00"
|
||||
},
|
||||
"Actions": {
|
||||
"#Bios.ResetBios": {
|
||||
"target": "/redfish/v1/Systems/437XR1138R2/BIOS/Actions/Bios.ResetBios"
|
||||
},
|
||||
"#Bios.ChangePassword": {
|
||||
"target": "/redfish/v1/Systems/437XR1138R2/BIOS/Actions/Bios.ChangePassword"
|
||||
}
|
||||
},
|
||||
"@odata.etag": "123",
|
||||
"@odata.context": "/redfish/v1/$metadata#Bios.Bios",
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/BIOS"
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"@odata.type": "#Bios.v1_0_0.Bios",
|
||||
"Id": "Settings",
|
||||
"Name": "BIOS Configuration Pending Settings",
|
||||
"AttributeRegistry": "BiosAttributeRegistryP89.v1_0_0",
|
||||
"Attributes": {
|
||||
"AdminPhone": "(404) 555-1212",
|
||||
"BootMode": "Uefi",
|
||||
"EmbeddedSata": "Ahci",
|
||||
"NicBoot1": "NetworkBoot",
|
||||
"NicBoot2": "NetworkBoot",
|
||||
"PowerProfile": "MaxPerf",
|
||||
"ProcCoreDisable": 0,
|
||||
"ProcHyperthreading": "Enabled",
|
||||
"ProcTurboMode": "Disabled",
|
||||
"UsbControl": "UsbEnabled"
|
||||
},
|
||||
"@odata.context": "/redfish/v1/$metadata#Bios.Bios",
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/BIOS/Settings",
|
||||
"@Redfish.Copyright": "Copyright 2014-2016 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"@Redfish.Settings": {
|
||||
"@odata.type": "#Settings.v1_0_0.Settings",
|
||||
"ETag": "9234ac83b9700123cc32",
|
||||
"Messages": [{
|
||||
"MessageId": "Base.1.0.SettingsFailed",
|
||||
"Message": "Settings update failed due to invalid value",
|
||||
"Severity": "High",
|
||||
"Resolution": "Fix the value and try again",
|
||||
"MessageArgs": [
|
||||
"arg1"
|
||||
],
|
||||
"RelatedProperties": [
|
||||
"#/Attributes/ProcTurboMode"
|
||||
]
|
||||
}],
|
||||
"SettingsObject": {
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/BIOS/Settings"
|
||||
},
|
||||
"Time": "2016-03-07T14:44.30-05:00"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
# 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
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources.system import bios
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class BiosTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BiosTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/bios.json', 'r') as f:
|
||||
bios_json = json.loads(f.read())
|
||||
with open('sushy/tests/unit/json_samples/bios_settings.json',
|
||||
'r') as f:
|
||||
bios_settings_json = json.loads(f.read())
|
||||
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
bios_json,
|
||||
bios_settings_json,
|
||||
bios_settings_json]
|
||||
|
||||
self.sys_bios = bios.Bios(
|
||||
self.conn, '/redfish/v1/Systems/437XR1138R2/BIOS',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.sys_bios._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.sys_bios.redfish_version)
|
||||
self.assertEqual('BIOS', self.sys_bios.identity)
|
||||
self.assertEqual('BIOS Configuration Current Settings',
|
||||
self.sys_bios.name)
|
||||
self.assertIsNone(self.sys_bios.description)
|
||||
self.assertEqual('123', self.sys_bios._etag)
|
||||
self.assertEqual('BiosAttributeRegistryP89.v1_0_0',
|
||||
self.sys_bios.attribute_registry)
|
||||
self.assertEqual('', self.sys_bios.attributes['AdminPhone'])
|
||||
self.assertEqual('Uefi', self.sys_bios.attributes['BootMode'])
|
||||
self.assertEqual(0, self.sys_bios.attributes['ProcCoreDisable'])
|
||||
# testing here if settings subfield parsed by checking ETag,
|
||||
# other settings fields tested in specific settings test
|
||||
self.assertEqual('9234ac83b9700123cc32',
|
||||
self.sys_bios._settings._etag)
|
||||
self.assertEqual('(404) 555-1212',
|
||||
self.sys_bios.pending_attributes['AdminPhone'])
|
||||
|
||||
def test_set_attribute(self):
|
||||
self.sys_bios.set_attribute('ProcTurboMode', 'Disabled')
|
||||
self.sys_bios._conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2/BIOS/Settings',
|
||||
data={'Attributes': {'ProcTurboMode': 'Disabled'}},
|
||||
headers={'If-Match': '123'})
|
||||
|
||||
def test_set_attribute_on_refresh(self):
|
||||
# make it to instantiate pending attributes
|
||||
self.sys_bios.pending_attributes
|
||||
self.sys_bios.set_attribute('ProcTurboMode', 'Disabled')
|
||||
self.assertTrue(self.sys_bios._pending_settings_resource._is_stale)
|
||||
# make it to refresh pending attributes on next retrieval
|
||||
self.sys_bios.pending_attributes
|
||||
self.assertFalse(self.sys_bios._pending_settings_resource._is_stale)
|
||||
|
||||
def test_set_attributes(self):
|
||||
self.sys_bios.set_attributes({'ProcTurboMode': 'Disabled',
|
||||
'UsbControl': 'UsbDisabled'})
|
||||
self.sys_bios._conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2/BIOS/Settings',
|
||||
data={'Attributes': {'ProcTurboMode': 'Disabled',
|
||||
'UsbControl': 'UsbDisabled'}},
|
||||
headers={'If-Match': '123'})
|
||||
|
||||
def test_set_attributes_on_refresh(self):
|
||||
# make it to instantiate pending attributes
|
||||
self.sys_bios.pending_attributes
|
||||
self.sys_bios.set_attributes({'ProcTurboMode': 'Disabled',
|
||||
'UsbControl': 'UsbDisabled'})
|
||||
self.assertTrue(self.sys_bios._pending_settings_resource._is_stale)
|
||||
# make it to refresh pending attributes on next retrieval
|
||||
self.sys_bios.pending_attributes
|
||||
self.assertFalse(self.sys_bios._pending_settings_resource._is_stale)
|
||||
|
||||
def test__get_reset_bios_action_element(self):
|
||||
value = self.sys_bios._get_reset_bios_action_element()
|
||||
self.assertEqual('/redfish/v1/Systems/437XR1138R2/BIOS/Actions/'
|
||||
'Bios.ResetBios',
|
||||
value.target_uri)
|
||||
|
||||
def test_reset_bios_missing_action(self):
|
||||
self.sys_bios._actions.reset_bios = None
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingActionError, '#Bios.ResetBios',
|
||||
self.sys_bios.reset_bios)
|
||||
|
||||
def test__parse_attributes_missing_reset_bios_target(self):
|
||||
self.sys_bios.json['Actions']['#Bios.ResetBios'].pop(
|
||||
'target')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
'attribute Actions/#Bios.ResetBios/target',
|
||||
self.sys_bios._parse_attributes)
|
||||
|
||||
def test_reset_bios(self):
|
||||
self.sys_bios.reset_bios()
|
||||
self.sys_bios._conn.post.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2/BIOS/Actions/Bios.ResetBios')
|
||||
|
||||
def test__get_change_password_element(self):
|
||||
value = self.sys_bios._get_change_password_element()
|
||||
self.assertEqual("/redfish/v1/Systems/437XR1138R2/BIOS/Actions/"
|
||||
"Bios.ChangePassword",
|
||||
value.target_uri)
|
||||
|
||||
def test_change_password_missing_action(self):
|
||||
self.sys_bios._actions.change_password = None
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingActionError, '#Bios.ChangePassword',
|
||||
self.sys_bios.change_password, 'newpassword',
|
||||
'oldpassword',
|
||||
'adminpassword')
|
||||
|
||||
def test__parse_attributes_missing_change_password_target(self):
|
||||
self.sys_bios.json['Actions']['#Bios.ChangePassword'].pop(
|
||||
'target')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
'attribute Actions/#Bios.ChangePassword/target',
|
||||
self.sys_bios._parse_attributes)
|
||||
|
||||
def test_change_password(self):
|
||||
self.sys_bios.change_password('newpassword',
|
||||
'oldpassword',
|
||||
'adminpassword')
|
||||
self.sys_bios._conn.post.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2/BIOS/Actions/Bios.ChangePassword',
|
||||
data={'OldPassword': 'oldpassword',
|
||||
'NewPassword': 'newpassword',
|
||||
'PasswordName': 'adminpassword'})
|
|
@ -19,6 +19,7 @@ import mock
|
|||
|
||||
import sushy
|
||||
from sushy import exceptions
|
||||
from sushy.resources.system import bios
|
||||
from sushy.resources.system import constants as sys_cons
|
||||
from sushy.resources.system import ethernet_interface
|
||||
from sushy.resources.system import mappings as sys_map
|
||||
|
@ -66,6 +67,7 @@ class SystemTestCase(base.TestCase):
|
|||
self.assertEqual("OK", self.sys_inst.memory_summary.health)
|
||||
self.assertIsNone(self.sys_inst._processors)
|
||||
self.assertIsNone(self.sys_inst._ethernet_interfaces)
|
||||
self.assertIsNone(self.sys_inst._bios)
|
||||
|
||||
def test__parse_attributes_missing_actions(self):
|
||||
self.sys_inst.json.pop('Actions')
|
||||
|
@ -379,6 +381,18 @@ class SystemTestCase(base.TestCase):
|
|||
self.assertIsInstance(self.sys_inst._ethernet_interfaces,
|
||||
ethernet_interface.EthernetInterfaceCollection)
|
||||
|
||||
def test_bios(self):
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
bios_return_value = None
|
||||
with open('sushy/tests/unit/json_samples/bios.json', 'r') as f:
|
||||
bios_return_value = json.loads(f.read())
|
||||
self.conn.get.return_value.json.side_effect = [bios_return_value]
|
||||
|
||||
self.assertIsNone(self.sys_inst._bios)
|
||||
self.assertIsInstance(self.sys_inst.bios, bios.Bios)
|
||||
self.assertEqual('BIOS Configuration Current Settings',
|
||||
self.sys_inst.bios.name)
|
||||
|
||||
|
||||
class SystemCollectionTestCase(base.TestCase):
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# Copyright 2017 Red Hat, Inc.
|
||||
# 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
|
||||
|
||||
from sushy.resources import settings
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class SettingsFieldTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SettingsFieldTestCase, self).setUp()
|
||||
with open('sushy/tests/unit/json_samples/settings.json',
|
||||
'r') as f:
|
||||
self.json = json.loads(f.read())
|
||||
|
||||
self.settings = settings.SettingsField()
|
||||
|
||||
def test__load(self):
|
||||
instance = self.settings._load(self.json, mock.Mock())
|
||||
|
||||
self.assertEqual('9234ac83b9700123cc32',
|
||||
instance._etag)
|
||||
self.assertEqual('2016-03-07T14:44.30-05:00',
|
||||
instance.time)
|
||||
self.assertEqual('/redfish/v1/Systems/437XR1138R2/BIOS/Settings',
|
||||
instance._settings_object_idref.resource_uri)
|
||||
self.assertEqual('Base.1.0.SettingsFailed',
|
||||
instance.messages[0].message_id)
|
||||
self.assertEqual('Settings update failed due to invalid value',
|
||||
instance.messages[0].message)
|
||||
self.assertEqual('High',
|
||||
instance.messages[0].severity)
|
||||
self.assertEqual('Fix the value and try again',
|
||||
instance.messages[0].resolution)
|
||||
self.assertEqual('arg1',
|
||||
instance.messages[0].message_args[0])
|
||||
self.assertEqual('#/Attributes/ProcTurboMode',
|
||||
instance.messages[0]._related_properties[0])
|
||||
self.assertEqual('/redfish/v1/Systems/437XR1138R2/BIOS/Settings',
|
||||
instance._settings_object_idref.resource_uri)
|
||||
|
||||
def test_commit(self):
|
||||
conn = mock.Mock()
|
||||
instance = self.settings._load(self.json, conn)
|
||||
instance.commit(conn, {'Attributes': {'key': 'value'}})
|
||||
conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2/BIOS/Settings',
|
||||
data={'Attributes': {'key': 'value'}}, headers=None)
|
||||
|
||||
def test_commit_with_etag(self):
|
||||
conn = mock.Mock()
|
||||
instance = self.settings._load(self.json, conn)
|
||||
instance.commit(conn,
|
||||
{'Attributes': {'key': 'value'}},
|
||||
'123')
|
||||
conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2/BIOS/Settings',
|
||||
data={'Attributes': {'key': 'value'}},
|
||||
headers={'If-Match': '123'})
|
Loading…
Reference in New Issue