Implement storage service discovery
Add the discovery of pod manager storage services to the rsd-lib suhsy extension. Change-Id: Ie824e18e6121f8822254a218ca94b07645b3ff60 Implements-Blueprint: storage-services
This commit is contained in:
parent
834e77e6d6
commit
3252ab39fb
@ -17,6 +17,7 @@ import sushy
|
||||
from sushy.resources import base
|
||||
|
||||
from rsd_lib.resources.node import node
|
||||
from rsd_lib.resources.storage_service import storage_service
|
||||
|
||||
|
||||
class RSDLib(sushy.Sushy):
|
||||
@ -24,6 +25,10 @@ class RSDLib(sushy.Sushy):
|
||||
_nodes_path = base.Field(['Nodes', '@odata.id'], required=True)
|
||||
"""NodeCollection path"""
|
||||
|
||||
_storage_service_path = base.Field(['Services',
|
||||
'@odata.id'], required=True)
|
||||
"""StorageServiceCollection path"""
|
||||
|
||||
def get_node_collection(self):
|
||||
"""Get the NodeCollection object
|
||||
|
||||
@ -42,3 +47,24 @@ class RSDLib(sushy.Sushy):
|
||||
"""
|
||||
return node.Node(self._conn, identity,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def get_storage_service_collection(self):
|
||||
"""Get the StorageServiceCollection object
|
||||
|
||||
:raises: MissingAttributeError, if the collection attribute is
|
||||
not found
|
||||
:returns: a StorageServiceCollection object
|
||||
"""
|
||||
return storage_service.StorageServiceCollection(
|
||||
self._conn, self._storage_service_path,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def get_storage_service(self, identity):
|
||||
"""Given the identity return a StorageService object
|
||||
|
||||
:param identity: The identity of the StorageService resource
|
||||
:returns: The StorageService object
|
||||
"""
|
||||
return storage_service.StorageService(
|
||||
self._conn, identity,
|
||||
redfish_version=self.redfish_version)
|
||||
|
0
rsd_lib/resources/storage_service/__init__.py
Normal file
0
rsd_lib/resources/storage_service/__init__.py
Normal file
76
rsd_lib/resources/storage_service/logical_drive.py
Normal file
76
rsd_lib/resources/storage_service/logical_drive.py
Normal file
@ -0,0 +1,76 @@
|
||||
# Copyright 2017 Intel, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LogicalDrive(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The logical drive identity string"""
|
||||
|
||||
drive_type = base.Field('Type')
|
||||
"""Type of logical drive"""
|
||||
|
||||
mode = base.Field('Mode')
|
||||
"""Drive mode - for Type=='LVM' only supported mode is 'LV'"""
|
||||
|
||||
protected = base.Field('Protected')
|
||||
"""If logical drive is protected"""
|
||||
|
||||
capacity_gib = base.Field('CapacityGiB')
|
||||
"""Logical drive capacity in GiB"""
|
||||
|
||||
image = base.Field('Image')
|
||||
"""Any name that identifies the content of image copied to this LV"""
|
||||
|
||||
bootable = base.Field('Bootable')
|
||||
"""If the LV contains a bootable operating system"""
|
||||
|
||||
snapshot = base.Field('Snapshot')
|
||||
"""Type of drive replication. Yes - copy on write, No - disc clone"""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a LogicalDrive
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the LogicalDrive resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(LogicalDrive, self).__init__(connector, identity,
|
||||
redfish_version)
|
||||
|
||||
|
||||
class LogicalDriveCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return LogicalDrive
|
||||
|
||||
def __init__(self, connector, path, redfish_version=None):
|
||||
"""A class representing a LogicalDriveCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: The canonical path to the LogicalDrive collection resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(LogicalDriveCollection, self).__init__(connector, path,
|
||||
redfish_version)
|
77
rsd_lib/resources/storage_service/physical_drive.py
Normal file
77
rsd_lib/resources/storage_service/physical_drive.py
Normal file
@ -0,0 +1,77 @@
|
||||
# Copyright 2017 Intel, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PhysicalDrive(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The physical drive identity string"""
|
||||
|
||||
interface = base.Field('Interface')
|
||||
"""The interface for the physical drive"""
|
||||
|
||||
capacity_gib = base.Field('CapacityGiB')
|
||||
"""Physical drive capacity in GiB"""
|
||||
|
||||
drive_type = base.Field('Type')
|
||||
"""Type of physical drive"""
|
||||
|
||||
rpm = base.Field('RPM')
|
||||
"""The RPM of this physical drive"""
|
||||
|
||||
manufacturer = base.Field('Manufacture')
|
||||
"""The manufacturer of the physical drive"""
|
||||
|
||||
model = base.Field('Model')
|
||||
"""The model of this physical drive"""
|
||||
|
||||
serial_number = base.Field('SerialNumber')
|
||||
"""The serial number for the physical drive"""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a PhysicalDrive
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the PhysicalDrive resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(PhysicalDrive, self).__init__(connector, identity,
|
||||
redfish_version)
|
||||
|
||||
|
||||
class PhysicalDriveCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return PhysicalDrive
|
||||
|
||||
def __init__(self, connector, path, redfish_version=None):
|
||||
"""A class representing a PhysicalDriveCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: The canonical path to the PhysicalDrive collection
|
||||
resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(PhysicalDriveCollection, self).__init__(connector, path,
|
||||
redfish_version)
|
62
rsd_lib/resources/storage_service/remote_target.py
Normal file
62
rsd_lib/resources/storage_service/remote_target.py
Normal file
@ -0,0 +1,62 @@
|
||||
# Copyright 2017 Intel, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RemoteTarget(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The target identity string"""
|
||||
|
||||
target_type = base.Field('Type')
|
||||
"""Type of target"""
|
||||
|
||||
addresses = base.Field('Addresses')
|
||||
|
||||
initiator = base.Field('Initiator')
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a RemoteTarget
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the RemoteTarget resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(RemoteTarget, self).__init__(connector, identity,
|
||||
redfish_version)
|
||||
|
||||
|
||||
class RemoteTargetCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return RemoteTarget
|
||||
|
||||
def __init__(self, connector, path, redfish_version=None):
|
||||
"""A class representing a RemoteTargetCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: The canonical path to the RemoteTarget collection resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(RemoteTargetCollection, self).__init__(connector, path,
|
||||
redfish_version)
|
145
rsd_lib/resources/storage_service/storage_service.py
Normal file
145
rsd_lib/resources/storage_service/storage_service.py
Normal file
@ -0,0 +1,145 @@
|
||||
# Copyright 2017 Intel, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
|
||||
from rsd_lib.resources.storage_service import logical_drive
|
||||
from rsd_lib.resources.storage_service import physical_drive
|
||||
from rsd_lib.resources.storage_service import remote_target
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class StorageService(base.ResourceBase):
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The storage service description"""
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The storage service identity string"""
|
||||
|
||||
name = base.Field('Name')
|
||||
"""The storage service name"""
|
||||
|
||||
_logical_drives = None # ref to LogicalDriveCollection instance
|
||||
|
||||
_physical_drives = None # ref to PhysicalDrivesCollection instance
|
||||
|
||||
_remote_targets = None # ref to RemoteTargetCollection instance
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a StorageService
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the StorageService resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(StorageService, self).__init__(connector, identity,
|
||||
redfish_version)
|
||||
|
||||
def _get_logical_drive_collection_path(self):
|
||||
"""Helper function to find the LogicalDriveCollection path"""
|
||||
logical_drive_col = self.json.get('LogicalDrives')
|
||||
if not logical_drive_col:
|
||||
raise exceptions.MissingAttributeError(attribute='LogicalDrives',
|
||||
resource=self._path)
|
||||
return logical_drive_col.get('@odata.id')
|
||||
|
||||
@property
|
||||
def logical_drives(self):
|
||||
"""Property to provide reference to `LogicalDriveCollection` instance
|
||||
|
||||
It is calculated once when it is queried for the first time. On
|
||||
refresh, this property is reset.
|
||||
"""
|
||||
if self._logical_drives is None:
|
||||
self._logical_drives = logical_drive.LogicalDriveCollection(
|
||||
self._conn, self._get_logical_drive_collection_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
return self._logical_drives
|
||||
|
||||
def _get_physical_drive_collection_path(self):
|
||||
"""Helper function to find the PhysicalDriveCollection path"""
|
||||
physical_drive_col = self.json.get('Drives')
|
||||
if not physical_drive_col:
|
||||
raise exceptions.MissingAttributeError(attribute='PhysicalDrives',
|
||||
resource=self._path)
|
||||
return physical_drive_col.get('@odata.id')
|
||||
|
||||
@property
|
||||
def physical_drives(self):
|
||||
"""Property to provide reference to `PhysicalDriveCollection` instance
|
||||
|
||||
It is calculated once when it is queried for the first time. On
|
||||
refresh, this property is reset.
|
||||
"""
|
||||
if self._physical_drives is None:
|
||||
self._physical_drives = physical_drive.PhysicalDriveCollection(
|
||||
self._conn, self._get_physical_drive_collection_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
return self._physical_drives
|
||||
|
||||
def _get_remote_target_collection_path(self):
|
||||
"""Helper function to find the RemoteTargetCollection path"""
|
||||
remote_target_col = self.json.get('RemoteTargets')
|
||||
if not remote_target_col:
|
||||
raise exceptions.MissingAttributeError(attribute='RemoteTargets',
|
||||
resource=self._path)
|
||||
return remote_target_col.get('@odata.id')
|
||||
|
||||
@property
|
||||
def remote_targets(self):
|
||||
"""Property to provide reference to `RemoteTargetCollection` instance
|
||||
|
||||
It is calculated once when it is queried for the first time. On
|
||||
refresh, this property is reset.
|
||||
"""
|
||||
if self._remote_targets is None:
|
||||
self._remote_targets = remote_target.RemoteTargetCollection(
|
||||
self._conn, self._get_remote_target_collection_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
return self._remote_targets
|
||||
|
||||
def refresh(self):
|
||||
super(StorageService, self).refresh()
|
||||
self._logical_drives = None
|
||||
self._physical_drives = None
|
||||
self._remote_targets = None
|
||||
|
||||
|
||||
class StorageServiceCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return StorageService
|
||||
|
||||
def __init__(self, connector, path, redfish_version=None):
|
||||
"""A class representing a StorageServiceCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: The canonical path to the StorageService collection
|
||||
resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(StorageServiceCollection, self).__init__(connector, path,
|
||||
redfish_version)
|
43
rsd_lib/tests/unit/json_samples/logical_drive.json
Normal file
43
rsd_lib/tests/unit/json_samples/logical_drive.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#LogicalDrives/Links/Members/$entity",
|
||||
"@odata.id": "/redfish/v1/Services/1/LogicalDrives/1",
|
||||
"@odata.type": "#LogicalDrive.LogicalDrive",
|
||||
"Id": "1",
|
||||
"Name": "Logical Drive",
|
||||
"Description": "Logical Drive",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK",
|
||||
},
|
||||
"Type": "LVM",
|
||||
"Mode": "RAID0",
|
||||
"Protected": false,
|
||||
"CapacityGiB": 8096,
|
||||
"Image": "Ubuntu 12.04.4LTS / Linux 3.11 / 2014.1",
|
||||
"Bootable": true,
|
||||
"Snapshot": false,
|
||||
"Oem": {},
|
||||
"Links": {
|
||||
"LogicalDrives": [
|
||||
],
|
||||
"PhysicalDrives": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Services/1/Drives/2"
|
||||
}
|
||||
],
|
||||
"MasterDrive": {
|
||||
"@odata.id": "/redfish/v1/Services/1/LogicalDrives/12"
|
||||
},
|
||||
"UsedBy": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Services/1/LogicalDrives/14"
|
||||
}
|
||||
],
|
||||
"Targets": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Services/1/Targets/2"
|
||||
}
|
||||
],
|
||||
"Oem": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#LogicalDrives",
|
||||
"@odata.id": "/redfish/v1/Services/1/LogicalDrives",
|
||||
"@odata.type": "#LogicalDriveCollection.LogicalDriveCollection",
|
||||
"Name": "Logical Drives Collection",
|
||||
"Members@odata.count": 1,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Services/1/LogicalDrives/1"
|
||||
}
|
||||
]
|
||||
}
|
28
rsd_lib/tests/unit/json_samples/physical_drive.json
Normal file
28
rsd_lib/tests/unit/json_samples/physical_drive.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Drive/Links/Members/$entity",
|
||||
"@odata.id": "/redfish/v1/Services/1/Drives/1",
|
||||
"@odata.type": "#PhysicalDrive.v1_0_0.PhysicalDrive",
|
||||
"Id": "1","Name": "Simple drive"
|
||||
"Description": "Physical drive"
|
||||
"Interface": < { "PCIe", "SAS", "SATA" } >
|
||||
"CapacityGiB": 500,
|
||||
"Type": < { "HDD", "SSD" } >,
|
||||
"RPM": 0,
|
||||
"Manufacturer": "Intel",
|
||||
"Model": "S3710",
|
||||
"SerialNumber": "XYZ123456789",
|
||||
"Status": {
|
||||
"State": < { "Enabled", "Disabled", "Offline", "InTest", "Starting", "Absent" } >,
|
||||
"Health": < {"OK", "Warning", "Critical" } >,
|
||||
"HealthRollup": < {"OK", "Warning", "Critical" } >
|
||||
},
|
||||
"Oem": {},
|
||||
"Links": {
|
||||
"UsedBy": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Services/1/LogicalDrives/1"
|
||||
}
|
||||
],
|
||||
"Oem": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Drives",
|
||||
"@odata.id": "/redfish/v1/Services/1/Drives",
|
||||
"@odata.type": "#PhysicalDriveCollection.PhysicalDriveCollection",
|
||||
"Name": "Physical Drives Collection",
|
||||
"Members@odata.count": 1,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Services/1/Drives/1"
|
||||
}
|
||||
]
|
||||
}
|
46
rsd_lib/tests/unit/json_samples/remote_target.json
Normal file
46
rsd_lib/tests/unit/json_samples/remote_target.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#RemoteTargets/Links/Members/$entity",
|
||||
"@odata.id": "/redfish/v1/Services/1/Targets/1",
|
||||
"@odata.type": "#RemoteTarget.v1_1_0.RemoteTarget",
|
||||
"Id": "1",
|
||||
"Name": "Remote Target",
|
||||
"Description": "Remote Target",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"Type": "Network Storage",
|
||||
"Addresses": [
|
||||
{
|
||||
"iSCSI":
|
||||
{
|
||||
"TargetLUN": [
|
||||
{
|
||||
"LUN" : 1,
|
||||
"LogicalDrive": "/redfish/v1/Services/1/LogicalDrives/1"
|
||||
}
|
||||
],
|
||||
"TargetIQN": "iqn.2015-01.com.example:ceph-ubuntu14",
|
||||
"TargetPortalIP": "10.102.44.54",
|
||||
"TargetPortalPort": 3260,
|
||||
"CHAP": {
|
||||
"Type": "Mutual",
|
||||
"Username": "valid_user",
|
||||
"Secret": null,
|
||||
"MutualUsername": "user2",
|
||||
"MutualSecret": null
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Initiator": [
|
||||
{
|
||||
"iSCSI":
|
||||
{
|
||||
"InitiatorIQN": "iqn.2015-01.com.example:fedora21"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Oem": {},
|
||||
"Links": {}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#RemoteTargets",
|
||||
"@odata.id": "/redfish/v1/Services/1/Targets",
|
||||
"@odata.type": "#RemoteTargetCollection.RemoteTargetCollection",
|
||||
"Name": "Remote Targets Collection",
|
||||
"Members@odata.count": 1,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Services/1/Targets/1"
|
||||
}
|
||||
]
|
||||
}
|
@ -7,6 +7,9 @@
|
||||
"Systems": {
|
||||
"@odata.id": "/redfish/v1/Systems"
|
||||
},
|
||||
"Services": {
|
||||
"@odata.id": "/redfish/v1/Services"
|
||||
},
|
||||
"Chassis": {
|
||||
"@odata.id": "/redfish/v1/Chassis"
|
||||
},
|
||||
|
30
rsd_lib/tests/unit/json_samples/storage_service.json
Normal file
30
rsd_lib/tests/unit/json_samples/storage_service.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Services/Members/1/$entity",
|
||||
"@odata.id": "/redfish/v1/Services/RSS1",
|
||||
"@odata.type": "#StorageService.v1 0 0.StorageService",
|
||||
"Id": "RSS1",
|
||||
"Name": "Storage Service",
|
||||
"Description": "Storage Service",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"RemoteTargets": {
|
||||
"@odata.id": "/redfish/v1/Services/RSS1/Targets"
|
||||
},
|
||||
"LogicalDrives": {
|
||||
"@odata.id": "/redfish/v1/Services/RSS1/LogicalDrives"
|
||||
},
|
||||
"Drives": {
|
||||
"@odata.id": "/redfish/v1/Services/RSS1/Drives"
|
||||
},
|
||||
"Oem": {},
|
||||
"Links": {
|
||||
"ManagedBy": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Managers/RSS"
|
||||
}
|
||||
],
|
||||
"Oem": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#StorageServices",
|
||||
"@odata.id": "/redfish/v1/Services",
|
||||
"@odata.type": "#StorageServiceCollection.StorageServiceCollection",
|
||||
"Name": "Storage Services Collection",
|
||||
"Description": "Collection of RSD Storage Services",
|
||||
"Members@odata.count": 1,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Services/RSS1"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,251 @@
|
||||
# Copyright 2017 Intel, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
|
||||
import mock
|
||||
from sushy import exceptions
|
||||
import testtools
|
||||
|
||||
from rsd_lib.resources.storage_service import logical_drive
|
||||
from rsd_lib.resources.storage_service import physical_drive
|
||||
from rsd_lib.resources.storage_service import remote_target
|
||||
from rsd_lib.resources.storage_service import storage_service
|
||||
|
||||
|
||||
class StorageServiceTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(StorageServiceTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/storage_service.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.storage_service_inst = storage_service.StorageService(
|
||||
self.conn, '/redfish/v1/Nodes/RSS1',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.storage_service_inst._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.storage_service_inst.redfish_version)
|
||||
self.assertEqual('Storage Service',
|
||||
self.storage_service_inst.description)
|
||||
self.assertEqual('RSS1', self.storage_service_inst.identity)
|
||||
self.assertEqual('Storage Service', self.storage_service_inst.name)
|
||||
self.assertIsNone(self.storage_service_inst._logical_drives)
|
||||
self.assertIsNone(self.storage_service_inst._physical_drives)
|
||||
self.assertIsNone(self.storage_service_inst._remote_targets)
|
||||
|
||||
def test__get_logical_drive_collection_path_missing_processors_attr(self):
|
||||
self.storage_service_inst._json.pop('LogicalDrives')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute LogicalDrives',
|
||||
self.storage_service_inst._get_logical_drive_collection_path)
|
||||
|
||||
def test_logical_drives(self):
|
||||
# check for the underneath variable value
|
||||
self.assertIsNone(self.storage_service_inst._logical_drives)
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'logical_drive_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN |
|
||||
actual_logical_drives = self.storage_service_inst.logical_drives
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_logical_drives,
|
||||
logical_drive.LogicalDriveCollection)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
# | WHEN & THEN |
|
||||
# tests for same object on invoking subsequently
|
||||
self.assertIs(actual_logical_drives,
|
||||
self.storage_service_inst.logical_drives)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_logical_drives_on_refresh(self):
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'logical_drive_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.storage_service_inst.logical_drives,
|
||||
logical_drive.LogicalDriveCollection)
|
||||
|
||||
# On refreshing the storage service instance...
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'storage_service.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.storage_service_inst.refresh()
|
||||
|
||||
# | WHEN & THEN |
|
||||
self.assertIsNone(self.storage_service_inst._logical_drives)
|
||||
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'logical_drive_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.storage_service_inst.logical_drives,
|
||||
logical_drive.LogicalDriveCollection)
|
||||
|
||||
def test__get_physical_drive_collection_path_missing_processors_attr(self):
|
||||
self.storage_service_inst._json.pop('Drives')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute PhysicalDrives',
|
||||
self.storage_service_inst._get_physical_drive_collection_path)
|
||||
|
||||
def test_physical_drives(self):
|
||||
# check for the underneath variable value
|
||||
self.assertIsNone(self.storage_service_inst._physical_drives)
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'physical_drive_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN |
|
||||
actual_physical_drives = self.storage_service_inst.physical_drives
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_physical_drives,
|
||||
physical_drive.PhysicalDriveCollection)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
# | WHEN & THEN |
|
||||
# tests for same object on invoking subsequently
|
||||
self.assertIs(actual_physical_drives,
|
||||
self.storage_service_inst.physical_drives)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_physical_drives_on_refresh(self):
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'physical_drive_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.storage_service_inst.physical_drives,
|
||||
physical_drive.PhysicalDriveCollection)
|
||||
|
||||
# On refreshing the storage service instance...
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'storage_service.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.storage_service_inst.refresh()
|
||||
|
||||
# | WHEN & THEN |
|
||||
self.assertIsNone(self.storage_service_inst._physical_drives)
|
||||
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'physical_drive_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.storage_service_inst.physical_drives,
|
||||
physical_drive.PhysicalDriveCollection)
|
||||
|
||||
def test__get_remote_target_collection_path_missing_processors_attr(self):
|
||||
self.storage_service_inst._json.pop('RemoteTargets')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute RemoteTargets',
|
||||
self.storage_service_inst._get_remote_target_collection_path)
|
||||
|
||||
def test_remote_targets(self):
|
||||
# check for the underneath variable value
|
||||
self.assertIsNone(self.storage_service_inst._remote_targets)
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'remote_target_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN |
|
||||
actual_remote_targets = self.storage_service_inst.remote_targets
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_remote_targets,
|
||||
remote_target.RemoteTargetCollection)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
# | WHEN & THEN |
|
||||
# tests for same object on invoking subsequently
|
||||
self.assertIs(actual_remote_targets,
|
||||
self.storage_service_inst.remote_targets)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_remote_targets_on_refresh(self):
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'remote_target_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.storage_service_inst.remote_targets,
|
||||
remote_target.RemoteTargetCollection)
|
||||
|
||||
# On refreshing the storage service instance...
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'storage_service.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.storage_service_inst.refresh()
|
||||
|
||||
# | WHEN & THEN |
|
||||
self.assertIsNone(self.storage_service_inst._remote_targets)
|
||||
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'remote_target_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.storage_service_inst.remote_targets,
|
||||
remote_target.RemoteTargetCollection)
|
||||
|
||||
|
||||
class StorageServiceCollectionTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(StorageServiceCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/'
|
||||
'storage_service_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.storage_service_col = storage_service.StorageServiceCollection(
|
||||
self.conn, '/redfish/v1/Services', redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.storage_service_col._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.storage_service_col.redfish_version)
|
||||
self.assertEqual('Storage Services Collection',
|
||||
self.storage_service_col.name)
|
||||
self.assertEqual(('/redfish/v1/Services/RSS1',),
|
||||
self.storage_service_col.members_identities)
|
||||
|
||||
@mock.patch.object(storage_service, 'StorageService', autospec=True)
|
||||
def test_get_member(self, mock_storage_service):
|
||||
self.storage_service_col.get_member('/redfish/v1/Services/RSS1')
|
||||
mock_storage_service.assert_called_once_with(
|
||||
self.storage_service_col._conn, '/redfish/v1/Services/RSS1',
|
||||
redfish_version=self.storage_service_col.redfish_version)
|
||||
|
||||
@mock.patch.object(storage_service, 'StorageService', autospec=True)
|
||||
def test_get_members(self, mock_storage_service):
|
||||
members = self.storage_service_col.get_members()
|
||||
mock_storage_service.assert_called_once_with(
|
||||
self.storage_service_col._conn, '/redfish/v1/Services/RSS1',
|
||||
redfish_version=self.storage_service_col.redfish_version)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(1, len(members))
|
Loading…
x
Reference in New Issue
Block a user