Add manager resource

This patch adds the Manager/ManagerCollection resource. Manager
resource will provide information about remote access controls like
serial console, command shell, graphical console etc. It will also
serve as the gateway to virtual media, ethernet interfaces (NICs)
information.
'ResetActionField' moved to a new file, "resources/common.py",
to be reused both by system and manager resource. Necessary changes
are also made to the usage documentation page pertaining to Manager
resource.

Partial-Bug: #1673886
Change-Id: I1d1b9b3f13002e654e4dc62d0558f5a2afbd8662
This commit is contained in:
Debayan Ray 2017-03-03 12:48:22 -05:00
parent 963c83ab78
commit bdce45aa43
15 changed files with 824 additions and 46 deletions

View File

@ -9,7 +9,7 @@ Welcome to Sushy's documentation!
Contents:
.. toctree::
:maxdepth: 1
:maxdepth: 2
About Sushy <readme>
installation

View File

@ -6,6 +6,10 @@ Usage
To use sushy in a project:
----------------------------------------
Creating and using a sushy system object
----------------------------------------
.. code-block:: python
import logging
@ -17,7 +21,8 @@ To use sushy in a project:
LOG.setLevel(logging.DEBUG)
LOG.addHandler(logging.StreamHandler())
s = sushy.Sushy('http://localhost:8000', username='foo', password='bar')
s = sushy.Sushy('http://localhost:8000/redfish/v1',
username='foo', password='bar')
# Get the Redfish version
print(s.redfish_version)
@ -79,6 +84,74 @@ To use sushy in a project:
print(sys_inst.processors.summary)
-----------------------------------------
Creating and using a sushy manager object
-----------------------------------------
.. code-block:: python
import logging
import sushy
# Enable logging at DEBUG level
LOG = logging.getLogger('sushy')
LOG.setLevel(logging.DEBUG)
LOG.addHandler(logging.StreamHandler())
s = sushy.Sushy('http://localhost:8000/redfish/v1',
username='foo', password='bar')
# Instantiate a manager object
mgr_inst = s.get_manager('BMC')
# Get the manager name & description
print(mgr_inst.name)
print(mgr_inst.description)
# Using manager collections
# Instantiate a ManagerCollection object
mgr_col = s.get_manager_collection()
# Print the ID of the managers available in the collection
print(mgr_col.members_identities)
# Get a list of manager objects available in the collection
mgr_insts = mgr_col.get_members()
# Instantiate a manager object, same as getting it directly
# from the s.get_manager()
mgr_inst = mgr_col.get_member(mgr_col.members_identities[0])
# Refresh the manager collection object
mgr_col.refresh()
# Using manager actions
# Get supported graphical console types
print(mgr_inst.get_supported_graphical_console_types())
# Get supported serial console types
print(mgr_inst.get_supported_serial_console_types())
# Get supported command shell types
print(mgr_inst.get_supported_command_shell_types())
# Get a list of allowed manager reset values
print(mgr_inst.get_allowed_reset_manager_values())
# Reset the manager
mgr_inst.reset_manager(sushy.RESET_MANAGER_FORCE_RESTART)
# Refresh the manager object
mgr_inst.refresh()
If you do not have any real baremetal machine that supports the Redfish
protocol you can look at the :ref:`contributing` page to learn how to
run a Redfish emulator.

View File

@ -18,6 +18,7 @@ import pbr.version
from sushy.main import Sushy
from sushy.resources.system.constants import * # noqa
from sushy.resources.manager.constants import * # noqa
__all__ = ('Sushy',)
__version__ = pbr.version.VersionInfo(

View File

@ -14,21 +14,27 @@
# under the License.
from sushy import connector
from sushy import exceptions
from sushy.resources import base
from sushy.resources.manager import manager
from sushy.resources.system import system
class Sushy(base.ResourceBase):
identity = None
"""The Redfish system identity"""
identity = base.Field('Id', required=True)
"""The Redfish root service identity"""
name = None
"""The Redfish system name"""
name = base.Field('Name')
"""The Redfish root service name"""
uuid = None
"""The Redfish system UUID"""
uuid = base.Field('UUID')
"""The Redfish root service UUID"""
_systems_path = base.Field(['Systems', '@odata.id'], required=True)
"""SystemCollection path"""
_managers_path = base.Field(['Managers', '@odata.id'], required=True)
"""ManagerCollection path"""
def __init__(self, base_url, username=None, password=None,
root_prefix='/redfish/v1/', verify=True):
@ -55,18 +61,8 @@ class Sushy(base.ResourceBase):
path=self._root_prefix)
def _parse_attributes(self):
self.identity = self.json.get('Id')
self.name = self.json.get('Name')
super(Sushy, self)._parse_attributes()
self.redfish_version = self.json.get('RedfishVersion')
self.uuid = self.json.get('UUID')
def _get_system_collection_path(self):
"""Helper function to find the SystemCollection path"""
systems_col = self.json.get('Systems')
if not systems_col:
raise exceptions.MissingAttributeError(attribute='Systems',
resource=self._path)
return systems_col.get('@odata.id')
def get_system_collection(self):
"""Get the SystemCollection object
@ -75,9 +71,8 @@ class Sushy(base.ResourceBase):
not found
:returns: a SystemCollection object
"""
return system.SystemCollection(
self._conn, self._get_system_collection_path(),
redfish_version=self.redfish_version)
return system.SystemCollection(self._conn, self._systems_path,
redfish_version=self.redfish_version)
def get_system(self, identity):
"""Given the identity return a System object
@ -87,3 +82,22 @@ class Sushy(base.ResourceBase):
"""
return system.System(self._conn, identity,
redfish_version=self.redfish_version)
def get_manager_collection(self):
"""Get the ManagerCollection object
:raises: MissingAttributeError, if the collection attribute is
not found
:returns: a ManagerCollection object
"""
return manager.ManagerCollection(self._conn, self._managers_path,
redfish_version=self.redfish_version)
def get_manager(self, identity):
"""Given the identity return a Manager object
:param identity: The identity of the Manager resource
:returns: The Manager object
"""
return manager.Manager(self._conn, identity,
redfish_version=self.redfish_version)

20
sushy/resources/common.py Normal file
View File

@ -0,0 +1,20 @@
# 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
class ResetActionField(base.CompositeField):
allowed_values = base.Field('ResetType@Redfish.AllowableValues',
adapter=list)
target_uri = base.Field('target', required=True)

View File

View File

@ -0,0 +1,78 @@
# 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.
# Values comes from the Redfish System json-schema 1.0.0:
# http://redfish.dmtf.org/schemas/v1/Manager.v1_0_0.json#/definitions/Manager # noqa
# Manager Reset action constants
RESET_MANAGER_GRACEFUL_RESTART = 'graceful restart'
RESET_MANAGER_FORCE_RESTART = 'force restart'
# Manager Type constants
MANAGER_TYPE_MANAGEMENT_CONTROLLER = 'management controller'
"""A controller used primarily to monitor or manage the operation of
a device or system"""
MANAGER_TYPE_ENCLOSURE_MANAGER = 'enclosure manager'
"""A controller which provides management functions for a chassis
or group of devices or systems"""
MANAGER_TYPE_BMC = 'bmc'
"""A controller which provides management functions for a single
computer system"""
MANAGER_TYPE_RACK_MANAGER = 'rack manager'
"""A controller which provides management functions for a whole or part
of a rack"""
MANAGER_TYPE_AUXILIARY_CONTROLLER = 'auxiliary controller'
"""A controller which provides management functions for a particular
subsystem or group of devices"""
# Graphical Console constants
GRAPHICAL_CONSOLE_KVMIP = 'graphical console kvmip'
"""Graphical Console connection using a KVM-IP (redirection of Keyboard,
Video, Mouse over IP) protocol"""
GRAPHICAL_CONSOLE_OEM = 'graphical console oem'
"""Graphical Console connection using an OEM-specific protocol"""
# Serial Console constants
SERIAL_CONSOLE_SSH = 'serial console ssh'
"""Serial Console connection using the SSH protocol"""
SERIAL_CONSOLE_TELNET = 'serial console telnet'
"""Serial Console connection using the Telnet protocol"""
SERIAL_CONSOLE_IPMI = 'serial console ipmi'
"""Serial Console connection using the IPMI Serial-over-LAN (SOL) protocol"""
SERIAL_CONSOLE_OEM = 'serial console oem'
"""Serial Console connection using an OEM-specific protocol"""
# Command Shell constants
COMMAND_SHELL_SSH = 'command shell ssh'
"""Command Shell connection using the SSH protocol"""
COMMAND_SHELL_TELNET = 'command shell telnet'
"""Command Shell connection using the Telnet protocol"""
COMMAND_SHELL_IPMI = 'command shell ipmi'
"""Command Shell connection using the IPMI Serial-over-LAN (SOL) protocol"""
COMMAND_SHELL_OEM = 'command shell oem'
"""Command Shell connection using an OEM-specific protocol"""

View File

@ -0,0 +1,197 @@
# 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 logging
from sushy import exceptions
from sushy.resources import base
from sushy.resources import common
from sushy.resources.manager import mappings as mgr_maps
LOG = logging.getLogger(__name__)
class ActionsField(base.CompositeField):
reset = common.ResetActionField('#Manager.Reset')
class RemoteAccessField(base.CompositeField):
service_enabled = base.Field('ServiceEnabled')
max_concurrent_sessions = base.Field('MaxConcurrentSessions')
connect_types_supported = base.Field('ConnectTypesSupported',
adapter=list)
class Manager(base.ResourceBase):
firmware_version = base.Field('FirmwareVersion')
"""The manager firmware version"""
graphical_console = RemoteAccessField('GraphicalConsole')
"""A dictionary containing the remote access support service via
graphical console (e.g. KVMIP) and max concurrent sessions
"""
serial_console = RemoteAccessField('SerialConsole')
"""A dictionary containing the remote access support service via
serial console (e.g. Telnet, SSH, IPMI) and max concurrent sessions
"""
command_shell = RemoteAccessField('CommandShell')
"""A dictionary containing the remote access support service via
command shell (e.g. Telnet, SSH) and max concurrent sessions
"""
description = base.Field('Description')
"""The manager description"""
identity = base.Field('Id', required=True)
"""The manager identity string"""
name = base.Field('Name')
"""The manager name"""
model = base.Field('Model')
"""The manager model"""
manager_type = base.MappedField('ManagerType',
mgr_maps.MANAGER_TYPE_VALUE_MAP)
"""The manager type"""
uuid = base.Field('UUID')
"""The manager UUID"""
_actions = ActionsField('Actions', required=True)
def __init__(self, connector, identity, redfish_version=None):
"""A class representing a Manager
:param connector: A Connector instance
:param identity: The identity of the Manager resource
:param redfish_version: The version of RedFish. Used to construct
the object according to schema of the given version.
"""
super(Manager, self).__init__(connector, identity, redfish_version)
def get_supported_graphical_console_types(self):
"""Get the supported values for Graphical Console connection types.
:returns: A set of supported values.
"""
if (not self.graphical_console
or not self.graphical_console.connect_types_supported):
LOG.warning('Could not figure out the supported values for '
'remote access via graphical console for Manager %s',
self.identity)
return set(mgr_maps.GRAPHICAL_CONSOLE_VALUE_MAP_REV)
return set([mgr_maps.GRAPHICAL_CONSOLE_VALUE_MAP[v] for v in
set(mgr_maps.GRAPHICAL_CONSOLE_VALUE_MAP).
intersection(self.graphical_console.
connect_types_supported)])
def get_supported_serial_console_types(self):
"""Get the supported values for Serial Console connection types.
:returns: A set of supported values.
"""
if (not self.serial_console
or not self.serial_console.connect_types_supported):
LOG.warning('Could not figure out the supported values for '
'remote access via serial console for Manager %s',
self.identity)
return set(mgr_maps.SERIAL_CONSOLE_VALUE_MAP_REV)
return set([mgr_maps.SERIAL_CONSOLE_VALUE_MAP[v] for v in
set(mgr_maps.SERIAL_CONSOLE_VALUE_MAP).
intersection(self.serial_console.connect_types_supported)])
def get_supported_command_shell_types(self):
"""Get the supported values for Command Shell connection types.
:returns: A set of supported values.
"""
if (not self.command_shell
or not self.command_shell.connect_types_supported):
LOG.warning('Could not figure out the supported values for '
'remote access via command shell for Manager %s',
self.identity)
return set(mgr_maps.COMMAND_SHELL_VALUE_MAP_REV)
return set([mgr_maps.COMMAND_SHELL_VALUE_MAP[v] for v in
set(mgr_maps.COMMAND_SHELL_VALUE_MAP).
intersection(self.command_shell.connect_types_supported)])
def _get_reset_action_element(self):
reset_action = self._actions.reset
if not reset_action:
raise exceptions.MissingActionError(action='#Manager.Reset',
resource=self._path)
return reset_action
def get_allowed_reset_manager_values(self):
"""Get the allowed values for resetting the manager.
:returns: A set of allowed values.
:raises: MissingAttributeError, if Actions/#Manager.Reset attribute
not present.
"""
reset_action = self._get_reset_action_element()
if not reset_action.allowed_values:
LOG.warning('Could not figure out the allowed values for the '
'reset manager action for Manager %s', self.identity)
return set(mgr_maps.RESET_MANAGER_VALUE_MAP_REV)
return set([mgr_maps.RESET_MANAGER_VALUE_MAP[v] for v in
set(mgr_maps.RESET_MANAGER_VALUE_MAP).
intersection(reset_action.allowed_values)])
def reset_manager(self, value):
"""Reset the manager.
:param value: The target value.
:raises: InvalidParameterValueError, if the target value is not
allowed.
"""
valid_resets = self.get_allowed_reset_manager_values()
if value not in valid_resets:
raise exceptions.InvalidParameterValueError(
parameter='value', value=value, valid_values=valid_resets)
value = mgr_maps.RESET_MANAGER_VALUE_MAP_REV[value]
target_uri = self._get_reset_action_element().target_uri
LOG.debug('Resetting the Manager %s ...', self.identity)
self._conn.post(target_uri, data={'ResetType': value})
LOG.info('The Manager %s is being reset', self.identity)
class ManagerCollection(base.ResourceCollectionBase):
@property
def _resource_type(self):
return Manager
def __init__(self, connector, path, redfish_version=None):
"""A class representing a ManagerCollection
:param connector: A Connector instance
:param path: The canonical path to the Manager collection resource
:param redfish_version: The version of RedFish. Used to construct
the object according to schema of the given version.
"""
super(ManagerCollection, self).__init__(connector, path,
redfish_version)

View File

@ -0,0 +1,61 @@
# 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.manager import constants as mgr_cons
from sushy import utils
RESET_MANAGER_VALUE_MAP = {
'GracefulRestart': mgr_cons.RESET_MANAGER_GRACEFUL_RESTART,
'ForceRestart': mgr_cons.RESET_MANAGER_FORCE_RESTART,
}
RESET_MANAGER_VALUE_MAP_REV = utils.revert_dictionary(RESET_MANAGER_VALUE_MAP)
MANAGER_TYPE_VALUE_MAP = {
'ManagementController': mgr_cons.MANAGER_TYPE_MANAGEMENT_CONTROLLER,
'EnclosureManager': mgr_cons.MANAGER_TYPE_ENCLOSURE_MANAGER,
'BMC': mgr_cons.MANAGER_TYPE_BMC,
'RackManager': mgr_cons.MANAGER_TYPE_RACK_MANAGER,
'AuxiliaryController': mgr_cons.MANAGER_TYPE_AUXILIARY_CONTROLLER
}
MANAGER_TYPE_VALUE_MAP_REV = (
utils.revert_dictionary(MANAGER_TYPE_VALUE_MAP))
GRAPHICAL_CONSOLE_VALUE_MAP = {
'KVMIP': mgr_cons.GRAPHICAL_CONSOLE_KVMIP,
'Oem': mgr_cons.GRAPHICAL_CONSOLE_OEM,
}
GRAPHICAL_CONSOLE_VALUE_MAP_REV = (
utils.revert_dictionary(GRAPHICAL_CONSOLE_VALUE_MAP))
SERIAL_CONSOLE_VALUE_MAP = {
'SSH': mgr_cons.SERIAL_CONSOLE_SSH,
'Telnet': mgr_cons.SERIAL_CONSOLE_TELNET,
'IPMI': mgr_cons.SERIAL_CONSOLE_IPMI,
'Oem': mgr_cons.SERIAL_CONSOLE_OEM,
}
SERIAL_CONSOLE_VALUE_MAP_REV = (
utils.revert_dictionary(SERIAL_CONSOLE_VALUE_MAP))
COMMAND_SHELL_VALUE_MAP = {
'SSH': mgr_cons.COMMAND_SHELL_SSH,
'Telnet': mgr_cons.COMMAND_SHELL_TELNET,
'IPMI': mgr_cons.COMMAND_SHELL_IPMI,
'Oem': mgr_cons.COMMAND_SHELL_OEM,
}
COMMAND_SHELL_VALUE_MAP_REV = (
utils.revert_dictionary(COMMAND_SHELL_VALUE_MAP))

View File

@ -17,6 +17,7 @@ import logging
from sushy import exceptions
from sushy.resources import base
from sushy.resources import common
from sushy.resources.system import constants as sys_cons
from sushy.resources.system import mappings as sys_maps
from sushy.resources.system import processor
@ -25,15 +26,8 @@ from sushy.resources.system import processor
LOG = logging.getLogger(__name__)
class ResetActionField(base.CompositeField):
allowed_values = base.Field('ResetType@Redfish.AllowableValues',
adapter=list)
target_uri = base.Field('target', required=True)
class ActionsField(base.CompositeField):
reset = ResetActionField('#ComputerSystem.Reset')
reset = common.ResetActionField('#ComputerSystem.Reset')
class BootField(base.CompositeField):

View File

@ -0,0 +1,86 @@
{
"@odata.type": "#Manager.v1_1_0.Manager",
"Id": "BMC",
"Name": "Manager",
"ManagerType": "BMC",
"Description": "Contoso BMC",
"ServiceEntryPointUUID": "92384634-2938-2342-8820-489239905423",
"UUID": "58893887-8974-2487-2389-841168418919",
"Model": "Joo Janta 200",
"DateTime": "2015-03-13T04:14:33+06:00",
"DateTimeLocalOffset": "+06:00",
"Status": {
"State": "Enabled",
"Health": "OK"
},
"GraphicalConsole": {
"ServiceEnabled": true,
"MaxConcurrentSessions": 2,
"ConnectTypesSupported": [
"KVMIP"
]
},
"SerialConsole": {
"ServiceEnabled": true,
"MaxConcurrentSessions": 1,
"ConnectTypesSupported": [
"Telnet",
"SSH",
"IPMI"
]
},
"CommandShell": {
"ServiceEnabled": true,
"MaxConcurrentSessions": 4,
"ConnectTypesSupported": [
"Telnet",
"SSH"
]
},
"FirmwareVersion": "1.00",
"NetworkProtocol": {
"@odata.id": "/redfish/v1/Managers/BMC/NetworkProtocol"
},
"EthernetInterfaces": {
"@odata.id": "/redfish/v1/Managers/BMC/NICs"
},
"SerialInterfaces": {
"@odata.id": "/redfish/v1/Managers/BMC/SerialInterfaces"
},
"LogServices": {
"@odata.id": "/redfish/v1/Managers/BMC/LogServices"
},
"VirtualMedia": {
"@odata.id": "/redfish/v1/Managers/BMC/VirtualMedia"
},
"Links": {
"ManagerForServers": [
{
"@odata.id": "/redfish/v1/Systems/437XR1138R2"
}
],
"ManagerForChassis": [
{
"@odata.id": "/redfish/v1/Chassis/1U"
}
],
"ManagerInChassis": {
"@odata.id": "/redfish/v1/Chassis/1U"
},
"Oem": {}
},
"Actions": {
"#Manager.Reset": {
"target": "/redfish/v1/Managers/BMC/Actions/Manager.Reset",
"ResetType@Redfish.AllowableValues": [
"ForceRestart",
"GracefulRestart"
]
},
"Oem": {}
},
"Oem": {},
"@odata.context": "/redfish/v1/$metadata#Manager.Manager",
"@odata.id": "/redfish/v1/Managers/BMC",
"@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."
}

View File

@ -0,0 +1,14 @@
{
"@odata.type": "#ManagerCollection.ManagerCollection",
"Name": "Manager Collection",
"Members@odata.count": 1,
"Members": [
{
"@odata.id": "/redfish/v1/Managers/BMC"
}
],
"Oem": {},
"@odata.context": "/redfish/v1/$metadata#Managers",
"@odata.id": "/redfish/v1/Managers",
"@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."
}

View File

@ -0,0 +1,235 @@
# 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 sushy
from sushy import exceptions
from sushy.resources.manager import manager
from sushy.tests.unit import base
class ManagerTestCase(base.TestCase):
def setUp(self):
super(ManagerTestCase, self).setUp()
self.conn = mock.Mock()
with open('sushy/tests/unit/json_samples/manager.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.manager = manager.Manager(self.conn, '/redfish/v1/Managers/BMC',
redfish_version='1.0.2')
def test__parse_attributes(self):
# | WHEN |
self.manager._parse_attributes()
# | THEN |
self.assertEqual('1.0.2', self.manager.redfish_version)
self.assertEqual('1.00', self.manager.firmware_version)
self.assertEqual(True, self.manager.graphical_console.service_enabled)
self.assertEqual(
2, self.manager.graphical_console.max_concurrent_sessions)
self.assertEqual(True, self.manager.serial_console.service_enabled)
self.assertEqual(
1, self.manager.serial_console.max_concurrent_sessions)
self.assertEqual(True, self.manager.command_shell.service_enabled)
self.assertEqual(
4, self.manager.command_shell.max_concurrent_sessions)
self.assertEqual('Contoso BMC', self.manager.description)
self.assertEqual('BMC', self.manager.identity)
self.assertEqual('Manager', self.manager.name)
self.assertEqual('Joo Janta 200', self.manager.model)
self.assertEqual(sushy.MANAGER_TYPE_BMC, self.manager.manager_type)
self.assertEqual('58893887-8974-2487-2389-841168418919',
self.manager.uuid)
def test_get_supported_graphical_console_types(self):
# | GIVEN |
expected = set([sushy.GRAPHICAL_CONSOLE_KVMIP])
# | WHEN |
values = self.manager.get_supported_graphical_console_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_supported_graphical_console_types_for_no_connect_types(self):
# | GIVEN |
graphical_console = self.manager.graphical_console
expected = set([sushy.GRAPHICAL_CONSOLE_KVMIP,
sushy.GRAPHICAL_CONSOLE_OEM])
for val in [None, []]:
graphical_console.connect_types_supported = val
# | WHEN |
values = self.manager.get_supported_graphical_console_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_supported_graphical_console_types_missing_graphcon_attr(self):
# | GIVEN |
self.manager.graphical_console = None
expected = set([sushy.GRAPHICAL_CONSOLE_KVMIP,
sushy.GRAPHICAL_CONSOLE_OEM])
# | WHEN |
values = self.manager.get_supported_graphical_console_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_supported_serial_console_types(self):
# | GIVEN |
expected = set([sushy.SERIAL_CONSOLE_SSH,
sushy.SERIAL_CONSOLE_TELNET,
sushy.SERIAL_CONSOLE_IPMI])
# | WHEN |
values = self.manager.get_supported_serial_console_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_supported_serial_console_types_for_no_connect_types(self):
# | GIVEN |
serial_console = self.manager.serial_console
expected = set([sushy.SERIAL_CONSOLE_SSH,
sushy.SERIAL_CONSOLE_TELNET,
sushy.SERIAL_CONSOLE_IPMI,
sushy.SERIAL_CONSOLE_OEM])
for val in [None, []]:
serial_console.connect_types_supported = val
# | WHEN |
values = self.manager.get_supported_serial_console_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_supported_serial_console_types_missing_serialcon_attr(self):
# | GIVEN |
self.manager.serial_console = None
expected = set([sushy.SERIAL_CONSOLE_SSH,
sushy.SERIAL_CONSOLE_TELNET,
sushy.SERIAL_CONSOLE_IPMI,
sushy.SERIAL_CONSOLE_OEM])
# | WHEN |
values = self.manager.get_supported_serial_console_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_supported_command_shell_types(self):
# | GIVEN |
expected = set([sushy.COMMAND_SHELL_SSH,
sushy.COMMAND_SHELL_TELNET])
# | WHEN |
values = self.manager.get_supported_command_shell_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_supported_command_shell_types_for_no_connect_types(self):
# | GIVEN |
command_shell = self.manager.command_shell
expected = set([sushy.COMMAND_SHELL_SSH,
sushy.COMMAND_SHELL_TELNET,
sushy.COMMAND_SHELL_IPMI,
sushy.COMMAND_SHELL_OEM])
for val in [None, []]:
command_shell.connect_types_supported = val
# | WHEN |
values = self.manager.get_supported_command_shell_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_supported_command_shell_types_missing_cmdshell_attr(self):
# | GIVEN |
self.manager.command_shell = None
expected = set([sushy.COMMAND_SHELL_SSH,
sushy.COMMAND_SHELL_TELNET,
sushy.COMMAND_SHELL_IPMI,
sushy.COMMAND_SHELL_OEM])
# | WHEN |
values = self.manager.get_supported_command_shell_types()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_allowed_reset_manager_values(self):
# | GIVEN |
expected = set([sushy.RESET_MANAGER_GRACEFUL_RESTART,
sushy.RESET_MANAGER_FORCE_RESTART])
# | WHEN |
values = self.manager.get_allowed_reset_manager_values()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_allowed_reset_manager_values_for_no_values_set(self):
# | GIVEN |
self.manager._actions.reset.allowed_values = []
expected = set([sushy.RESET_MANAGER_GRACEFUL_RESTART,
sushy.RESET_MANAGER_FORCE_RESTART])
# | WHEN |
values = self.manager.get_allowed_reset_manager_values()
# | THEN |
self.assertEqual(expected, values)
self.assertIsInstance(values, set)
def test_get_allowed_reset_manager_values_missing_action_reset_attr(self):
# | GIVEN |
self.manager._actions.reset = None
# | WHEN & THEN |
self.assertRaisesRegex(
exceptions.MissingActionError, 'action #Manager.Reset',
self.manager.get_allowed_reset_manager_values)
def test_reset_manager(self):
self.manager.reset_manager(sushy.RESET_MANAGER_GRACEFUL_RESTART)
self.manager._conn.post.assert_called_once_with(
'/redfish/v1/Managers/BMC/Actions/Manager.Reset',
data={'ResetType': 'GracefulRestart'})
def test_reset_manager_with_invalid_value(self):
self.assertRaises(exceptions.InvalidParameterValueError,
self.manager.reset_manager, 'invalid-value')
class ManagerCollectionTestCase(base.TestCase):
def setUp(self):
super(ManagerCollectionTestCase, self).setUp()
self.conn = mock.Mock()
with open('sushy/tests/unit/json_samples/'
'manager_collection.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.managers = manager.ManagerCollection(
self.conn, '/redfish/v1/Managers', redfish_version='1.0.2')
@mock.patch.object(manager, 'Manager', autospec=True)
def test_get_member(self, Manager_mock):
self.managers.get_member('/redfish/v1/Managers/BMC')
Manager_mock.assert_called_once_with(
self.managers._conn, '/redfish/v1/Managers/BMC',
redfish_version=self.managers.redfish_version)
@mock.patch.object(manager, 'Manager', autospec=True)
def test_get_members(self, Manager_mock):
members = self.managers.get_members()
Manager_mock.assert_called_once_with(
self.managers._conn, '/redfish/v1/Managers/BMC',
redfish_version=self.managers.redfish_version)
self.assertIsInstance(members, list)
self.assertEqual(1, len(members))

View File

@ -18,8 +18,8 @@ import json
import mock
from sushy import connector
from sushy import exceptions
from sushy import main
from sushy.resources.manager import manager
from sushy.resources.system import system
from sushy.tests.unit import base
@ -30,12 +30,12 @@ class MainTestCase(base.TestCase):
def setUp(self, mock_connector):
super(MainTestCase, self).setUp()
self.conn = mock.Mock()
mock_connector.return_code = self.conn
mock_connector.return_value = self.conn
with open('sushy/tests/unit/json_samples/root.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.root = main.Sushy(
'http://foo.bar:1234', username='foo', password='bar',
verify=True)
with open('sushy/tests/unit/json_samples/root.json', 'r') as f:
self.root._json = json.loads(f.read())
mock_connector.assert_called_once_with(
'http://foo.bar:1234', 'foo', 'bar', True)
@ -46,17 +46,8 @@ class MainTestCase(base.TestCase):
self.assertEqual('1.0.2', self.root.redfish_version)
self.assertEqual('92384634-2938-2342-8820-489239905423',
self.root.uuid)
def test__get_system_collection_path(self):
self.assertEqual(
'/redfish/v1/Systems', self.root._get_system_collection_path())
def test__get_system_collection_path_missing_systems_attr(self):
self.root._json.pop('Systems')
self.assertRaisesRegex(
exceptions.MissingAttributeError,
'The attribute Systems is missing',
self.root._get_system_collection_path)
self.assertEqual('/redfish/v1/Systems', self.root._systems_path)
self.assertEqual('/redfish/v1/Managers', self.root._managers_path)
@mock.patch.object(system, 'SystemCollection', autospec=True)
def test_get_system_collection(self, mock_system_collection):
@ -71,3 +62,17 @@ class MainTestCase(base.TestCase):
mock_system.assert_called_once_with(
self.root._conn, 'fake-system-id',
redfish_version=self.root.redfish_version)
@mock.patch.object(manager, 'ManagerCollection', autospec=True)
def test_get_manager_collection(self, ManagerCollection_mock):
self.root.get_manager_collection()
ManagerCollection_mock.assert_called_once_with(
self.root._conn, '/redfish/v1/Managers',
redfish_version=self.root.redfish_version)
@mock.patch.object(manager, 'Manager', autospec=True)
def test_get_manager(self, Manager_mock):
self.root.get_manager('fake-manager-id')
Manager_mock.assert_called_once_with(
self.root._conn, 'fake-manager-id',
redfish_version=self.root.redfish_version)