Add `ChassisCollection` and `Chassis` classes
Add representation of Chassis and ChassisCollection resources. The Chassis is used to represent a chassis or other physical enclosure as a Redfish resource. Also adds the methods get_chassis_collection and get_chassis in the public API. Implements: ChassisCollection and Chassis classes Story: #2003853 Task: #26647 Change-Id: I59083562ff2ab3b18bfeebdabc0f4cfd663d01bb
This commit is contained in:
parent
0480def823
commit
c5d13e4385
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for the Chassis resource to the library.
|
||||
|
|
@ -20,6 +20,7 @@ from sushy.main import Sushy
|
|||
from sushy.resources.constants import * # noqa
|
||||
from sushy.resources.system.constants import * # noqa
|
||||
from sushy.resources.manager.constants import * # noqa
|
||||
from sushy.resources.chassis.constants import * # noqa
|
||||
|
||||
__all__ = ('Sushy',)
|
||||
__version__ = pbr.version.VersionInfo(
|
||||
|
|
|
@ -18,6 +18,7 @@ from sushy import auth as sushy_auth
|
|||
from sushy import connector as sushy_connector
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources.chassis import chassis
|
||||
from sushy.resources.manager import manager
|
||||
from sushy.resources.registry import message_registry_file
|
||||
from sushy.resources.sessionservice import session
|
||||
|
@ -69,6 +70,9 @@ class Sushy(base.ResourceBase):
|
|||
_managers_path = base.Field(['Managers', '@odata.id'])
|
||||
"""ManagerCollection path"""
|
||||
|
||||
_chassis_path = base.Field(['Chassis', '@odata.id'])
|
||||
"""ChassisCollection path"""
|
||||
|
||||
_session_service_path = base.Field(['SessionService', '@odata.id'])
|
||||
"""SessionService path"""
|
||||
|
||||
|
@ -141,6 +145,29 @@ class Sushy(base.ResourceBase):
|
|||
return system.System(self._conn, identity,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def get_chassis_collection(self):
|
||||
"""Get the ChassisCollection object
|
||||
|
||||
:raises: MissingAttributeError, if the collection attribute is
|
||||
not found
|
||||
:returns: a ChassisCollection object
|
||||
"""
|
||||
if not self._chassis_path:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='Chassis/@odata.id', resource=self._path)
|
||||
|
||||
return chassis.ChassisCollection(self._conn, self._chassis_path,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def get_chassis(self, identity):
|
||||
"""Given the identity return a Chassis object
|
||||
|
||||
:param identity: The identity of the Chassis resource
|
||||
:returns: The Chassis object
|
||||
"""
|
||||
return chassis.Chassis(self._conn, identity,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def get_manager_collection(self):
|
||||
"""Get the ManagerCollection object
|
||||
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
# 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/Chassis.v1_8_0.json
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources.chassis import mappings as cha_maps
|
||||
from sushy.resources import common
|
||||
from sushy.resources import mappings as res_maps
|
||||
|
||||
import logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ActionsField(base.CompositeField):
|
||||
reset = common.ResetActionField('#Chassis.Reset')
|
||||
|
||||
|
||||
class PhysicalSecurity(base.CompositeField):
|
||||
intrusion_sensor = base.MappedField('IntrusionSensor',
|
||||
cha_maps.CHASSIS_INTRUSION_SENSOR_MAP)
|
||||
"""IntrusionSensor
|
||||
This indicates the known state of the physical security sensor, such as if
|
||||
it is hardware intrusion detected.
|
||||
"""
|
||||
|
||||
intrusion_sensor_number = base.Field('IntrusionSensorNumber')
|
||||
"""A numerical identifier to represent the physical security sensor"""
|
||||
|
||||
intrusion_sensor_re_arm = (
|
||||
base.MappedField('IntrusionSensorReArm',
|
||||
cha_maps.CHASSIS_INTRUSION_SENSOR_RE_ARM_MAP))
|
||||
"""This indicates how the Normal state to be restored"""
|
||||
|
||||
|
||||
class Chassis(base.ResourceBase):
|
||||
"""Chassis resource
|
||||
|
||||
The Chassis represents the physical components of a system. This
|
||||
resource represents the sheet-metal confined spaces and logical zones
|
||||
such as racks, enclosures, chassis and all other containers.
|
||||
"""
|
||||
|
||||
chassis_type = base.MappedField('ChassisType',
|
||||
cha_maps.CHASSIS_TYPE_VALUE_MAP,
|
||||
required=True)
|
||||
"""The type of physical form factor of the chassis"""
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""Identifier for the chassis"""
|
||||
|
||||
name = base.Field('Name', required=True)
|
||||
"""The chassis name"""
|
||||
|
||||
asset_tag = base.Field('AssetTag')
|
||||
"""The user assigned asset tag of this chassis"""
|
||||
|
||||
depth_mm = base.Field('DepthMm')
|
||||
"""Depth in millimeters
|
||||
The depth of the chassis. The value of this property shall represent
|
||||
the depth (length) of the chassis (in millimeters) as specified by the
|
||||
manufacturer.
|
||||
"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The chassis description"""
|
||||
|
||||
height_mm = base.Field('HeightMm')
|
||||
"""Height in millimeters
|
||||
The height of the chassis. The value of this property shall represent
|
||||
the height of the chassis (in millimeters) as specified by the
|
||||
manufacturer.
|
||||
"""
|
||||
|
||||
indicator_led = base.MappedField('IndicatorLED',
|
||||
res_maps.INDICATOR_LED_VALUE_MAP)
|
||||
"""The state of the indicator LED, used to identify the chassis"""
|
||||
|
||||
manufacturer = base.Field('Manufacturer')
|
||||
"""The manufacturer of this chassis"""
|
||||
|
||||
model = base.Field('Model')
|
||||
"""The model number of the chassis"""
|
||||
|
||||
part_number = base.Field('PartNumber')
|
||||
"""The part number of the chassis"""
|
||||
|
||||
physical_security = PhysicalSecurity('PhysicalSecurity')
|
||||
"""PhysicalSecurity
|
||||
This value of this property shall contain the sensor state of the physical
|
||||
security.
|
||||
"""
|
||||
|
||||
power_state = base.MappedField('PowerState',
|
||||
res_maps.POWER_STATE_VALUE_MAP)
|
||||
"""The current power state of the chassis"""
|
||||
|
||||
serial_number = base.Field('SerialNumber')
|
||||
"""The serial number of the chassis"""
|
||||
|
||||
sku = base.Field('SKU')
|
||||
"""Stock-keeping unit number (SKU)
|
||||
The value of this property shall be the stock-keeping unit number for
|
||||
this chassis.
|
||||
"""
|
||||
|
||||
status = common.StatusField('Status')
|
||||
"""Status and Health
|
||||
This property describes the status and health of the chassis and its
|
||||
children.
|
||||
"""
|
||||
|
||||
uuid = base.Field('UUID')
|
||||
"""The Universal Unique Identifier (UUID) for this Chassis."""
|
||||
|
||||
weight_kg = base.Field('WeightKg')
|
||||
"""Weight in kilograms
|
||||
The value of this property shall represent the published mass (commonly
|
||||
referred to as weight) of the chassis (in kilograms).
|
||||
"""
|
||||
|
||||
width_mm = base.Field('WidthMm')
|
||||
"""Width in millimeters
|
||||
The value of this property shall represent the width of the chassis
|
||||
(in millimeters) as specified by the manufacturer.
|
||||
"""
|
||||
|
||||
_actions = ActionsField('Actions')
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a Chassis
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the Chassis resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(Chassis, self).__init__(connector, identity, redfish_version)
|
||||
|
||||
def _get_reset_action_element(self):
|
||||
reset_action = self._actions.reset
|
||||
|
||||
if not reset_action:
|
||||
raise exceptions.MissingActionError(action='#Chassis.Reset',
|
||||
resource=self._path)
|
||||
return reset_action
|
||||
|
||||
def get_allowed_reset_chassis_values(self):
|
||||
"""Get the allowed values for resetting the chassis.
|
||||
|
||||
:returns: A set of allowed values.
|
||||
:raises: MissingAttributeError, if Actions/#Chassis.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 chassis action for Chassis %s', self.identity)
|
||||
return set(res_maps.RESET_TYPE_VALUE_MAP_REV)
|
||||
|
||||
return set([res_maps.RESET_TYPE_VALUE_MAP[v] for v in
|
||||
set(res_maps.RESET_TYPE_VALUE_MAP).
|
||||
intersection(reset_action.allowed_values)])
|
||||
|
||||
def reset_chassis(self, value):
|
||||
"""Reset the chassis.
|
||||
|
||||
:param value: The target value.
|
||||
:raises: InvalidParameterValueError, if the target value is not
|
||||
allowed.
|
||||
"""
|
||||
valid_resets = self.get_allowed_reset_chassis_values()
|
||||
if value not in valid_resets:
|
||||
raise exceptions.InvalidParameterValueError(
|
||||
parameter='value', value=value, valid_values=valid_resets)
|
||||
|
||||
value = res_maps.RESET_TYPE_VALUE_MAP_REV[value]
|
||||
target_uri = self._get_reset_action_element().target_uri
|
||||
|
||||
LOG.debug('Resetting the Chassis %s ...', self.identity)
|
||||
self._conn.post(target_uri, data={'ResetType': value})
|
||||
LOG.info('The Chassis %s is being reset', self.identity)
|
||||
|
||||
|
||||
class ChassisCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return Chassis
|
||||
|
||||
def __init__(self, connector, path, redfish_version=None):
|
||||
"""A class representing a ChassisCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: The canonical path to the Chassis collection resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(ChassisCollection, self).__init__(connector, path,
|
||||
redfish_version)
|
|
@ -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.
|
||||
|
||||
# Values comes from the Redfish Chassis json-schema 1.8.0:
|
||||
# http://redfish.dmtf.org/schemas/v1/Chassis.v1_8_0.json#/definitions/Chassis
|
||||
|
||||
# Chassis Types constants
|
||||
|
||||
CHASSIS_TYPE_RACK = 'rack chassis type'
|
||||
"""An equipment rack, typically a 19-inch wide freestanding unit"""
|
||||
|
||||
CHASSIS_TYPE_BLADE = 'blade chassis type'
|
||||
"""Blade
|
||||
|
||||
An enclosed or semi-enclosed, typically vertically-oriented, system
|
||||
chassis which must be plugged into a multi-system chassis to function
|
||||
normally.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_ENCLOSURE = 'enclosure chassis type'
|
||||
"""A generic term for a chassis that does not fit any other description"""
|
||||
|
||||
CHASSIS_TYPE_STAND_ALONE = 'stand alone chassis type'
|
||||
"""StandAlone
|
||||
|
||||
A single, free-standing system, commonly called a tower or desktop
|
||||
chassis.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_RACK_MOUNT = 'rack mount chassis type'
|
||||
"""RackMount
|
||||
|
||||
A single system chassis designed specifically for mounting in an
|
||||
equipment rack.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_CARD = 'card chassis type'
|
||||
"""Card
|
||||
|
||||
A loose device or circuit board intended to be installed in a system or
|
||||
other enclosure.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_CARTRIDGE = 'cartridge chassis type'
|
||||
"""Cartridge
|
||||
|
||||
A small self-contained system intended to be plugged into a multi-system
|
||||
chassis"""
|
||||
|
||||
CHASSIS_TYPE_ROW = 'row chassis type'
|
||||
"""A collection of equipment rack"""
|
||||
|
||||
CHASSIS_TYPE_POD = 'pod chassis type'
|
||||
"""Pod
|
||||
|
||||
A collection of equipment racks in a large, likely transportable,
|
||||
container"""
|
||||
|
||||
CHASSIS_TYPE_EXPANSION = 'expansion chassis type'
|
||||
"""A chassis which expands the capabilities or capacity of another chassis"""
|
||||
|
||||
CHASSIS_TYPE_SIDECAR = 'sidecar chassis type'
|
||||
"""Sidecar
|
||||
|
||||
A chassis that mates mechanically with another chassis to expand its
|
||||
capabilities or capacity.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_ZONE = 'zone chassis type'
|
||||
"""Zone
|
||||
|
||||
A logical division or portion of a physical chassis that contains multiple
|
||||
devices or systems that cannot be physically separated.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_SLED = 'sled chassis type'
|
||||
"""Sled
|
||||
|
||||
An enclosed or semi-enclosed, system chassis which must be plugged into a
|
||||
multi-system chassis to function normally similar to a blade type chassis.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_SHELF = 'shelf chassis type'
|
||||
"""Shelf
|
||||
|
||||
An enclosed or semi-enclosed, typically horizontally-oriented, system chassis
|
||||
which must be plugged into a multi-system chassis to function
|
||||
normally.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_DRAWER = 'drawer chassis type'
|
||||
"""Drawer
|
||||
|
||||
An enclosed or semi-enclosed, typically horizontally-oriented, system
|
||||
chassis which may be slid into a multi-system chassis.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_MODULE = 'module chassis type'
|
||||
"""Module
|
||||
|
||||
A small, typically removable, chassis or card which contains devices for
|
||||
a particular subsystem or function.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_COMPONENT = 'component chassis type'
|
||||
"""Component
|
||||
|
||||
A small chassis, card, or device which contains devices for a particular
|
||||
subsystem or function.
|
||||
"""
|
||||
|
||||
CHASSIS_TYPE_IP_BASED_DRIVE = 'IP based drive chassis type'
|
||||
"""A chassis in a drive form factor with IP-based network connections"""
|
||||
|
||||
CHASSIS_TYPE_RACK_GROUP = 'rack group chassis type'
|
||||
"""A group of racks which form a single entity or share infrastructure"""
|
||||
|
||||
CHASSIS_TYPE_STORAGE_ENCLOSURE = 'storage enclosure chassis type'
|
||||
"""A chassis which encloses storage"""
|
||||
|
||||
CHASSIS_TYPE_OTHER = 'other chassis type'
|
||||
"""A chassis that does not fit any of these definitions"""
|
||||
|
||||
# Chassis IntrusionSensor constants
|
||||
|
||||
CHASSIS_INTRUSION_SENSOR_NORMAL = 'normal chassis intrusion sensor'
|
||||
"""No abnormal physical security conditions are detected at this time"""
|
||||
|
||||
CHASSIS_INTRUSION_SENSOR_HARDWARE_INTRUSION = 'hardware intrusion chassis ' \
|
||||
'intrusion sensor'
|
||||
"""HardwareIntrusion
|
||||
|
||||
A door, lock, or other mechanism protecting the internal system hardware from
|
||||
being accessed is detected as being in an insecure state.
|
||||
"""
|
||||
|
||||
CHASSIS_INTRUSION_SENSOR_TAMPERING_DETECTED = 'tampering detected chassis ' \
|
||||
'intrusion sensor'
|
||||
"""Physical tampering of the monitored entity is detected"""
|
||||
|
||||
# Chassis IntrusionSensorReArm constants
|
||||
|
||||
CHASSIS_INTRUSION_SENSOR_RE_ARM_MANUAL = 'manual re arm chassis intrusion ' \
|
||||
'sensor'
|
||||
"""This sensor would be restored to the Normal state by a manual re-arm"""
|
||||
|
||||
CHASSIS_INTRUSION_SENSOR_RE_ARM_AUTOMATIC = 'automatic re arm chassis ' \
|
||||
'intrusion sensor'
|
||||
"""Automatic
|
||||
|
||||
This sensor would be restored to the Normal state automatically as no abnormal
|
||||
physical security conditions are detected.
|
||||
"""
|
|
@ -0,0 +1,48 @@
|
|||
# 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.chassis import constants as cha_cons
|
||||
|
||||
CHASSIS_TYPE_VALUE_MAP = {
|
||||
'Rack': cha_cons.CHASSIS_TYPE_RACK,
|
||||
'Blade': cha_cons.CHASSIS_TYPE_BLADE,
|
||||
'Enclosure': cha_cons.CHASSIS_TYPE_ENCLOSURE,
|
||||
'StandAlone': cha_cons.CHASSIS_TYPE_STAND_ALONE,
|
||||
'RackMount': cha_cons.CHASSIS_TYPE_RACK_MOUNT,
|
||||
'Card': cha_cons.CHASSIS_TYPE_CARD,
|
||||
'Cartridge': cha_cons.CHASSIS_TYPE_CARTRIDGE,
|
||||
'Row': cha_cons.CHASSIS_TYPE_ROW,
|
||||
'Pod': cha_cons.CHASSIS_TYPE_POD,
|
||||
'Expansion': cha_cons.CHASSIS_TYPE_EXPANSION,
|
||||
'Sidecar': cha_cons.CHASSIS_TYPE_SIDECAR,
|
||||
'Zone': cha_cons.CHASSIS_TYPE_ZONE,
|
||||
'Sled': cha_cons.CHASSIS_TYPE_SLED,
|
||||
'Shelf': cha_cons.CHASSIS_TYPE_SHELF,
|
||||
'Drawer': cha_cons.CHASSIS_TYPE_DRAWER,
|
||||
'Module': cha_cons.CHASSIS_TYPE_MODULE,
|
||||
'Component': cha_cons.CHASSIS_TYPE_COMPONENT,
|
||||
'IPBasedDrive': cha_cons.CHASSIS_TYPE_IP_BASED_DRIVE,
|
||||
'RackGroup': cha_cons.CHASSIS_TYPE_RACK_GROUP,
|
||||
'StorageEnclosure': cha_cons.CHASSIS_TYPE_STORAGE_ENCLOSURE,
|
||||
'Other': cha_cons.CHASSIS_TYPE_OTHER,
|
||||
}
|
||||
|
||||
CHASSIS_INTRUSION_SENSOR_MAP = {
|
||||
'Normal': cha_cons.CHASSIS_INTRUSION_SENSOR_NORMAL,
|
||||
'HardwareIntrusion': cha_cons.CHASSIS_INTRUSION_SENSOR_HARDWARE_INTRUSION,
|
||||
'TamperingDetected': cha_cons.CHASSIS_INTRUSION_SENSOR_TAMPERING_DETECTED,
|
||||
}
|
||||
|
||||
CHASSIS_INTRUSION_SENSOR_RE_ARM_MAP = {
|
||||
'Manual': cha_cons.CHASSIS_INTRUSION_SENSOR_RE_ARM_MANUAL,
|
||||
'Automatic': cha_cons.CHASSIS_INTRUSION_SENSOR_RE_ARM_AUTOMATIC,
|
||||
}
|
|
@ -40,3 +40,64 @@ PARAMTYPE_NUMBER = 'number'
|
|||
SEVERITY_OK = 'ok'
|
||||
SEVERITY_WARNING = 'warning'
|
||||
SEVERITY_CRITICAL = 'critical'
|
||||
|
||||
# Indicator LED Constants
|
||||
|
||||
INDICATOR_LED_LIT = 'indicator led lit'
|
||||
"""The Indicator LED is lit"""
|
||||
|
||||
INDICATOR_LED_BLINKING = 'indicator led blinking'
|
||||
"""The Indicator LED is blinking"""
|
||||
|
||||
INDICATOR_LED_OFF = 'indicator led off'
|
||||
"""The Indicator LED is off"""
|
||||
|
||||
INDICATOR_LED_UNKNOWN = 'indicator led unknown'
|
||||
"""The state of the Indicator LED cannot be determine"""
|
||||
|
||||
# System' PowerState constants
|
||||
|
||||
POWER_STATE_ON = 'on'
|
||||
"""The resource is powered on"""
|
||||
|
||||
POWER_STATE_OFF = 'off'
|
||||
"""The resource is powered off, although some components may continue to
|
||||
have AUX power such as management controller"""
|
||||
|
||||
POWER_STATE_POWERING_ON = 'powering on'
|
||||
"""A temporary state between Off and On. This temporary state can
|
||||
be very short"""
|
||||
|
||||
POWER_STATE_POWERING_OFF = 'powering off'
|
||||
"""A temporary state between On and Off. The power off action can take
|
||||
time while the OS is in the shutdown process"""
|
||||
|
||||
# Reset action constants
|
||||
|
||||
RESET_TYPE_ON = 'on'
|
||||
"""Turn the unit on"""
|
||||
|
||||
RESET_TYPE_FORCE_ON = 'force on'
|
||||
"""Turn the unit on immediately"""
|
||||
|
||||
RESET_TYPE_FORCE_OFF = 'force off'
|
||||
"""Turn the unit off immediately (non-graceful shutdown)"""
|
||||
|
||||
RESET_TYPE_GRACEFUL_SHUTDOWN = 'graceful shutdown'
|
||||
"""Perform a graceful shutdown and power off"""
|
||||
|
||||
RESET_TYPE_GRACEFUL_RESTART = 'graceful restart'
|
||||
"""Perform a graceful shutdown followed by a restart of the system"""
|
||||
|
||||
RESET_TYPE_FORCE_RESTART = 'force restart'
|
||||
"""Perform an immediate (non-graceful) shutdown, followed by a restart"""
|
||||
|
||||
RESET_TYPE_NMI = 'nmi'
|
||||
"""Generate a Diagnostic Interrupt (usually an NMI on x86 systems) to cease
|
||||
normal operations, perform diagnostic actions and typically halt the system"""
|
||||
|
||||
RESET_TYPE_PUSH_POWER_BUTTON = 'push power button'
|
||||
"""Simulate the pressing of the physical power button on this unit"""
|
||||
|
||||
RESET_TYPE_POWER_CYCLE = 'power cycle'
|
||||
"""Perform a power cycle of the unit"""
|
||||
|
|
|
@ -13,10 +13,15 @@
|
|||
# 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
|
||||
|
||||
from sushy.resources import constants as res_cons
|
||||
|
||||
# Manager Reset action constants
|
||||
|
||||
RESET_MANAGER_GRACEFUL_RESTART = 'graceful restart'
|
||||
RESET_MANAGER_FORCE_RESTART = 'force restart'
|
||||
RESET_MANAGER_GRACEFUL_RESTART = res_cons.RESET_TYPE_GRACEFUL_RESTART
|
||||
"""Perform a graceful shutdown followed by a restart of the system"""
|
||||
|
||||
RESET_MANAGER_FORCE_RESTART = res_cons.RESET_TYPE_FORCE_RESTART
|
||||
"""Perform an immediate (non-graceful) shutdown, followed by a restart"""
|
||||
|
||||
# Manager Type constants
|
||||
|
||||
|
|
|
@ -45,3 +45,33 @@ SEVERITY_VALUE_MAP = {
|
|||
'Warning': res_cons.SEVERITY_WARNING,
|
||||
'Critical': res_cons.SEVERITY_CRITICAL
|
||||
}
|
||||
|
||||
INDICATOR_LED_VALUE_MAP = {
|
||||
'Lit': res_cons.INDICATOR_LED_LIT,
|
||||
'Blinking': res_cons.INDICATOR_LED_BLINKING,
|
||||
'Off': res_cons.INDICATOR_LED_OFF,
|
||||
'Unknown': res_cons.INDICATOR_LED_UNKNOWN,
|
||||
}
|
||||
|
||||
POWER_STATE_VALUE_MAP = {
|
||||
'On': res_cons.POWER_STATE_ON,
|
||||
'Off': res_cons.POWER_STATE_OFF,
|
||||
'PoweringOn': res_cons.POWER_STATE_POWERING_ON,
|
||||
'PoweringOff': res_cons.POWER_STATE_POWERING_OFF,
|
||||
}
|
||||
|
||||
POWER_STATE_MAP_REV = utils.revert_dictionary(POWER_STATE_VALUE_MAP)
|
||||
|
||||
RESET_TYPE_VALUE_MAP = {
|
||||
'On': res_cons.RESET_TYPE_ON,
|
||||
'ForceOff': res_cons.RESET_TYPE_FORCE_OFF,
|
||||
'GracefulShutdown': res_cons.RESET_TYPE_GRACEFUL_SHUTDOWN,
|
||||
'GracefulRestart': res_cons.RESET_TYPE_GRACEFUL_RESTART,
|
||||
'ForceRestart': res_cons.RESET_TYPE_FORCE_RESTART,
|
||||
'Nmi': res_cons.RESET_TYPE_NMI,
|
||||
'ForceOn': res_cons.RESET_TYPE_FORCE_ON,
|
||||
'PushPowerButton': res_cons.RESET_TYPE_PUSH_POWER_BUTTON,
|
||||
'PowerCycle': res_cons.RESET_TYPE_POWER_CYCLE,
|
||||
}
|
||||
|
||||
RESET_TYPE_VALUE_MAP_REV = utils.revert_dictionary(RESET_TYPE_VALUE_MAP)
|
||||
|
|
|
@ -16,46 +16,48 @@
|
|||
# Values comes from the Redfish System json-schema 1.0.0:
|
||||
# http://redfish.dmtf.org/schemas/v1/ComputerSystem.v1_0_0.json#/definitions/ComputerSystem # noqa
|
||||
|
||||
from sushy.resources import constants as res_cons
|
||||
|
||||
# Reset action constants
|
||||
|
||||
RESET_ON = 'on'
|
||||
RESET_FORCE_OFF = 'force off'
|
||||
RESET_GRACEFUL_SHUTDOWN = 'graceful shutdown'
|
||||
RESET_GRACEFUL_RESTART = 'graceful restart'
|
||||
RESET_FORCE_RESTART = 'force restart'
|
||||
RESET_NMI = 'nmi'
|
||||
RESET_FORCE_ON = 'force on'
|
||||
RESET_PUSH_POWER_BUTTON = 'push power button'
|
||||
RESET_ON = res_cons.RESET_TYPE_ON
|
||||
RESET_FORCE_OFF = res_cons.RESET_TYPE_FORCE_OFF
|
||||
RESET_GRACEFUL_SHUTDOWN = res_cons.RESET_TYPE_GRACEFUL_SHUTDOWN
|
||||
RESET_GRACEFUL_RESTART = res_cons.RESET_TYPE_GRACEFUL_RESTART
|
||||
RESET_FORCE_RESTART = res_cons.RESET_TYPE_FORCE_RESTART
|
||||
RESET_NMI = res_cons.RESET_TYPE_NMI
|
||||
RESET_FORCE_ON = res_cons.RESET_TYPE_FORCE_ON
|
||||
RESET_PUSH_POWER_BUTTON = res_cons.RESET_TYPE_PUSH_POWER_BUTTON
|
||||
|
||||
# System' PowerState constants
|
||||
|
||||
SYSTEM_POWER_STATE_ON = 'on'
|
||||
SYSTEM_POWER_STATE_ON = res_cons.POWER_STATE_ON
|
||||
"""The system is powered on"""
|
||||
|
||||
SYSTEM_POWER_STATE_OFF = 'off'
|
||||
SYSTEM_POWER_STATE_OFF = res_cons.POWER_STATE_OFF
|
||||
"""The system is powered off, although some components may continue to
|
||||
have AUX power such as management controller"""
|
||||
|
||||
SYSTEM_POWER_STATE_POWERING_ON = 'powering on'
|
||||
SYSTEM_POWER_STATE_POWERING_ON = res_cons.POWER_STATE_POWERING_ON
|
||||
"""A temporary state between Off and On. This temporary state can
|
||||
be very short"""
|
||||
|
||||
SYSTEM_POWER_STATE_POWERING_OFF = 'powering off'
|
||||
SYSTEM_POWER_STATE_POWERING_OFF = res_cons.POWER_STATE_POWERING_OFF
|
||||
"""A temporary state between On and Off. The power off action can take
|
||||
time while the OS is in the shutdown process"""
|
||||
|
||||
# Indicator LED Constants
|
||||
|
||||
SYSTEM_INDICATOR_LED_LIT = 'Lit'
|
||||
SYSTEM_INDICATOR_LED_LIT = res_cons.INDICATOR_LED_LIT
|
||||
"""The Indicator LED is lit"""
|
||||
|
||||
SYSTEM_INDICATOR_LED_BLINKING = 'Blinking'
|
||||
SYSTEM_INDICATOR_LED_BLINKING = res_cons.INDICATOR_LED_BLINKING
|
||||
"""The Indicator LED is blinking"""
|
||||
|
||||
SYSTEM_INDICATOR_LED_OFF = 'Off'
|
||||
SYSTEM_INDICATOR_LED_OFF = res_cons.INDICATOR_LED_OFF
|
||||
"""The Indicator LED is off"""
|
||||
|
||||
SYSTEM_INDICATOR_LED_UNKNOWN = 'Unknown'
|
||||
SYSTEM_INDICATOR_LED_UNKNOWN = res_cons.INDICATOR_LED_UNKNOWN
|
||||
"""The state of the Indicator LED cannot be determine"""
|
||||
|
||||
# Boot source target constants
|
||||
|
|
|
@ -30,22 +30,6 @@ RESET_SYSTEM_VALUE_MAP = {
|
|||
|
||||
RESET_SYSTEM_VALUE_MAP_REV = utils.revert_dictionary(RESET_SYSTEM_VALUE_MAP)
|
||||
|
||||
SYSTEM_POWER_STATE_MAP = {
|
||||
'On': sys_cons.SYSTEM_POWER_STATE_ON,
|
||||
'Off': sys_cons.SYSTEM_POWER_STATE_OFF,
|
||||
'PoweringOn': sys_cons.SYSTEM_POWER_STATE_POWERING_ON,
|
||||
'PoweringOff': sys_cons.SYSTEM_POWER_STATE_POWERING_OFF,
|
||||
}
|
||||
|
||||
SYSTEM_POWER_STATE_MAP_REV = utils.revert_dictionary(SYSTEM_POWER_STATE_MAP)
|
||||
|
||||
SYSTEM_INDICATOR_LED_MAP = {
|
||||
'Lit': sys_cons.SYSTEM_INDICATOR_LED_LIT,
|
||||
'Blinking': sys_cons.SYSTEM_INDICATOR_LED_BLINKING,
|
||||
'Off': sys_cons.SYSTEM_INDICATOR_LED_OFF,
|
||||
'Unknown': sys_cons.SYSTEM_INDICATOR_LED_UNKNOWN,
|
||||
}
|
||||
|
||||
BOOT_SOURCE_TARGET_MAP = {
|
||||
'None': sys_cons.BOOT_SOURCE_TARGET_NONE,
|
||||
'Pxe': sys_cons.BOOT_SOURCE_TARGET_PXE,
|
||||
|
|
|
@ -18,6 +18,7 @@ import logging
|
|||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
from sushy.resources import mappings as res_maps
|
||||
from sushy.resources.system import bios
|
||||
from sushy.resources.system import constants as sys_cons
|
||||
from sushy.resources.system import ethernet_interface
|
||||
|
@ -86,7 +87,7 @@ class System(base.ResourceBase):
|
|||
"""The system identity string"""
|
||||
|
||||
indicator_led = base.MappedField('IndicatorLED',
|
||||
sys_maps.SYSTEM_INDICATOR_LED_MAP)
|
||||
res_maps.INDICATOR_LED_VALUE_MAP)
|
||||
"""Whether the indicator LED is lit or off"""
|
||||
|
||||
manufacturer = base.Field('Manufacturer')
|
||||
|
@ -99,7 +100,7 @@ class System(base.ResourceBase):
|
|||
"""The system part number"""
|
||||
|
||||
power_state = base.MappedField('PowerState',
|
||||
sys_maps.SYSTEM_POWER_STATE_MAP)
|
||||
res_maps.POWER_STATE_VALUE_MAP)
|
||||
"""The system power state"""
|
||||
|
||||
serial_number = base.Field('SerialNumber')
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
{
|
||||
"@odata.type": "#Chassis.v1_8_0.Chassis",
|
||||
"Id": "Blade1",
|
||||
"Name": "Blade",
|
||||
"Description": "Test description",
|
||||
"ChassisType": "Blade",
|
||||
"AssetTag": "45Z-2381",
|
||||
"Manufacturer": "Contoso",
|
||||
"Model": "SX1000",
|
||||
"SKU": "6914260",
|
||||
"SerialNumber": "529QB9450R6",
|
||||
"PartNumber": "166480-S23",
|
||||
"UUID": "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF",
|
||||
"PowerState": "On",
|
||||
"IndicatorLED": "Off",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"HeightMm": 44.45,
|
||||
"WidthMm": 431.8,
|
||||
"DepthMm": 711,
|
||||
"WeightKg": 15.31,
|
||||
"Location": {
|
||||
"PartLocation": {
|
||||
"ServiceLabel": "Blade 1",
|
||||
"LocationType": "Slot",
|
||||
"LocationOrdinalValue": 0,
|
||||
"Reference": "Front",
|
||||
"Orientation": "LeftToRight"
|
||||
}
|
||||
},
|
||||
"PhysicalSecurity": {
|
||||
"IntrusionSensor": "Normal",
|
||||
"IntrusionSensorNumber": 123,
|
||||
"IntrusionSensorReArm": "Manual"
|
||||
},
|
||||
"Thermal": {
|
||||
"@odata.id": "/redfish/v1/Chassis/Blade1/Thermal"
|
||||
},
|
||||
"Links": {
|
||||
"ComputerSystems": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/529QB9450R6"
|
||||
}
|
||||
],
|
||||
"ManagedBy": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Managers/Blade1BMC"
|
||||
}
|
||||
],
|
||||
"ContainedBy": {
|
||||
"@odata.id": "/redfish/v1/Chassis/MultiBladeEncl"
|
||||
},
|
||||
"CooledBy": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/MultiBladeEncl/Thermal#/Fans/0"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/MultiBladeEncl/Thermal#/Fans/1"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/MultiBladeEncl/Thermal#/Fans/2"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/MultiBladeEncl/Thermal#/Fans/3"
|
||||
}
|
||||
],
|
||||
"PoweredBy": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/MultiBladeEncl/Power#/PowerSupplies/0"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/MultiBladeEncl/Power#/PowerSupplies/1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Actions": {
|
||||
"#Chassis.Reset": {
|
||||
"target": "/redfish/v1/Chassis/Blade1/Actions/Chassis.Reset",
|
||||
"ResetType@Redfish.AllowableValues": [
|
||||
"ForceRestart",
|
||||
"GracefulRestart",
|
||||
"On",
|
||||
"ForceOff",
|
||||
"GracefulShutdown",
|
||||
"Nmi",
|
||||
"ForceOn",
|
||||
"PushPowerButton",
|
||||
"PowerCycle"
|
||||
]
|
||||
},
|
||||
"Oem": {}
|
||||
},
|
||||
"@odata.context": "/redfish/v1/$metadata#Chassis.Chassis",
|
||||
"@odata.id": "/redfish/v1/Chassis/Blade1",
|
||||
"@Redfish.Copyright": "Copyright 2014-2017 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"@odata.type": "#ChassisCollection.ChassisCollection",
|
||||
"Name": "Chassis Collection",
|
||||
"Members@odata.count": 5,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/MultiBladeEncl"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/Blade1"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/Blade2"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/Blade3"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/Blade4"
|
||||
}
|
||||
],
|
||||
"@odata.context": "/redfish/v1/$metadata#ChassisCollection.ChassisCollection",
|
||||
"@odata.id": "/redfish/v1/Chassis",
|
||||
"@Redfish.Copyright": "Copyright 2014-2017 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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.chassis import chassis
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class ChassisTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ChassisTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/chassis.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.chassis = chassis.Chassis(self.conn, '/redfish/v1/Chassis/Blade1',
|
||||
redfish_version='1.8.0')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
# | WHEN |
|
||||
self.chassis._parse_attributes()
|
||||
# | THEN |
|
||||
self.assertEqual('1.8.0', self.chassis.redfish_version)
|
||||
self.assertEqual('Blade1', self.chassis.identity)
|
||||
self.assertEqual('Blade', self.chassis.name)
|
||||
self.assertEqual('Test description', self.chassis.description)
|
||||
self.assertEqual('45Z-2381', self.chassis.asset_tag)
|
||||
self.assertEqual(sushy.CHASSIS_TYPE_BLADE,
|
||||
self.chassis.chassis_type)
|
||||
self.assertEqual('Contoso', self.chassis.manufacturer)
|
||||
self.assertEqual('SX1000', self.chassis.model)
|
||||
self.assertEqual('529QB9450R6', self.chassis.serial_number)
|
||||
self.assertEqual('6914260', self.chassis.sku)
|
||||
self.assertEqual('166480-S23', self.chassis.part_number)
|
||||
self.assertEqual('FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF',
|
||||
self.chassis.uuid)
|
||||
self.assertEqual(sushy.INDICATOR_LED_OFF,
|
||||
self.chassis.indicator_led)
|
||||
self.assertEqual(sushy.POWER_STATE_ON,
|
||||
self.chassis.power_state)
|
||||
self.assertEqual(sushy.STATE_ENABLED, self.chassis.status.state)
|
||||
self.assertEqual(44.45, self.chassis.height_mm)
|
||||
self.assertEqual(431.8, self.chassis.width_mm)
|
||||
self.assertEqual(711, self.chassis.depth_mm)
|
||||
self.assertEqual(15.31, self.chassis.weight_kg)
|
||||
self.assertEqual(sushy.HEALTH_OK, self.chassis.status.health)
|
||||
self.assertEqual(sushy.CHASSIS_INTRUSION_SENSOR_NORMAL,
|
||||
self.chassis.physical_security.intrusion_sensor)
|
||||
self.assertEqual(123,
|
||||
self.chassis.physical_security.intrusion_sensor_number
|
||||
)
|
||||
self.assertEqual(sushy.CHASSIS_INTRUSION_SENSOR_RE_ARM_MANUAL,
|
||||
self.chassis.physical_security.intrusion_sensor_re_arm
|
||||
)
|
||||
|
||||
def test_get_allowed_reset_chasis_values(self):
|
||||
# | GIVEN |
|
||||
expected = {sushy.RESET_TYPE_POWER_CYCLE,
|
||||
sushy.RESET_TYPE_PUSH_POWER_BUTTON,
|
||||
sushy.RESET_TYPE_FORCE_ON, sushy.RESET_TYPE_NMI,
|
||||
sushy.RESET_TYPE_FORCE_RESTART,
|
||||
sushy.RESET_TYPE_GRACEFUL_RESTART, sushy.RESET_TYPE_ON,
|
||||
sushy.RESET_TYPE_FORCE_OFF,
|
||||
sushy.RESET_TYPE_GRACEFUL_SHUTDOWN}
|
||||
# | WHEN |
|
||||
values = self.chassis.get_allowed_reset_chassis_values()
|
||||
# | THEN |
|
||||
self.assertEqual(expected, values)
|
||||
self.assertIsInstance(values, set)
|
||||
|
||||
def test_get_allowed_reset_chassis_values_for_no_values_set(self):
|
||||
# | GIVEN |
|
||||
self.chassis._actions.reset.allowed_values = []
|
||||
expected = {sushy.RESET_TYPE_POWER_CYCLE,
|
||||
sushy.RESET_TYPE_PUSH_POWER_BUTTON,
|
||||
sushy.RESET_TYPE_FORCE_ON, sushy.RESET_TYPE_NMI,
|
||||
sushy.RESET_TYPE_FORCE_RESTART,
|
||||
sushy.RESET_TYPE_GRACEFUL_RESTART, sushy.RESET_TYPE_ON,
|
||||
sushy.RESET_TYPE_FORCE_OFF,
|
||||
sushy.RESET_TYPE_GRACEFUL_SHUTDOWN}
|
||||
# | WHEN |
|
||||
values = self.chassis.get_allowed_reset_chassis_values()
|
||||
# | THEN |
|
||||
self.assertEqual(expected, values)
|
||||
self.assertIsInstance(values, set)
|
||||
|
||||
def test_get_allowed_reset_chassis_values_missing_action_reset_attr(self):
|
||||
# | GIVEN |
|
||||
self.chassis._actions.reset = None
|
||||
# | WHEN & THEN |
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingActionError, 'action #Chassis.Reset')
|
||||
|
||||
def test_reset_chassis(self):
|
||||
self.chassis.reset_chassis(sushy.RESET_TYPE_GRACEFUL_RESTART)
|
||||
self.chassis._conn.post.assert_called_once_with(
|
||||
'/redfish/v1/Chassis/Blade1/Actions/Chassis.Reset',
|
||||
data={'ResetType': 'GracefulRestart'})
|
||||
|
||||
def test_reset_chassis_with_invalid_value(self):
|
||||
self.assertRaises(exceptions.InvalidParameterValueError,
|
||||
self.chassis.reset_chassis, 'invalid-value')
|
||||
|
||||
|
||||
class ChassisCollectionTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ChassisCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'chassis_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
self.chassis = chassis.ChassisCollection(
|
||||
self.conn, '/redfish/v1/Chassis', redfish_version='1.5.0')
|
||||
|
||||
@mock.patch.object(chassis, 'Chassis', autospec=True)
|
||||
def test_get_member(self, chassis_mock):
|
||||
self.chassis.get_member('/redfish/v1/Chassis/MultiBladeEncl')
|
||||
chassis_mock.assert_called_once_with(
|
||||
self.chassis._conn, '/redfish/v1/Chassis/MultiBladeEncl',
|
||||
redfish_version=self.chassis.redfish_version)
|
||||
|
||||
@mock.patch.object(chassis, 'Chassis', autospec=True)
|
||||
def test_get_members(self, chassis_mock):
|
||||
members = self.chassis.get_members()
|
||||
calls = [
|
||||
mock.call(self.chassis._conn, '/redfish/v1/Chassis/MultiBladeEncl',
|
||||
redfish_version=self.chassis.redfish_version),
|
||||
mock.call(self.chassis._conn, '/redfish/v1/Chassis/Blade1',
|
||||
redfish_version=self.chassis.redfish_version),
|
||||
mock.call(self.chassis._conn, '/redfish/v1/Chassis/Blade2',
|
||||
redfish_version=self.chassis.redfish_version),
|
||||
mock.call(self.chassis._conn, '/redfish/v1/Chassis/Blade3',
|
||||
redfish_version=self.chassis.redfish_version),
|
||||
mock.call(self.chassis._conn, '/redfish/v1/Chassis/Blade4',
|
||||
redfish_version=self.chassis.redfish_version)
|
||||
]
|
||||
chassis_mock.assert_has_calls(calls)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(5, len(members))
|
|
@ -21,6 +21,7 @@ from sushy import auth
|
|||
from sushy import connector
|
||||
from sushy import exceptions
|
||||
from sushy import main
|
||||
from sushy.resources.chassis import chassis
|
||||
from sushy.resources.manager import manager
|
||||
from sushy.resources.registry import message_registry_file
|
||||
from sushy.resources.sessionservice import session
|
||||
|
@ -99,6 +100,20 @@ class MainTestCase(base.TestCase):
|
|||
self.root._conn, 'fake-system-id',
|
||||
redfish_version=self.root.redfish_version)
|
||||
|
||||
@mock.patch.object(chassis, 'Chassis', autospec=True)
|
||||
def test_get_chassis(self, mock_chassis):
|
||||
self.root.get_chassis('fake-chassis-id')
|
||||
mock_chassis.assert_called_once_with(
|
||||
self.root._conn, 'fake-chassis-id',
|
||||
redfish_version=self.root.redfish_version)
|
||||
|
||||
@mock.patch.object(chassis, 'ChassisCollection', autospec=True)
|
||||
def test_get_chassis_collection(self, chassis_collection_mock):
|
||||
self.root.get_chassis_collection()
|
||||
chassis_collection_mock.assert_called_once_with(
|
||||
self.root._conn, '/redfish/v1/Chassis',
|
||||
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()
|
||||
|
|
Loading…
Reference in New Issue