Add CapacitySources class in RSD 2.4
Change-Id: I049ce331a5a2f430dca4a5e9f56e11dcbfc4fa45
This commit is contained in:
parent
171b075a92
commit
aeacfae878
132
rsd_lib/resources/v2_4/storage_service/capacity.py
Normal file
132
rsd_lib/resources/v2_4/storage_service/capacity.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
from sushy.resources import base
|
||||||
|
from sushy import utils
|
||||||
|
|
||||||
|
from rsd_lib import base as rsd_lib_base
|
||||||
|
from rsd_lib.resources.v2_3.storage_service import drive
|
||||||
|
from rsd_lib.resources.v2_3.storage_service import storage_pool
|
||||||
|
from rsd_lib import utils as rsd_lib_utils
|
||||||
|
|
||||||
|
|
||||||
|
class CapacityInfoField(base.CompositeField):
|
||||||
|
"""CapacityInfo field
|
||||||
|
|
||||||
|
The capacity of specific data type in a data store.
|
||||||
|
"""
|
||||||
|
|
||||||
|
consumed_bytes = base.Field(
|
||||||
|
"ConsumedBytes", adapter=rsd_lib_utils.num_or_none
|
||||||
|
)
|
||||||
|
"""The number of bytes consumed in this data store for this data type."""
|
||||||
|
|
||||||
|
allocated_bytes = base.Field(
|
||||||
|
"AllocatedBytes", adapter=rsd_lib_utils.num_or_none
|
||||||
|
)
|
||||||
|
"""The number of bytes currently allocated by the storage system in this
|
||||||
|
data store for this data type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
guaranteed_bytes = base.Field(
|
||||||
|
"GuaranteedBytes", adapter=rsd_lib_utils.num_or_none
|
||||||
|
)
|
||||||
|
"""The number of bytes the storage system guarantees can be allocated in
|
||||||
|
this data store for this data type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
provisioned_bytes = base.Field(
|
||||||
|
"ProvisionedBytes", adapter=rsd_lib_utils.num_or_none
|
||||||
|
)
|
||||||
|
"""The maximum number of bytes that can be allocated in this data store
|
||||||
|
for this data type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class CapacityField(base.CompositeField):
|
||||||
|
"""Capacity field
|
||||||
|
|
||||||
|
This is the schema definition for the Capacity of a device. It
|
||||||
|
represents the properties for capacity for any data store.
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = CapacityInfoField("Data")
|
||||||
|
"""The capacity information relating to the user data."""
|
||||||
|
|
||||||
|
metadata = CapacityInfoField("Metadata")
|
||||||
|
"""The capacity information relating to metadata."""
|
||||||
|
|
||||||
|
snapshot = CapacityInfoField("Snapshot")
|
||||||
|
"""The capacity information relating to snapshot or backup data."""
|
||||||
|
|
||||||
|
is_thin_provisioned = base.Field("IsThinProvisioned", adapter=bool)
|
||||||
|
"""Marks that the capacity is not necessarily fully allocated."""
|
||||||
|
|
||||||
|
|
||||||
|
class CapacitySource(rsd_lib_base.ResourceBase):
|
||||||
|
"""CapacitySource resource class
|
||||||
|
|
||||||
|
A description of the type and source of storage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
provided_capacity = CapacityField("ProvidedCapacity")
|
||||||
|
"""The amount of space that has been provided from the ProvidingDrives,
|
||||||
|
ProvidingVolumes, ProvidingMemory or ProvidingPools.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# TODO(lin.yang): Add property for references in CapacitySource resource
|
||||||
|
|
||||||
|
@property
|
||||||
|
@utils.cache_it
|
||||||
|
def providing_volumes(self):
|
||||||
|
"""Property to provide reference to `VolumeCollection` instance
|
||||||
|
|
||||||
|
It is calculated once when it is queried for the first time. On
|
||||||
|
refresh, this property is reset.
|
||||||
|
"""
|
||||||
|
from rsd_lib.resources.v2_4.storage_service import volume
|
||||||
|
return volume.VolumeCollection(
|
||||||
|
self._conn,
|
||||||
|
utils.get_sub_resource_path_by(self, "ProvidingVolumes"),
|
||||||
|
redfish_version=self.redfish_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@utils.cache_it
|
||||||
|
def providing_pools(self):
|
||||||
|
"""Property to provide reference to `StoragePoolCollection` instance
|
||||||
|
|
||||||
|
It is calculated once when it is queried for the first time. On
|
||||||
|
refresh, this property is reset.
|
||||||
|
"""
|
||||||
|
return storage_pool.StoragePoolCollection(
|
||||||
|
self._conn,
|
||||||
|
utils.get_sub_resource_path_by(self, "ProvidingPools"),
|
||||||
|
redfish_version=self.redfish_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@utils.cache_it
|
||||||
|
def providing_drives(self):
|
||||||
|
"""Property to provide reference to `DriveCollection` instance
|
||||||
|
|
||||||
|
It is calculated once when it is queried for the first time. On
|
||||||
|
refresh, this property is reset.
|
||||||
|
"""
|
||||||
|
return drive.DriveCollection(
|
||||||
|
self._conn,
|
||||||
|
utils.get_sub_resource_path_by(self, "ProvidingDrives"),
|
||||||
|
redfish_version=self.redfish_version,
|
||||||
|
)
|
@ -14,11 +14,29 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from sushy import exceptions
|
from sushy import exceptions
|
||||||
|
from sushy import utils
|
||||||
|
|
||||||
from rsd_lib.resources.v2_3.storage_service import volume
|
from rsd_lib.resources.v2_3.storage_service import volume
|
||||||
|
from rsd_lib.resources.v2_4.storage_service import capacity
|
||||||
|
|
||||||
|
|
||||||
class Volume(volume.Volume):
|
class Volume(volume.Volume):
|
||||||
|
@property
|
||||||
|
@utils.cache_it
|
||||||
|
def capacity_sources(self):
|
||||||
|
"""Property to provide a list of `CapacitySource` instance
|
||||||
|
|
||||||
|
It is calculated once when it is queried for the first time. On
|
||||||
|
refresh, this property is reset.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
capacity.CapacitySource(
|
||||||
|
self._conn, path, redfish_version=self.redfish_version
|
||||||
|
)
|
||||||
|
for path in utils.get_sub_resource_path_by(
|
||||||
|
self, "CapacitySources", is_collection=True
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
def resize(self, num_bytes):
|
def resize(self, num_bytes):
|
||||||
"""Update volume properties
|
"""Update volume properties
|
||||||
@ -27,20 +45,21 @@ class Volume(volume.Volume):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(num_bytes, int):
|
if not isinstance(num_bytes, int):
|
||||||
raise exceptions.InvalidParameterValueError(
|
raise exceptions.InvalidParameterValueError(
|
||||||
parameter='num_bytes', value=num_bytes,
|
parameter="num_bytes", value=num_bytes, valid_values="integer"
|
||||||
valid_values='integer')
|
)
|
||||||
|
|
||||||
if self.capacity_bytes and num_bytes <= self.capacity_bytes:
|
if self.capacity_bytes and num_bytes <= self.capacity_bytes:
|
||||||
raise exceptions.InvalidParameterValueError(
|
raise exceptions.InvalidParameterValueError(
|
||||||
parameter='num_bytes', value=num_bytes,
|
parameter="num_bytes",
|
||||||
valid_values='> {0}'.format(self.capacity_bytes))
|
value=num_bytes,
|
||||||
|
valid_values="> {0}".format(self.capacity_bytes),
|
||||||
|
)
|
||||||
|
|
||||||
data = {"Capacity": {"Data": {'AllocatedBytes': num_bytes}}}
|
data = {"Capacity": {"Data": {"AllocatedBytes": num_bytes}}}
|
||||||
self._conn.patch(self.path, data=data)
|
self._conn.patch(self.path, data=data)
|
||||||
|
|
||||||
|
|
||||||
class VolumeCollection(volume.VolumeCollection):
|
class VolumeCollection(volume.VolumeCollection):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _resource_type(self):
|
def _resource_type(self):
|
||||||
return Volume
|
return Volume
|
||||||
|
28
rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json
Normal file
28
rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#Capacity.CapacitySource",
|
||||||
|
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/1/CapacitySources/1",
|
||||||
|
"@odata.type": "#Capacity.v1_1_0.CapacitySource",
|
||||||
|
"Description": "Volume capacity source",
|
||||||
|
"Id": "1",
|
||||||
|
"Name": "CapacitySource",
|
||||||
|
"ProvidingPools": {
|
||||||
|
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/1/CapacitySources/1/ProvidingPools"
|
||||||
|
},
|
||||||
|
"ProvidingVolumes": {
|
||||||
|
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/1/CapacitySources/1/ProvidingVolumes"
|
||||||
|
},
|
||||||
|
"ProvidingDrives": {
|
||||||
|
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/1/CapacitySources/1/ProvidingDrives"
|
||||||
|
},
|
||||||
|
"ProvidedCapacity": {
|
||||||
|
"Data": {
|
||||||
|
"AllocatedBytes": 3071983104
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Oem": {},
|
||||||
|
"Status": {
|
||||||
|
"Health": "OK",
|
||||||
|
"HealthRollup": "OK",
|
||||||
|
"State": "Enabled"
|
||||||
|
}
|
||||||
|
}
|
@ -26,19 +26,10 @@
|
|||||||
},
|
},
|
||||||
"CapacitySources": [
|
"CapacitySources": [
|
||||||
{
|
{
|
||||||
"ProvidingPools": [
|
"@odata.id": "/redfish/v1/StorageServices/NVMeoE1/Volumes/1/CapacitySources/1"
|
||||||
{
|
|
||||||
"@odata.id": "/redfish/v1/StorageServices/1/StoragePools/2"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ProvidedCapacity": {
|
|
||||||
"Data": {
|
|
||||||
"AllocatedBytes": 3071983104
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Identifiers": [
|
"Identifiers": [
|
||||||
{
|
{
|
||||||
"DurableName": "/dev/nvme1n1p1",
|
"DurableName": "/dev/nvme1n1p1",
|
||||||
"DurableNameFormat": "SystemPath"
|
"DurableNameFormat": "SystemPath"
|
||||||
|
@ -0,0 +1,224 @@
|
|||||||
|
# Copyright 2018 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
|
||||||
|
import testtools
|
||||||
|
|
||||||
|
from rsd_lib.resources.v2_3.storage_service import drive
|
||||||
|
from rsd_lib.resources.v2_3.storage_service import storage_pool
|
||||||
|
from rsd_lib.resources.v2_4.storage_service import capacity
|
||||||
|
from rsd_lib.resources.v2_4.storage_service import volume
|
||||||
|
|
||||||
|
|
||||||
|
class CapacitySourceTestCase(testtools.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(CapacitySourceTestCase, self).setUp()
|
||||||
|
self.conn = mock.Mock()
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.capacity_sources_inst = capacity.CapacitySource(
|
||||||
|
self.conn,
|
||||||
|
"/redfish/v1/StorageServices/1/Volumes/1/CapacitySources/1",
|
||||||
|
redfish_version="1.0.2",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test__parse_attributes(self):
|
||||||
|
self.capacity_sources_inst._parse_attributes()
|
||||||
|
self.assertEqual("1.0.2", self.capacity_sources_inst.redfish_version)
|
||||||
|
self.assertEqual(
|
||||||
|
"Volume capacity source", self.capacity_sources_inst.description
|
||||||
|
)
|
||||||
|
self.assertEqual("1", self.capacity_sources_inst.identity)
|
||||||
|
self.assertEqual("CapacitySource", self.capacity_sources_inst.name)
|
||||||
|
self.assertEqual(
|
||||||
|
3071983104,
|
||||||
|
self.capacity_sources_inst.provided_capacity.data.allocated_bytes,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_providing_volumes(self):
|
||||||
|
# | GIVEN |
|
||||||
|
self.conn.get.return_value.json.reset_mock()
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/volume_collection.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN |
|
||||||
|
actual_providing_volumes = self.capacity_sources_inst.providing_volumes
|
||||||
|
# | THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
actual_providing_volumes, volume.VolumeCollection
|
||||||
|
)
|
||||||
|
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_providing_volumes,
|
||||||
|
self.capacity_sources_inst.providing_volumes,
|
||||||
|
)
|
||||||
|
self.conn.get.return_value.json.assert_not_called()
|
||||||
|
|
||||||
|
def test_providing_volumes_on_refresh(self):
|
||||||
|
# | GIVEN |
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/volume_collection.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.capacity_sources_inst.providing_volumes,
|
||||||
|
volume.VolumeCollection,
|
||||||
|
)
|
||||||
|
|
||||||
|
# On refreshing the chassis instance...
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.capacity_sources_inst.invalidate()
|
||||||
|
self.capacity_sources_inst.refresh(force=False)
|
||||||
|
|
||||||
|
# | GIVEN |
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/volume_collection.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.capacity_sources_inst.providing_volumes,
|
||||||
|
volume.VolumeCollection,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_providing_pools(self):
|
||||||
|
# | GIVEN |
|
||||||
|
self.conn.get.return_value.json.reset_mock()
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_3/"
|
||||||
|
"storage_pool_collection.json",
|
||||||
|
"r",
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN |
|
||||||
|
actual_providing_pools = self.capacity_sources_inst.providing_pools
|
||||||
|
# | THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
actual_providing_pools, storage_pool.StoragePoolCollection
|
||||||
|
)
|
||||||
|
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_providing_pools, self.capacity_sources_inst.providing_pools
|
||||||
|
)
|
||||||
|
self.conn.get.return_value.json.assert_not_called()
|
||||||
|
|
||||||
|
def test_providing_pools_on_refresh(self):
|
||||||
|
# | GIVEN |
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_3/"
|
||||||
|
"storage_pool_collection.json",
|
||||||
|
"r",
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.capacity_sources_inst.providing_pools,
|
||||||
|
storage_pool.StoragePoolCollection,
|
||||||
|
)
|
||||||
|
|
||||||
|
# On refreshing the chassis instance...
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.capacity_sources_inst.invalidate()
|
||||||
|
self.capacity_sources_inst.refresh(force=False)
|
||||||
|
|
||||||
|
# | GIVEN |
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_3/"
|
||||||
|
"storage_pool_collection.json",
|
||||||
|
"r",
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.capacity_sources_inst.providing_pools,
|
||||||
|
storage_pool.StoragePoolCollection,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_providing_drives(self):
|
||||||
|
# | GIVEN |
|
||||||
|
self.conn.get.return_value.json.reset_mock()
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_3/drive_collection.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN |
|
||||||
|
actual_providing_drives = self.capacity_sources_inst.providing_drives
|
||||||
|
# | THEN |
|
||||||
|
self.assertIsInstance(actual_providing_drives, drive.DriveCollection)
|
||||||
|
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_providing_drives,
|
||||||
|
self.capacity_sources_inst.providing_drives,
|
||||||
|
)
|
||||||
|
self.conn.get.return_value.json.assert_not_called()
|
||||||
|
|
||||||
|
def test_providing_drives_on_refresh(self):
|
||||||
|
# | GIVEN |
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_3/drive_collection.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.capacity_sources_inst.providing_drives, drive.DriveCollection
|
||||||
|
)
|
||||||
|
|
||||||
|
# On refreshing the chassis instance...
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.capacity_sources_inst.invalidate()
|
||||||
|
self.capacity_sources_inst.refresh(force=False)
|
||||||
|
|
||||||
|
# | GIVEN |
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_3/drive_collection.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.capacity_sources_inst.providing_drives, drive.DriveCollection
|
||||||
|
)
|
@ -19,125 +19,200 @@ import testtools
|
|||||||
|
|
||||||
from sushy import exceptions
|
from sushy import exceptions
|
||||||
|
|
||||||
|
from rsd_lib.resources.v2_4.storage_service import capacity
|
||||||
from rsd_lib.resources.v2_4.storage_service import volume
|
from rsd_lib.resources.v2_4.storage_service import volume
|
||||||
|
|
||||||
|
|
||||||
class StorageServiceTestCase(testtools.TestCase):
|
class StorageServiceTestCase(testtools.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(StorageServiceTestCase, self).setUp()
|
super(StorageServiceTestCase, self).setUp()
|
||||||
self.conn = mock.Mock()
|
self.conn = mock.Mock()
|
||||||
with open('rsd_lib/tests/unit/json_samples/v2_3/volume.json',
|
with open(
|
||||||
'r') as f:
|
"rsd_lib/tests/unit/json_samples/v2_4/volume.json", "r"
|
||||||
|
) as f:
|
||||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
self.volume_inst = volume.Volume(
|
self.volume_inst = volume.Volume(
|
||||||
self.conn, '/redfish/v1/StorageServices/NVMeoE1/Volumes/1',
|
self.conn,
|
||||||
redfish_version='1.0.2')
|
"/redfish/v1/StorageServices/NVMeoE1/Volumes/1",
|
||||||
|
redfish_version="1.0.2",
|
||||||
|
)
|
||||||
|
|
||||||
def test__parse_attributes(self):
|
def test__parse_attributes(self):
|
||||||
self.volume_inst._parse_attributes()
|
self.volume_inst._parse_attributes()
|
||||||
self.assertEqual('1.0.2', self.volume_inst.redfish_version)
|
self.assertEqual("1.0.2", self.volume_inst.redfish_version)
|
||||||
self.assertEqual('Volume description', self.volume_inst.description)
|
self.assertEqual("Volume description", self.volume_inst.description)
|
||||||
self.assertEqual('1', self.volume_inst.identity)
|
self.assertEqual("1", self.volume_inst.identity)
|
||||||
self.assertEqual('NVMe remote storage', self.volume_inst.name)
|
self.assertEqual("NVMe remote storage", self.volume_inst.name)
|
||||||
self.assertEqual('Enabled', self.volume_inst.status.state)
|
self.assertEqual("Enabled", self.volume_inst.status.state)
|
||||||
self.assertEqual('OK', self.volume_inst.status.health)
|
self.assertEqual("OK", self.volume_inst.status.health)
|
||||||
self.assertEqual('OK', self.volume_inst.status.health_rollup)
|
self.assertEqual("OK", self.volume_inst.status.health_rollup)
|
||||||
self.assertIsNone(self.volume_inst.model)
|
self.assertIsNone(self.volume_inst.model)
|
||||||
self.assertIsNone(self.volume_inst.manufacturer)
|
self.assertIsNone(self.volume_inst.manufacturer)
|
||||||
self.assertEqual(['Read', 'Write'],
|
self.assertEqual(
|
||||||
self.volume_inst.access_capabilities)
|
["Read", "Write"], self.volume_inst.access_capabilities
|
||||||
|
)
|
||||||
self.assertEqual(3071983104, self.volume_inst.capacity_bytes)
|
self.assertEqual(3071983104, self.volume_inst.capacity_bytes)
|
||||||
self.assertEqual(3071983104, self.volume_inst.allocated_Bytes)
|
self.assertEqual(3071983104, self.volume_inst.allocated_Bytes)
|
||||||
self.assertEqual(('/redfish/v1/StorageServices/1/StoragePools/2',),
|
|
||||||
self.volume_inst.capacity_sources[0].providing_pools)
|
|
||||||
self.assertEqual(3071983104,
|
|
||||||
self.volume_inst.capacity_sources[0].allocated_Bytes)
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'/dev/nvme1n1p1',
|
"/dev/nvme1n1p1", self.volume_inst.identifiers[0].durable_name
|
||||||
self.volume_inst.identifiers[0].durable_name)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'SystemPath',
|
"SystemPath", self.volume_inst.identifiers[0].durable_name_format
|
||||||
self.volume_inst.identifiers[0].durable_name_format)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'iqn.2001-04.com.example:diskarrays-sn-a8675309',
|
"iqn.2001-04.com.example:diskarrays-sn-a8675309",
|
||||||
self.volume_inst.identifiers[1].durable_name)
|
self.volume_inst.identifiers[1].durable_name,
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'iQN',
|
"iQN", self.volume_inst.identifiers[1].durable_name_format
|
||||||
self.volume_inst.identifiers[1].durable_name_format)
|
)
|
||||||
self.assertEqual(('/redfish/v1/Fabrics/NVMeoE/Endpoints/1',),
|
|
||||||
self.volume_inst.links.endpoints)
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'/redfish/v1/StorageServices/NVMeoE1/Volumes/1/Metrics',
|
("/redfish/v1/Fabrics/NVMeoE/Endpoints/1",),
|
||||||
self.volume_inst.links.metrics)
|
self.volume_inst.links.endpoints,
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'SourceElement',
|
"/redfish/v1/StorageServices/NVMeoE1/Volumes/1/Metrics",
|
||||||
self.volume_inst.replica_infos[0].replica_readonly_access)
|
self.volume_inst.links.metrics,
|
||||||
self.assertEqual('Snapshot',
|
)
|
||||||
self.volume_inst.replica_infos[0].replica_type)
|
self.assertEqual(
|
||||||
self.assertEqual('Target',
|
"SourceElement",
|
||||||
self.volume_inst.replica_infos[0].replica_role)
|
self.volume_inst.replica_infos[0].replica_readonly_access,
|
||||||
self.assertEqual('/redfish/v1/StorageServices/NVMeoE1/Volumes/2',
|
)
|
||||||
self.volume_inst.replica_infos[0].replica)
|
self.assertEqual(
|
||||||
|
"Snapshot", self.volume_inst.replica_infos[0].replica_type
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
"Target", self.volume_inst.replica_infos[0].replica_role
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
"/redfish/v1/StorageServices/NVMeoE1/Volumes/2",
|
||||||
|
self.volume_inst.replica_infos[0].replica,
|
||||||
|
)
|
||||||
self.assertEqual(False, self.volume_inst.bootable)
|
self.assertEqual(False, self.volume_inst.bootable)
|
||||||
self.assertIsNone(self.volume_inst.erased)
|
self.assertIsNone(self.volume_inst.erased)
|
||||||
self.assertEqual(True, self.volume_inst.erase_on_detach)
|
self.assertEqual(True, self.volume_inst.erase_on_detach)
|
||||||
|
|
||||||
|
def test_capacity_sources(self):
|
||||||
|
# | GIVEN |
|
||||||
|
self.conn.get.return_value.json.reset_mock()
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN |
|
||||||
|
actual_capacity_sources = self.volume_inst.capacity_sources
|
||||||
|
# | THEN |
|
||||||
|
self.assertIsInstance(actual_capacity_sources, list)
|
||||||
|
self.assertIsInstance(
|
||||||
|
actual_capacity_sources[0], capacity.CapacitySource
|
||||||
|
)
|
||||||
|
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_capacity_sources, self.volume_inst.capacity_sources
|
||||||
|
)
|
||||||
|
self.conn.get.return_value.json.assert_not_called()
|
||||||
|
|
||||||
|
def test_capacity_sources_on_refresh(self):
|
||||||
|
# | GIVEN |
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(self.volume_inst.capacity_sources, list)
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.volume_inst.capacity_sources[0], capacity.CapacitySource
|
||||||
|
)
|
||||||
|
|
||||||
|
# On refreshing the telemetry service instance...
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/volume.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.volume_inst.invalidate()
|
||||||
|
self.volume_inst.refresh(force=False)
|
||||||
|
|
||||||
|
# | GIVEN |
|
||||||
|
with open(
|
||||||
|
"rsd_lib/tests/unit/json_samples/v2_4/capacity_sources.json", "r"
|
||||||
|
) as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(self.volume_inst.capacity_sources, list)
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.volume_inst.capacity_sources[0], capacity.CapacitySource
|
||||||
|
)
|
||||||
|
|
||||||
def test_resize_volume(self):
|
def test_resize_volume(self):
|
||||||
self.volume_inst.resize(3071983105)
|
self.volume_inst.resize(3071983105)
|
||||||
self.volume_inst._conn.patch.assert_called_once_with(
|
self.volume_inst._conn.patch.assert_called_once_with(
|
||||||
'/redfish/v1/StorageServices/NVMeoE1/Volumes/1',
|
"/redfish/v1/StorageServices/NVMeoE1/Volumes/1",
|
||||||
data={"Capacity": {"Data": {'AllocatedBytes': 3071983105}}})
|
data={"Capacity": {"Data": {"AllocatedBytes": 3071983105}}},
|
||||||
|
)
|
||||||
|
|
||||||
def test_update_volume_with_invalid_parameter(self):
|
def test_update_volume_with_invalid_parameter(self):
|
||||||
with self.assertRaisesRegex(
|
with self.assertRaisesRegex(
|
||||||
exceptions.InvalidParameterValueError,
|
exceptions.InvalidParameterValueError,
|
||||||
'The parameter "num_bytes" value "fake-value" is invalid'):
|
'The parameter "num_bytes" value "fake-value" is invalid',
|
||||||
self.volume_inst.resize('fake-value')
|
):
|
||||||
|
self.volume_inst.resize("fake-value")
|
||||||
|
|
||||||
with self.assertRaisesRegex(
|
with self.assertRaisesRegex(
|
||||||
exceptions.InvalidParameterValueError,
|
exceptions.InvalidParameterValueError,
|
||||||
'The parameter "num_bytes" value "1024" is invalid'):
|
'The parameter "num_bytes" value "1024" is invalid',
|
||||||
|
):
|
||||||
self.volume_inst.resize(1024)
|
self.volume_inst.resize(1024)
|
||||||
|
|
||||||
|
|
||||||
class VolumeCollectionTestCase(testtools.TestCase):
|
class VolumeCollectionTestCase(testtools.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(VolumeCollectionTestCase, self).setUp()
|
super(VolumeCollectionTestCase, self).setUp()
|
||||||
self.conn = mock.Mock()
|
self.conn = mock.Mock()
|
||||||
with open('rsd_lib/tests/unit/json_samples/v2_4/'
|
with open(
|
||||||
'volume_collection.json', 'r') as f:
|
"rsd_lib/tests/unit/json_samples/v2_4/volume_collection.json", "r"
|
||||||
|
) as f:
|
||||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
self.volume_col = volume.VolumeCollection(
|
self.volume_col = volume.VolumeCollection(
|
||||||
self.conn, '/redfish/v1/StorageServices/NVMeoE1/Volumes',
|
self.conn,
|
||||||
redfish_version='1.0.2')
|
"/redfish/v1/StorageServices/NVMeoE1/Volumes",
|
||||||
|
redfish_version="1.0.2",
|
||||||
|
)
|
||||||
|
|
||||||
def test__parse_attributes(self):
|
def test__parse_attributes(self):
|
||||||
self.volume_col._parse_attributes()
|
self.volume_col._parse_attributes()
|
||||||
self.assertEqual('1.0.2', self.volume_col.redfish_version)
|
self.assertEqual("1.0.2", self.volume_col.redfish_version)
|
||||||
self.assertEqual('Volume Collection',
|
self.assertEqual("Volume Collection", self.volume_col.name)
|
||||||
self.volume_col.name)
|
self.assertEqual(
|
||||||
self.assertEqual(('/redfish/v1/StorageServices/NVMeoE1/Volumes/1',),
|
("/redfish/v1/StorageServices/NVMeoE1/Volumes/1",),
|
||||||
self.volume_col.members_identities)
|
self.volume_col.members_identities,
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(volume, 'Volume', autospec=True)
|
@mock.patch.object(volume, "Volume", autospec=True)
|
||||||
def test_get_member(self, mock_volume):
|
def test_get_member(self, mock_volume):
|
||||||
self.volume_col.get_member(
|
self.volume_col.get_member(
|
||||||
'/redfish/v1/StorageServices/NVMeoE1/Volumes/1')
|
"/redfish/v1/StorageServices/NVMeoE1/Volumes/1"
|
||||||
|
)
|
||||||
mock_volume.assert_called_once_with(
|
mock_volume.assert_called_once_with(
|
||||||
self.volume_col._conn,
|
self.volume_col._conn,
|
||||||
'/redfish/v1/StorageServices/NVMeoE1/Volumes/1',
|
"/redfish/v1/StorageServices/NVMeoE1/Volumes/1",
|
||||||
redfish_version=self.volume_col.redfish_version)
|
redfish_version=self.volume_col.redfish_version,
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(volume, 'Volume', autospec=True)
|
@mock.patch.object(volume, "Volume", autospec=True)
|
||||||
def test_get_members(self, mock_volume):
|
def test_get_members(self, mock_volume):
|
||||||
members = self.volume_col.get_members()
|
members = self.volume_col.get_members()
|
||||||
mock_volume.assert_called_once_with(
|
mock_volume.assert_called_once_with(
|
||||||
self.volume_col._conn,
|
self.volume_col._conn,
|
||||||
'/redfish/v1/StorageServices/NVMeoE1/Volumes/1',
|
"/redfish/v1/StorageServices/NVMeoE1/Volumes/1",
|
||||||
redfish_version=self.volume_col.redfish_version)
|
redfish_version=self.volume_col.redfish_version,
|
||||||
|
)
|
||||||
self.assertIsInstance(members, list)
|
self.assertIsInstance(members, list)
|
||||||
self.assertEqual(1, len(members))
|
self.assertEqual(1, len(members))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user