Merge "Add manager resource"
This commit is contained in:
commit
ad0d018fbd
|
@ -9,7 +9,7 @@ Welcome to Sushy's documentation!
|
|||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:maxdepth: 2
|
||||
|
||||
About Sushy <readme>
|
||||
installation
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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"""
|
|
@ -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)
|
|
@ -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))
|
|
@ -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):
|
||||
|
|
|
@ -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."
|
||||
}
|
|
@ -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."
|
||||
}
|
|
@ -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))
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue