Add RAID mode conversion methods

Introduces System OEM extension and Dell RAID service
with first Convert to RAID/Non-RAID methods.

Depends-On: https://review.opendev.org/c/openstack/sushy/+/799504
Change-Id: I53964f935d82c349d51c0991c46a3e2b9b0d2682
This commit is contained in:
Aija Jauntēva 2021-06-17 12:03:43 -04:00
parent a9ab0b8051
commit 79d4ecb587
10 changed files with 1117 additions and 2 deletions

View File

@ -4,4 +4,4 @@
pbr!=2.1.0,>=2.0.0 # Apache-2.0
python-dateutil>=2.7.0 # BSD
sushy>=3.7.0 # Apache-2.0
sushy>=3.11.0 # Apache-2.0

View File

@ -26,7 +26,8 @@ packages =
[entry_points]
sushy.resources.manager.oems =
dell = sushy_oem_idrac.resources.manager.manager:get_extension
sushy.resources.system.oems =
dell = sushy_oem_idrac.resources.system.system:get_extension
[build_sphinx]
source-dir = doc/source

View File

@ -0,0 +1,15 @@
# Copyright (c) 2021 Dell Inc. or its subsidiaries.
#
# 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_oem_idrac.resources.system.constants import * # noqa

View File

@ -0,0 +1,19 @@
# Copyright (c) 2021 Dell Inc. or its subsidiaries.
#
# 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.
PHYSICAL_DISK_STATE_MODE_RAID = 'RAID'
"""RAID mode"""
PHYSICAL_DISK_STATE_MODE_NONRAID = 'Non-RAID'
"""Non-RAID mode"""

View File

@ -0,0 +1,108 @@
# Copyright (c) 2021 Dell Inc. or its subsidiaries.
#
# 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 import taskmonitor
LOG = logging.getLogger(__name__)
class ActionsField(base.CompositeField):
convert_to_raid = common.ActionField("#DellRaidService.ConvertToRAID")
convert_to_nonraid = common.ActionField(
"#DellRaidService.ConvertToNonRAID")
class DellRaidService(base.ResourceBase):
identity = base.Field('Id', required=True)
_actions = ActionsField('Actions')
def __init__(self, connector, identity, redfish_version=None,
registries=None, root=None):
"""A class representing a DellRaidService.
:param connector: A Connector instance
:param identity: The identity of the DellRaidService resource
:param redfish_version: The version of Redfish. Used to
construct the object according to schema of the given
version.
:param registries: Dict of Redfish Message Registry objects to
be used in any resource that needs registries to parse
messages.
:param root: Sushy root object. Empty for Sushy root itself.
"""
super(DellRaidService, self).__init__(
connector, identity, redfish_version=redfish_version,
registries=registries, root=root)
def convert_to_raid(self, physical_disk_fqdds):
"""Converts physical disks to a state usable for RAID
:param physical_disk_fqdds: An array of FQDDs where each
identifies a physical drive.
:returns: Sushy's TaskMonitor instance for TaskService task
"""
target_uri = self._actions.convert_to_raid.target_uri
payload = {'PDArray': physical_disk_fqdds}
response = self._conn.post(target_uri, data=payload)
task_monitor = self._get_task_monitor_from_dell_job(response)
LOG.info('Converting to RAID mode: %s', physical_disk_fqdds)
return task_monitor
def convert_to_nonraid(self, physical_disk_fqdds):
"""Converts physical disks to non-RAID state.
:param physical_disk_fqdds: An array of FQDDs where each
identifies a physical drive.
:returns: Sushy's TaskMonitor instance for TaskService task
"""
target_uri = self._actions.convert_to_nonraid.target_uri
payload = {'PDArray': physical_disk_fqdds}
response = self._conn.post(target_uri, data=payload)
task_monitor = self._get_task_monitor_from_dell_job(response)
LOG.info('Converting to non-RAID mode: %s', physical_disk_fqdds)
return task_monitor
def _get_task_monitor_from_dell_job(self, response):
"""From OEM job response returns generic Task monitor
:param response: Response from OEM job
:returns: Sushy's TaskMonitor instance for TaskService task
"""
location = response.headers.get('Location')
if not location:
raise exceptions.ExtensionError(
error='Response %s does not include Location in header'
% (response.url))
task_id = location.split('/')[-1]
task = None
for t in self.root.get_task_service().tasks.get_members():
if t.identity == task_id:
task = t
break
if not task:
raise exceptions.ExtensionError(
error="Did not find task by id %s" % task_id)
return taskmonitor.TaskMonitor(
self._conn, task.path,
redfish_version=self.redfish_version,
registries=self.registries)

View File

@ -0,0 +1,127 @@
# Copyright (c) 2021 Dell Inc. or its subsidiaries.
#
# 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 sushy
from sushy import exceptions
from sushy.resources.oem import base as oem_base
from sushy import utils as sushy_utils
from sushy_oem_idrac.resources.system import constants as sys_cons
from sushy_oem_idrac.resources.system import raid_service
def _filter_disks_not_in_mode(controller_to_disks, mode):
"""Filters disks that are not in requested mode
:param controller_to_disks: dictionary of controllers and their drives
:param mode: constants.PHYSICAL_DISK_STATE_MODE_RAID or
constants.PHYSICAL_DISK_STATE_MODE_NONRAID
:returns: dictionary of controllers and their drives that need mode changed
"""
sushy_raw_device = sushy.VOLUME_TYPE_RAW_DEVICE
for controller, drives in controller_to_disks.items():
toprocess_drives = []
for drive in drives:
is_raw_device = False
volumes = None
try:
volumes = drive.volumes
except exceptions.MissingAttributeError:
pass
if (volumes
and (volumes[0].volume_type == sushy_raw_device
or volumes[0].raid_type is None)):
is_raw_device = True
if (mode == sys_cons.PHYSICAL_DISK_STATE_MODE_RAID
and is_raw_device
or mode == sys_cons.PHYSICAL_DISK_STATE_MODE_NONRAID
and not is_raw_device):
toprocess_drives.append(drive)
controller_to_disks[controller] = toprocess_drives
return controller_to_disks
class DellSystemExtension(oem_base.OEMResourceBase):
@property
@sushy_utils.cache_it
def raid_service(self):
"""`DellRaidService` of the system"""
path = sushy_utils.get_sub_resource_path_by(
self, ["Links", "Oem", "Dell", "DellRaidService"],
is_collection=False)
return raid_service.DellRaidService(
self._conn, path, redfish_version=self.redfish_version,
registries=self.registries, root=self.root)
def change_physical_disk_state(self, mode, controller_to_disks=None):
"""Converts physical disks RAID status
Converts only those disks that are not already in requested mode.
:param mode: constants.PHYSICAL_DISK_STATE_MODE_RAID or
constants.PHYSICAL_DISK_STATE_MODE_NONRAID
:param controller_to_disks: dictionary of controllers and their drives.
Optional, if not provided, processes all RAID, except BOSS,
controller drives.
:returns: List of task monitors for each controller's disks if any
drives need changes
"""
if not controller_to_disks:
controller_to_disks = self._get_controller_to_disks()
# Do not process BOSS controllers as can't convert their disks
boss_controllers = [c for c in controller_to_disks
if 'BOSS' in c.name.upper()]
for c in boss_controllers:
controller_to_disks.pop(c)
controller_to_disks = _filter_disks_not_in_mode(
controller_to_disks, mode)
# Convert by each controller that have eligible disks
task_monitors = []
for controller, drives in controller_to_disks.items():
if drives:
drive_fqdds = [d.identity for d in drives]
if mode == sys_cons.PHYSICAL_DISK_STATE_MODE_RAID:
task_monitors.append(
self.raid_service.convert_to_raid(drive_fqdds))
elif mode == sys_cons.PHYSICAL_DISK_STATE_MODE_NONRAID:
task_monitors.append(
self.raid_service.convert_to_nonraid(drive_fqdds))
return task_monitors
def _get_controller_to_disks(self):
"""Gets all RAID controllers and their disks on system
:returns: dictionary of RAID controllers and their disks
"""
controller_to_disks = {}
for storage in self._parent_resource.storage.get_members():
controller = (storage.storage_controllers[0]
if storage.storage_controllers else None)
if not controller or controller and not controller.raid_types:
continue
controller_to_disks[controller] = storage.drives
return controller_to_disks
def get_extension(*args, **kwargs):
return DellSystemExtension

View File

@ -0,0 +1,213 @@
{
"@odata.context": "/redfish/v1/$metadata#DellRaidService.DellRaidService",
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService",
"@odata.type": "#DellRaidService.v1_3_0.DellRaidService",
"Actions": {
"#DellRaidService.AssignSpare": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.AssignSpare"
},
"#DellRaidService.BlinkTarget": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.BlinkTarget"
},
"#DellRaidService.CancelBackgroundInitialization": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.CancelBackgroundInitialization"
},
"#DellRaidService.CancelCheckConsistency": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.CancelCheckConsistency"
},
"#DellRaidService.CancelRebuildPhysicalDisk": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.CancelRebuildPhysicalDisk"
},
"#DellRaidService.ChangePDState": {
"State@Redfish.AllowableValues": [
"Offline",
"Online"
],
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ChangePDState"
},
"#DellRaidService.CheckVDValues": {
"VDPropNameArrayIn@Redfish.AllowableValues": [
"RAIDLevel",
"Size",
"SpanDepth",
"SpanLength",
"StartingLBA",
"T10PIStatus"
],
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.CheckVDValues"
},
"#DellRaidService.ClearControllerPreservedCache": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ClearControllerPreservedCache"
},
"#DellRaidService.ClearForeignConfig": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ClearForeignConfig"
},
"#DellRaidService.ConvertToNonRAID": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ConvertToNonRAID"
},
"#DellRaidService.ConvertToRAID": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ConvertToRAID"
},
"#DellRaidService.EnableControllerEncryption": {
"Mode@Redfish.AllowableValues": [
"DKM",
"LKM",
"SEKM"
],
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.EnableControllerEncryption"
},
"#DellRaidService.GetAvailableDisks": {
"BlockSizeInBytes@Redfish.AllowableValues": [
"4096",
"512",
"All"
],
"DiskEncrypt@Redfish.AllowableValues": [
"All",
"FDE",
"NonFDE"
],
"DiskType@Redfish.AllowableValues": [
"All",
"HDD",
"SSD"
],
"Diskprotocol@Redfish.AllowableValues": [
"AllProtocols",
"NVMe",
"SAS",
"SATA"
],
"FormFactor@Redfish.AllowableValues": [
"All",
"M.2"
],
"RaidLevel@Redfish.AllowableValues": [
"NoRAID",
"RAID0",
"RAID1",
"RAID10",
"RAID5",
"RAID50",
"RAID6",
"RAID60"
],
"T10PIStatus@Redfish.AllowableValues": [
"All",
"T10PICapable",
"T10PIIncapable"
],
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.GetAvailableDisks"
},
"#DellRaidService.GetDHSDisks": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.GetDHSDisks"
},
"#DellRaidService.GetRAIDLevels": {
"BlockSizeInBytes@Redfish.AllowableValues": [
"4096",
"512",
"All"
],
"DiskEncrypt@Redfish.AllowableValues": [
"All",
"FDE",
"NonFDE"
],
"DiskType@Redfish.AllowableValues": [
"All",
"HDD",
"SSD"
],
"Diskprotocol@Redfish.AllowableValues": [
"AllProtocols",
"NVMe",
"SAS",
"SATA"
],
"FormFactor@Redfish.AllowableValues": [
"All",
"M.2"
],
"T10PIStatus@Redfish.AllowableValues": [
"All",
"T10PICapable",
"T10PIIncapable"
],
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.GetRAIDLevels"
},
"#DellRaidService.ImportForeignConfig": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ImportForeignConfig"
},
"#DellRaidService.LockVirtualDisk": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.LockVirtualDisk"
},
"#DellRaidService.OnlineCapacityExpansion": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.OnlineCapacityExpansion"
},
"#DellRaidService.PrepareToRemove": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.PrepareToRemove"
},
"#DellRaidService.RAIDLevelMigration": {
"NewRaidLevel@Redfish.AllowableValues": [
"NoRAID",
"RAID0",
"RAID1",
"RAID10",
"RAID5",
"RAID50",
"RAID6",
"RAID60"
],
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.RAIDLevelMigration"
},
"#DellRaidService.ReKey": {
"Mode@Redfish.AllowableValues": [
"LKM",
"SEKM"
],
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ReKey"
},
"#DellRaidService.RebuildPhysicalDisk": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.RebuildPhysicalDisk"
},
"#DellRaidService.RemoveControllerKey": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.RemoveControllerKey"
},
"#DellRaidService.RenameVD": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.RenameVD"
},
"#DellRaidService.ReplacePhysicalDisk": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ReplacePhysicalDisk"
},
"#DellRaidService.ResetConfig": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ResetConfig"
},
"#DellRaidService.SetAssetName": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.SetAssetName"
},
"#DellRaidService.SetBootVD": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.SetBootVD"
},
"#DellRaidService.SetControllerKey": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.SetControllerKey"
},
"#DellRaidService.StartPatrolRead": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.StartPatrolRead"
},
"#DellRaidService.StopPatrolRead": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.StopPatrolRead"
},
"#DellRaidService.UnBlinkTarget": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.UnBlinkTarget"
},
"#DellRaidService.UnLockSecureForeignConfig": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.UnLockSecureForeignConfig"
},
"#DellRaidService.UnassignSpare": {
"target": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.UnassignSpare"
}
},
"Description": "The DellRaidService resource provides some actions to support RAID functionality.",
"Id": "DellRaidService",
"Name": "DellRaidService"
}

View File

@ -0,0 +1,398 @@
{
"@odata.context": "/redfish/v1/$metadata#ComputerSystem.ComputerSystem",
"@odata.id": "/redfish/v1/Systems/System.Embedded.1",
"@odata.type": "#ComputerSystem.v1_10_0.ComputerSystem",
"Actions": {
"#ComputerSystem.Reset": {
"target": "/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset",
"ResetType@Redfish.AllowableValues": [
"On",
"ForceOff",
"ForceRestart",
"GracefulRestart",
"GracefulShutdown",
"PushPowerButton",
"Nmi",
"PowerCycle"
]
}
},
"AssetTag": "",
"Bios": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Bios"
},
"BiosVersion": "2.10.2",
"Boot": {
"BootOptions": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/BootOptions"
},
"Certificates": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Boot/Certificates"
},
"BootOrder": [
"Boot0006",
"Boot0009",
"Boot0007",
"Boot0005",
"Boot0003",
"Boot0004",
"Boot0008",
"Boot0002"
],
"BootOrder@odata.count": 8,
"BootSourceOverrideEnabled": "Disabled",
"BootSourceOverrideMode": "UEFI",
"BootSourceOverrideTarget": "None",
"UefiTargetBootSourceOverride": null,
"BootSourceOverrideTarget@Redfish.AllowableValues": [
"None",
"Pxe",
"Floppy",
"Cd",
"Hdd",
"BiosSetup",
"Utilities",
"UefiTarget",
"SDCard",
"UefiHttp"
]
},
"Description": "Computer System which represents a machine (physical or virtual) and the local resources such as memory, cpu and other devices that can be accessed from that machine.",
"EthernetInterfaces": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/EthernetInterfaces"
},
"HostName": "",
"HostWatchdogTimer": {
"FunctionEnabled": false,
"Status": {
"State": "Disabled"
},
"TimeoutAction": "None"
},
"HostingRoles": [],
"HostingRoles@odata.count": 0,
"Id": "System.Embedded.1",
"IndicatorLED": "Lit",
"Links": {
"Chassis": [
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1"
}
],
"Chassis@odata.count": 1,
"CooledBy": [
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/0"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/1"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/2"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/3"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/4"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/5"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/6"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/7"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/8"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/9"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/10"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/11"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/12"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/13"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/14"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Thermal#/Fans/15"
}
],
"CooledBy@odata.count": 16,
"ManagedBy": [
{
"@odata.id": "/redfish/v1/Managers/iDRAC.Embedded.1"
}
],
"ManagedBy@odata.count": 1,
"Oem": {
"Dell": {
"@odata.type": "#DellOem.v1_1_0.DellOemLinks",
"BootOrder": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellBootSources"
},
"DellBootSources": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellBootSources"
},
"DellSoftwareInstallationService": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellSoftwareInstallationService"
},
"DellVideoCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellVideo"
},
"DellChassisCollection": {
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Oem/Dell/DellChassis"
},
"DellPresenceAndStatusSensorCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellPresenceAndStatusSensors"
},
"DellSensorCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellSensors"
},
"DellRollupStatusCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRollupStatus"
},
"DellPSNumericSensorCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellPSNumericSensors"
},
"DellVideoNetworkCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellVideoNetwork"
},
"DellOSDeploymentService": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellOSDeploymentService"
},
"DellMetricService": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellMetricService"
},
"DellGPUSensorCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellGPUSensors"
},
"DellRaidService": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService"
},
"DellNumericSensorCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellNumericSensors"
},
"DellBIOSService": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellBIOSService"
},
"DellSlotCollection": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellSlots"
}
}
},
"PoweredBy": [
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Power#/PowerSupplies/0"
},
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Power#/PowerSupplies/1"
}
],
"PoweredBy@odata.count": 2
},
"Manufacturer": "Dell Inc.",
"Memory": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Memory"
},
"MemorySummary": {
"MemoryMirroring": "System",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"TotalSystemMemoryGiB": 192
},
"Model": "PowerEdge R640",
"Name": "System",
"NetworkInterfaces": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/NetworkInterfaces"
},
"Oem": {
"Dell": {
"@odata.type": "#DellOem.v1_1_0.DellOemResources",
"DellSystem": {
"BIOSReleaseDate": "02/24/2021",
"BaseBoardChassisSlot": "NA",
"BatteryRollupStatus": "OK",
"BladeGeometry": "NotApplicable",
"CMCIP": null,
"CPURollupStatus": "OK",
"ChassisModel": "",
"ChassisName": "Main System Chassis",
"ChassisServiceTag": "8CYCZ23",
"ChassisSystemHeightUnit": 1,
"CurrentRollupStatus": "OK",
"EstimatedExhaustTemperatureCelsius": 46,
"EstimatedSystemAirflowCFM": 26,
"ExpressServiceCode": "18197565051",
"FanRollupStatus": "OK",
"Id": "System.Embedded.1",
"IDSDMRollupStatus": null,
"IntrusionRollupStatus": "OK",
"IsOEMBranded": "False",
"LastSystemInventoryTime": "2021-06-16T09:46:25+00:00",
"LastUpdateTime": "2021-05-31T15:39:10+00:00",
"LicensingRollupStatus": "OK",
"MaxCPUSockets": 2,
"MaxDIMMSlots": 24,
"MaxPCIeSlots": 3,
"MemoryOperationMode": "OptimizerMode",
"Name": "DellSystem",
"NodeID": "8CYCZ23",
"PSRollupStatus": "OK",
"PlatformGUID": "33325a4f-c0b8-4380-5910-00434c4c4544",
"PopulatedDIMMSlots": 12,
"PopulatedPCIeSlots": 1,
"PowerCapEnabledState": "Disabled",
"SDCardRollupStatus": null,
"SELRollupStatus": "OK",
"ServerAllocationWatts": null,
"StorageRollupStatus": "OK",
"SysMemErrorMethodology": "Multi-bitECC",
"SysMemFailOverState": "NotInUse",
"SysMemLocation": "SystemBoardOrMotherboard",
"SysMemPrimaryStatus": "OK",
"SystemGeneration": "14G Monolithic",
"SystemID": 1814,
"SystemRevision": "I",
"TempRollupStatus": "OK",
"TempStatisticsRollupStatus": "OK",
"UUID": "4c4c4544-0043-5910-8043-b8c04f5a3233",
"VoltRollupStatus": "OK",
"smbiosGUID": "44454c4c-4300-1059-8043-b8c04f5a3233",
"@odata.context": "/redfish/v1/$metadata#DellSystem.DellSystem",
"@odata.type": "#DellSystem.v1_2_0.DellSystem",
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellSystem/System.Embedded.1"
}
}
},
"PCIeDevices": [
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/25-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/24-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-28"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-23"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-31"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/3-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-17"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/59-0"
}
],
"PCIeDevices@odata.count": 9,
"PCIeFunctions": [
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/25-0/PCIeFunctions/25-0-1"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/24-0/PCIeFunctions/24-0-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/25-0/PCIeFunctions/25-0-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-28/PCIeFunctions/0-28-4"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-23/PCIeFunctions/0-23-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-31/PCIeFunctions/0-31-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-28/PCIeFunctions/0-28-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/3-0/PCIeFunctions/3-0-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-0/PCIeFunctions/0-0-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-17/PCIeFunctions/0-17-5"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/59-0/PCIeFunctions/59-0-1"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/59-0/PCIeFunctions/59-0-0"
},
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/PCIeDevices/0-31/PCIeFunctions/0-31-4"
}
],
"PCIeFunctions@odata.count": 13,
"PartNumber": "06NR82A02",
"PowerState": "On",
"ProcessorSummary": {
"Count": 2,
"LogicalProcessorCount": 80,
"Model": "Intel(R) Xeon(R) Gold 6230 CPU @ 2.10GHz",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
}
},
"Processors": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Processors"
},
"SKU": "8CYCZ23",
"SecureBoot": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/SecureBoot"
},
"SerialNumber": "CNIVC000180873",
"SimpleStorage": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/SimpleStorage"
},
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Storage": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Storage"
},
"SystemType": "Physical",
"TrustedModules": [
{
"FirmwareVersion": "Unknown",
"InterfaceType": null,
"Status": {
"State": "Disabled"
}
}
],
"TrustedModules@odata.count": 1,
"UUID": "4c4c4544-0043-5910-8043-b8c04f5a3233"
}

View File

@ -0,0 +1,122 @@
# Copyright (c) 2021 Dell Inc. or its subsidiaries.
#
# 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
from unittest import mock
from oslotest.base import BaseTestCase
from sushy import exceptions
from sushy import taskmonitor
from sushy_oem_idrac.resources.system import raid_service
class DellRaidService(BaseTestCase):
def setUp(self):
super(DellRaidService, self).setUp()
self.conn = mock.Mock()
with open('sushy_oem_idrac/tests/unit/json_samples/'
'raid_service.json') as f:
mock_response = self.conn.get.return_value
mock_response.json.return_value = json.load(f)
mock_response.status_code = 200
self.mock_response = mock.Mock()
self.mock_response.status_code = 202
self.mock_response.headers = {
'Location': '/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/Jobs/'
'JID_999888777666'
}
self.root = mock.Mock()
self.raid_service = raid_service.DellRaidService(
self.conn,
'/redfish/v1/Systems/System.Embedded.1/Oem/Dell/'
'DellRaidService', root=self.root
)
@mock.patch.object(raid_service.DellRaidService,
'_get_task_monitor_from_dell_job', autospec=True)
def test_convert_to_raid(self, mock_get_task_mon):
mock_task_mon = mock.Mock()
mock_get_task_mon.return_value = mock_task_mon
fqdds = ["Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1",
"Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1"]
task_mon = self.raid_service.convert_to_raid(fqdds)
self.conn.post.assert_called_once_with(
'/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/'
'Actions/DellRaidService.ConvertToRAID',
data={'PDArray': fqdds})
self.assertEqual(mock_task_mon, task_mon)
@mock.patch.object(raid_service.DellRaidService,
'_get_task_monitor_from_dell_job', autospec=True)
def test_convert_to_nonraid(self, mock_get_task_mon):
mock_task_mon = mock.Mock()
mock_get_task_mon.return_value = mock_task_mon
fqdds = ["Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1",
"Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1"]
task_mon = self.raid_service.convert_to_nonraid(fqdds)
self.conn.post.assert_called_once_with(
'/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/'
'Actions/DellRaidService.ConvertToNonRAID',
data={'PDArray': fqdds})
self.assertEqual(mock_task_mon, task_mon)
def test__get_task_monitor_from_dell_job(self):
mock_task1 = mock.Mock(identity='JID_111222333444',
path='/TaskService/Task/JID_111222333444')
mock_task2 = mock.Mock(identity='JID_999888777666',
path='/TaskService/Task/JID_999888777666')
mock_tasks = mock.Mock()
mock_tasks.get_members.return_value = [mock_task1, mock_task2]
self.root.get_task_service.return_value.tasks = mock_tasks
task_mon = self.raid_service._get_task_monitor_from_dell_job(
self.mock_response)
self.assertIsInstance(task_mon, taskmonitor.TaskMonitor)
self.assertEqual('/TaskService/Task/JID_999888777666',
task_mon.task_monitor_uri)
def test__get_task_monitor_from_dell_job_location_missing(self):
mock_response = mock.Mock()
mock_response.status_code = 202
mock_response.headers = {
'Connection': 'Keep-Alive'
}
self.assertRaisesRegex(
exceptions.ExtensionError,
'does not include Location',
self.raid_service._get_task_monitor_from_dell_job, mock_response)
def test__get_task_monitor_from_dell_job_task_not_found(self):
mock_task1 = mock.Mock(identity='JID_000000000000',
path='/TaskService/Task/JID_000000000000')
mock_tasks = mock.Mock()
mock_tasks.get_members.return_value = [mock_task1]
self.root.get_task_service.return_value.tasks = mock_tasks
self.assertRaisesRegex(
exceptions.ExtensionError,
'not find task by id',
self.raid_service._get_task_monitor_from_dell_job,
self.mock_response)

View File

@ -0,0 +1,112 @@
# Copyright (c) 2021 Dell Inc. or its subsidiaries.
#
# 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
from unittest import mock
from oslotest.base import BaseTestCase
from sushy import exceptions
from sushy_oem_idrac.resources.system import constants as sys_cons
from sushy_oem_idrac.resources.system import raid_service
from sushy_oem_idrac.resources.system import system as oem_system
class SystemTestCase(BaseTestCase):
def setUp(self):
super(SystemTestCase, self).setUp()
self.conn = mock.Mock()
with open('sushy_oem_idrac/tests/unit/json_samples/'
'system.json') as f:
mock_response = self.conn.get.return_value
mock_response.json.return_value = json.load(f)
mock_response.status_code = 200
self.oem_system = oem_system.DellSystemExtension(
self.conn, '/redfish/v1/Systems/System.Embedded.1')
mock_perc_raid = mock.Mock(
identity='Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1')
type(mock_perc_raid).volumes = mock.PropertyMock(
side_effect=exceptions.MissingAttributeError)
mock_perc_nonraid = mock.Mock(
identity='Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1',
volumes=[mock.Mock(volume_type='rawdevice', raid_type=None)])
mock_boss_controller = mock.MagicMock(raid_types=['RAID1'])
mock_boss_controller.name = 'BOSS-S1'
mock_boss = mock.Mock(storage_controllers=[mock_boss_controller],
drives=mock.Mock())
mock_perc_controller = mock.MagicMock(raid_types=['RAID1'])
mock_perc_controller.name = 'PERC'
mock_perc = mock.Mock(storage_controllers=[mock_perc_controller],
drives=[mock_perc_raid, mock_perc_nonraid])
mock_system = mock.Mock()
mock_storage_nocontroller = mock.Mock(storage_controllers=[])
mock_storage_nonraid = mock.Mock(
storage_controllers=[mock.Mock(raid_types=[])])
mock_storage_boss = mock_boss
mock_storage_raid = mock_perc
mock_system.storage.get_members.return_value = [
mock_storage_nocontroller, mock_storage_nonraid, mock_storage_boss,
mock_storage_raid]
self.oem_system._parent_resource = mock_system
def test_raid_service(self):
with open('sushy_oem_idrac/tests/unit/json_samples/'
'raid_service.json') as f:
mock_response = self.conn.get.return_value
mock_response.json.return_value = json.load(f)
mock_response.status_code = 200
result = self.oem_system.raid_service
self.assertEqual(
'/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService',
result.path)
self.assertIsInstance(result,
raid_service.DellRaidService)
def test_change_physical_disk_state_raid(self):
mock_taskmon = mock.Mock()
mock_raid = mock.Mock()
mock_raid.return_value = mock_taskmon
mock_nonraid = mock.Mock()
self.oem_system.raid_service.convert_to_raid = mock_raid
self.oem_system.raid_service.convert_to_nonraid = mock_nonraid
task_mons = self.oem_system.change_physical_disk_state(
sys_cons.PHYSICAL_DISK_STATE_MODE_RAID)
self.assertEqual([mock_taskmon], task_mons)
mock_raid.assert_called_once_with(
['Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1'])
mock_nonraid.assert_not_called()
def test_change_physical_disk_state_nonraid(self):
mock_taskmon = mock.Mock()
mock_raid = mock.Mock()
mock_nonraid = mock.Mock()
mock_nonraid.return_value = mock_taskmon
self.oem_system.raid_service.convert_to_raid = mock_raid
self.oem_system.raid_service.convert_to_nonraid = mock_nonraid
task_mons = self.oem_system.change_physical_disk_state(
sys_cons.PHYSICAL_DISK_STATE_MODE_NONRAID)
self.assertEqual([mock_taskmon], task_mons)
mock_raid.assert_not_called()
mock_nonraid.assert_called_once_with(
['Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1'])