Merge "Add support for the `CompositionService` resource"
This commit is contained in:
commit
fb465bc3e0
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for the CompositionService resource to the library.
|
||||
|
||||
The `CompositionService` is the top level resource for all things
|
||||
related to Composability. If a Redfish service supports Composability,
|
||||
the Service Root resource will contain the `CompositionService` property.
|
|
@ -19,6 +19,7 @@ from sushy import connector as sushy_connector
|
|||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources.chassis import chassis
|
||||
from sushy.resources.compositionservice import compositionservice
|
||||
from sushy.resources.manager import manager
|
||||
from sushy.resources.registry import message_registry_file
|
||||
from sushy.resources.sessionservice import session
|
||||
|
@ -65,6 +66,10 @@ class Sushy(base.ResourceBase):
|
|||
'ProtocolFeaturesSupported')
|
||||
"""The information about protocol features supported by the service"""
|
||||
|
||||
_composition_service_path = base.Field(
|
||||
['CompositionService', '@odata.id'])
|
||||
"""CompositionService path"""
|
||||
|
||||
_systems_path = base.Field(['Systems', '@odata.id'])
|
||||
"""SystemCollection path"""
|
||||
|
||||
|
@ -257,3 +262,18 @@ class Sushy(base.ResourceBase):
|
|||
self._conn,
|
||||
self._registries_path,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def get_composition_service(self):
|
||||
"""Get the CompositionService object
|
||||
|
||||
:raises: MissingAttributeError, if the composition service
|
||||
attribute is not found
|
||||
:returns: The CompositionService object
|
||||
"""
|
||||
if not self._composition_service_path:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='CompositionService/@odata.id',
|
||||
resource=self._path)
|
||||
return compositionservice.CompositionService(
|
||||
self._conn, self._composition_service_path,
|
||||
redfish_version=self.redfish_version)
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This is referred from Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/CompositionService.v1_1_0.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
from sushy.resources.compositionservice import resourceblock
|
||||
from sushy.resources.compositionservice import resourcezone
|
||||
from sushy import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CompositionService(base.ResourceBase):
|
||||
|
||||
allow_overprovisioning = base.Field('AllowOverprovisioning')
|
||||
"""This indicates whether this service is allowed to overprovision"""
|
||||
|
||||
allow_zone_affinity = base.Field('AllowZoneAffinity')
|
||||
"""This indicates whether a client is allowed to request that given
|
||||
composition request"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The composition service description"""
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The composition service identity string"""
|
||||
|
||||
name = base.Field('Name', required=True)
|
||||
"""The composition service name"""
|
||||
|
||||
status = common.StatusField('Status')
|
||||
"""The status of composition service"""
|
||||
|
||||
service_enabled = base.Field('ServiceEnabled')
|
||||
"""The status of composition service is enabled"""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a CompositionService
|
||||
|
||||
:param connector: A connector instance
|
||||
:param identity: The identity of the CompositionService resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version
|
||||
"""
|
||||
super(CompositionService, self).__init__(
|
||||
connector,
|
||||
identity,
|
||||
redfish_version)
|
||||
|
||||
def _get_resource_blocks_collection_path(self):
|
||||
"""Helper function to find the ResourceBlockCollections path"""
|
||||
res_block_col = self.json.get('ResourceBlocks')
|
||||
if not res_block_col:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='ResourceBlocks', resource=self._path)
|
||||
return res_block_col.get('@odata.id')
|
||||
|
||||
def _get_resource_zones_collection_path(self):
|
||||
"""Helper function to find the ResourceZoneCollections path"""
|
||||
res_zone_col = self.json.get('ResourceZones')
|
||||
if not res_zone_col:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='ResourceZones', resource=self._path)
|
||||
return res_zone_col.get('@odata.id')
|
||||
|
||||
@property
|
||||
@utils.cache_it
|
||||
def resource_blocks(self):
|
||||
"""Property to reference `ResourceBlockCollection` instance"""
|
||||
return resourceblock.ResourceBlockCollection(
|
||||
self.conn, self._get_resource_blocks_collection_path,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
@property
|
||||
@utils.cache_it
|
||||
def resource_zones(self):
|
||||
"""Property to reference `ResourceZoneCollection` instance"""
|
||||
return resourcezone.ResourceZoneCollection(
|
||||
self.conn, self._get_resource_zones_collection_path,
|
||||
redfish_version=self.redfish_version)
|
|
@ -0,0 +1,31 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# Values come from the Redfish ResourceBlock json-schema.
|
||||
# https://redfish.dmtf.org/schemas/ResourceBlock.v1_3_0.json
|
||||
|
||||
# Composition state related constants
|
||||
COMPOSITION_STATE_COMPOSING = 'Composing'
|
||||
COMPOSITION_STATE_COMPOSED_AND_AVAILABLE = 'ComposedAndAvailable'
|
||||
COMPOSITION_STATE_COMPOSED = 'Composed'
|
||||
COMPOSITION_STATE_UNUSED = 'Unused'
|
||||
COMPOSITION_STATE_FAILED = 'Failed'
|
||||
COMPOSITION_STATE_UNAVAILABLE = 'Unavailable'
|
||||
|
||||
# Resource Block type related constants
|
||||
RESOURCE_BLOCK_TYPE_COMPUTE = 'Compute'
|
||||
RESOURCE_BLOCK_TYPE_PROCESSOR = 'Processor'
|
||||
RESOURCE_BLOCK_TYPE_MEMORY = 'Memory'
|
||||
RESOURCE_BLOCK_TYPE_NETWORK = 'Network'
|
||||
RESOURCE_BLOCK_TYPE_STORAGE = 'Storage'
|
||||
RESOURCE_BLOCK_TYPE_COMPUTERSYSTEM = 'ComputerSystem'
|
||||
RESOURCE_BLOCK_TYPE_EXPANSION = 'Expansion'
|
|
@ -0,0 +1,40 @@
|
|||
# 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.compositionservice import constants as comp_cons
|
||||
from sushy import utils
|
||||
|
||||
|
||||
COMPOSITION_STATE_VALUE_MAP = {
|
||||
'Composing': comp_cons.COMPOSITION_STATE_COMPOSING,
|
||||
'ComposedAndAvailable': comp_cons.COMPOSITION_STATE_COMPOSED_AND_AVAILABLE,
|
||||
'Composed': comp_cons.COMPOSITION_STATE_COMPOSED,
|
||||
'Unused': comp_cons.COMPOSITION_STATE_UNUSED,
|
||||
'Failed': comp_cons.COMPOSITION_STATE_FAILED,
|
||||
'Unavailable': comp_cons.COMPOSITION_STATE_UNAVAILABLE
|
||||
}
|
||||
|
||||
COMPOSITION_STATE_VALUE_MAP_REV = (
|
||||
utils.revert_dictionary(COMPOSITION_STATE_VALUE_MAP))
|
||||
|
||||
RESOURCE_BLOCK_TYPE_VALUE_MAP = {
|
||||
'Compute': comp_cons.RESOURCE_BLOCK_TYPE_COMPUTE,
|
||||
'Processor': comp_cons.RESOURCE_BLOCK_TYPE_PROCESSOR,
|
||||
'Memory': comp_cons.RESOURCE_BLOCK_TYPE_MEMORY,
|
||||
'Network': comp_cons.RESOURCE_BLOCK_TYPE_NETWORK,
|
||||
'Storage': comp_cons.RESOURCE_BLOCK_TYPE_STORAGE,
|
||||
'ComputerSystem': comp_cons.RESOURCE_BLOCK_TYPE_COMPUTERSYSTEM,
|
||||
'Expansion': comp_cons.RESOURCE_BLOCK_TYPE_EXPANSION
|
||||
}
|
||||
|
||||
RESOURCE_BLOCK_TYPE_VALUE_MAP_REV = (
|
||||
utils.revert_dictionary(RESOURCE_BLOCK_TYPE_VALUE_MAP))
|
|
@ -0,0 +1,112 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This is referred from Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/ResourceBlock.v1_1_0.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
from sushy.resources.compositionservice import mappings as res_maps
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CompositionStatusField(base.CompositeField):
|
||||
|
||||
composition_state = base.MappedField(
|
||||
'CompositionState',
|
||||
res_maps.COMPOSITION_STATE_VALUE_MAP,
|
||||
required=True)
|
||||
"""Inform the client, state of the resource block"""
|
||||
|
||||
max_compositions = base.Field('MaxCompositions')
|
||||
"""The maximum number of compositions"""
|
||||
|
||||
number_of_compositions = base.Field('NumberOfCompositions')
|
||||
"""The number of compositions"""
|
||||
|
||||
reserved_state = base.Field('Reserved')
|
||||
"""Inform the resource block has been identified by a client"""
|
||||
|
||||
sharing_capable = base.Field('SharingCapable')
|
||||
"""Indicates if this Resource Block is capable of participating in
|
||||
multiple compositions simultaneously"""
|
||||
|
||||
sharing_enabled = base.Field('SharingEnabled')
|
||||
"""Indicates if this Resource Block is allowed to participate in
|
||||
multiple compositions simultaneously"""
|
||||
|
||||
|
||||
class ResourceBlock(base.ResourceBase):
|
||||
|
||||
composition_status = CompositionStatusField(
|
||||
'CompositionStatus',
|
||||
required=True)
|
||||
"""The composition state of resource block"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The resource block description"""
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The resource block identity string"""
|
||||
|
||||
name = base.Field('Name', required=True)
|
||||
"""The resource block name"""
|
||||
|
||||
resource_block_type = base.MappedField(
|
||||
'ResourceBlockType',
|
||||
res_maps.RESOURCE_BLOCK_TYPE_VALUE_MAP,
|
||||
required=True)
|
||||
"""The type of resource block"""
|
||||
|
||||
status = common.StatusField('Status')
|
||||
"""The status of resource block"""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a ResourceBlock
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the ResourceBlock resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version.
|
||||
"""
|
||||
super(ResourceBlock, self).__init__(
|
||||
connector,
|
||||
identity,
|
||||
redfish_version)
|
||||
|
||||
|
||||
class ResourceBlockCollection(base.ResourceCollectionBase):
|
||||
|
||||
name = base.Field('Name')
|
||||
"""The resource block collection name"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The resource block collection description"""
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return ResourceBlock
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a ResourceBlockCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: A identity of the ResourceBlock resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version.
|
||||
"""
|
||||
super(ResourceBlockCollection, self).__init__(
|
||||
connector, identity, redfish_version)
|
|
@ -0,0 +1,92 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This is referred from Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/Zone.v1_2_0.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LinksField(base.CompositeField):
|
||||
|
||||
endpoints = base.Field('Endpoints')
|
||||
"""The references to the endpoints that are contained in this zone"""
|
||||
|
||||
involved_switches = base.Field('InvolvedSwitches')
|
||||
"""The references to the switches in this zone"""
|
||||
|
||||
resource_blocks = base.Field('ResourceBlocks')
|
||||
"""The references to the Resource Blocks that are used in this zone"""
|
||||
|
||||
|
||||
class ResourceZone(base.ResourceBase):
|
||||
|
||||
# Note(dnuka): This patch doesn't contain 100% of the ResourceZone
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The resources zone description"""
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The resource zone identity string"""
|
||||
|
||||
links = LinksField('Links')
|
||||
"""The references to other resources that are related to this
|
||||
resource"""
|
||||
|
||||
name = base.Field('Name', required=True)
|
||||
"""The resource zone name"""
|
||||
|
||||
status = common.StatusField('Status')
|
||||
"""The resource zone status"""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a ResourceZone
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the ResourceZone resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version.
|
||||
"""
|
||||
super(ResourceZone, self).__init__(
|
||||
connector,
|
||||
identity,
|
||||
redfish_version)
|
||||
|
||||
|
||||
class ResourceZoneCollection(base.ResourceCollectionBase):
|
||||
|
||||
name = base.Field('Name')
|
||||
"""The resource zone collection name"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The resource zone collection description"""
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return ResourceZone
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a ResourceZoneCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the ResourceZone resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version.
|
||||
"""
|
||||
super(ResourceZoneCollection, self).__init__(
|
||||
connector, identity, redfish_version)
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#CompositionService.CompositionService",
|
||||
"@odata.type": "#CompositionService.v1_1_0.CompositionService",
|
||||
"@odata.id": "/redfish/v1/CompositionService",
|
||||
"AllowOverprovisioning": false,
|
||||
"AllowZoneAffinity": true,
|
||||
"Description": "CompositionService1",
|
||||
"Id": "CompositionService",
|
||||
"Name": "Composition Service",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"ServiceEnabled": true,
|
||||
"ResourceBlocks": {
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks"
|
||||
},
|
||||
"ResourceZones": {
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceZones"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#ResourceBlock.ResourceBlock",
|
||||
"@odata.type": "#ResourceBlock.v1_3_0.ResourceBlock",
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/DriveBlock3",
|
||||
"Id": "DriveBlock3",
|
||||
"Name": "Drive Block 3",
|
||||
"Description": "ResourceBlock1",
|
||||
"ResourceBlockType": "Storage",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"CompositionStatus": {
|
||||
"Reserved": false,
|
||||
"CompositionState": "Composed",
|
||||
"MaxCompositions": 1,
|
||||
"NumberOfCompositions": 0,
|
||||
"SharingCapable": true,
|
||||
"SharingEnabled": false
|
||||
},
|
||||
"Processors": [],
|
||||
"Memory": [],
|
||||
"Storage": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/DriveBlock3/Storage/Block3NVMe"
|
||||
}
|
||||
],
|
||||
"Links": {
|
||||
"ComputerSystems": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/ComposedSystem"
|
||||
}
|
||||
],
|
||||
"Chassis": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/ComposableModule3"
|
||||
}
|
||||
],
|
||||
"Zones": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceZones/1"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceZones/2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"@odata.type": "#ResourceBlockCollection.ResourceBlockCollection",
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks",
|
||||
"Name": "Resource Block Collection",
|
||||
"Members@odata.count": 1,
|
||||
"Members": [
|
||||
{ "@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/ComputeBlock1" }
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Zone.Zone",
|
||||
"@odata.type": "#Zone.v1_2_1.Zone",
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceZones/1",
|
||||
"Id": "1",
|
||||
"Name": "Resource Zone 1",
|
||||
"Description": "ResourceZone1",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"Links": {
|
||||
"ResourceBlocks": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/ComputeBlock1"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/DriveBlock3"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/DriveBlock4"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/DriveBlock5"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/DriveBlock6"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceBlocks/DriveBlock7"
|
||||
}
|
||||
]
|
||||
},
|
||||
"@Redfish.CollectionCapabilities": {
|
||||
"@odata.type": "#CollectionCapabilities.v1_0_0.CollectionCapabilities",
|
||||
"Capabilities": [
|
||||
{
|
||||
"CapabilitiesObject": {
|
||||
"@odata.id": "/redfish/v1/Systems/Capabilities"
|
||||
},
|
||||
"UseCase": "ComputerSystemComposition",
|
||||
"Links": {
|
||||
"TargetCollection": {
|
||||
"@odata.id": "/redfish/v1/Systems"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"@odata.type": "#ZoneCollection.ZoneCollection",
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceZones",
|
||||
"Name": "Resource Zone Collection",
|
||||
"Members@odata.count": 1,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/CompositionService/ResourceZones/1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -33,6 +33,9 @@
|
|||
"AccountService": {
|
||||
"@odata.id": "/redfish/v1/AccountService"
|
||||
},
|
||||
"CompositionService": {
|
||||
"@odata.id": "/redfish/v1/CompositionService"
|
||||
},
|
||||
"EventService": {
|
||||
"@odata.id": "/redfish/v1/EventService"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# 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.resources.compositionservice import compositionservice
|
||||
from sushy.resources import constants as res_cons
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class CompositionServiceTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CompositionServiceTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open(
|
||||
'sushy/tests/unit/json_samples/compositionservice.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.comp_ser = compositionservice.CompositionService(
|
||||
self.conn,
|
||||
'/redfish/v1/CompositionService',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.comp_ser._parse_attributes()
|
||||
self.assertFalse(self.comp_ser.allow_overprovisioning)
|
||||
self.assertTrue(self.comp_ser.allow_zone_affinity)
|
||||
self.assertTrue(self.comp_ser.description, 'CompositionService1')
|
||||
self.assertEqual(
|
||||
'CompositionService',
|
||||
self.comp_ser.identity)
|
||||
self.assertEqual(
|
||||
'Composition Service',
|
||||
self.comp_ser.name)
|
||||
self.assertEqual(res_cons.STATE_ENABLED, self.comp_ser.status.state)
|
||||
self.assertEqual(res_cons.HEALTH_OK, self.comp_ser.status.health)
|
||||
self.assertTrue(self.comp_ser.service_enabled)
|
|
@ -0,0 +1,107 @@
|
|||
# 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
|
||||
from sushy.resources.compositionservice import constants as res_block_cons
|
||||
from sushy.resources.compositionservice import resourceblock
|
||||
from sushy.resources import constants as res_cons
|
||||
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class ResourceBlockTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ResourceBlockTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/resourceblock.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.res_block = resourceblock.ResourceBlock(
|
||||
self.conn,
|
||||
'/redfish/v1/CompositionService/ResourceBlocks/DriveBlock3',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.res_block._parse_attributes()
|
||||
self.assertEqual(
|
||||
res_block_cons.COMPOSITION_STATE_COMPOSED,
|
||||
self.res_block.composition_status.composition_state)
|
||||
self.assertEqual(1, self.res_block.composition_status.max_compositions)
|
||||
self.assertEqual(
|
||||
0, self.res_block.composition_status.number_of_compositions)
|
||||
self.assertFalse(self.res_block.composition_status.reserved_state)
|
||||
self.assertTrue(self.res_block.composition_status.sharing_capable)
|
||||
self.assertFalse(self.res_block.composition_status.sharing_enabled)
|
||||
self.assertEqual('ResourceBlock1', self.res_block.description)
|
||||
self.assertEqual('DriveBlock3', self.res_block.identity)
|
||||
self.assertEqual('Drive Block 3', self.res_block.name)
|
||||
self.assertEqual(
|
||||
res_block_cons.RESOURCE_BLOCK_TYPE_STORAGE,
|
||||
self.res_block.resource_block_type)
|
||||
self.assertEqual(
|
||||
res_cons.STATE_ENABLED,
|
||||
self.res_block.status.state)
|
||||
self.assertEqual(res_cons.HEALTH_OK, self.res_block.status.health)
|
||||
exp_path = '/redfish/v1/CompositionService/ResourceBlocks/DriveBlock3'
|
||||
self.assertEqual(exp_path, self.res_block.path)
|
||||
|
||||
def test__parse_attributes_missing_identity(self):
|
||||
self.res_block.json.pop('Id')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Id',
|
||||
self.res_block._parse_attributes)
|
||||
|
||||
|
||||
class ResourceBlockCollectionTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ResourceBlockCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'resourceblock_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.res_block_col = resourceblock.ResourceBlockCollection(
|
||||
self.conn, '/redfish/v1/CompositionService/ResourceBlocks',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
path = '/redfish/v1/CompositionService/ResourceBlocks/ComputeBlock1'
|
||||
self.res_block_col._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.res_block_col.redfish_version)
|
||||
self.assertEqual(
|
||||
'Resource Block Collection',
|
||||
self.res_block_col.name)
|
||||
self.assertEqual((path,), self.res_block_col.members_identities)
|
||||
|
||||
@mock.patch.object(resourceblock, 'ResourceBlock', autospec=True)
|
||||
def test_get_member(self, mock_resourceblock):
|
||||
path = '/redfish/v1/CompositionService/ResourceBlocks/ComputeBlock1'
|
||||
self.res_block_col.get_member(path)
|
||||
mock_resourceblock.assert_called_once_with(
|
||||
self.res_block_col._conn, path,
|
||||
redfish_version=self.res_block_col.redfish_version)
|
||||
|
||||
@mock.patch.object(resourceblock, 'ResourceBlock', autospec=True)
|
||||
def test_get_members(self, mock_resourceblock):
|
||||
path = '/redfish/v1/CompositionService/ResourceBlocks/ComputeBlock1'
|
||||
members = self.res_block_col.get_members()
|
||||
mock_resourceblock.assert_called_once_with(
|
||||
self.res_block_col._conn, path,
|
||||
redfish_version=self.res_block_col.redfish_version)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(1, len(members))
|
|
@ -0,0 +1,93 @@
|
|||
# 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
|
||||
from sushy.resources.compositionservice import resourcezone
|
||||
from sushy.resources import constants as res_cons
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class ResourceZoneTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ResourceZoneTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/resourcezone.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.res_zone = resourcezone.ResourceZone(
|
||||
self.conn,
|
||||
'/redfish/v1/CompositionService/ResourceZones/1',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.res_zone._parse_attributes()
|
||||
self.assertEqual('ResourceZone1', self.res_zone.description)
|
||||
self.assertEqual('1', self.res_zone.identity)
|
||||
self.assertEqual('Resource Zone 1', self.res_zone.name)
|
||||
self.assertEqual(
|
||||
res_cons.STATE_ENABLED,
|
||||
self.res_zone.status.state)
|
||||
self.assertEqual(
|
||||
res_cons.HEALTH_OK,
|
||||
self.res_zone.status.health)
|
||||
exp_path = '/redfish/v1/CompositionService/ResourceZones/1'
|
||||
self.assertEqual(exp_path, self.res_zone.path)
|
||||
|
||||
def test__parse_attributes_missing_identity(self):
|
||||
self.res_zone.json.pop('Id')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Id',
|
||||
self.res_zone._parse_attributes)
|
||||
|
||||
|
||||
class ResourceZoneCollectionTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ResourceZoneCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'resourcezone_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.res_zone_col = resourcezone.ResourceZoneCollection(
|
||||
self.conn, '/redfish/v1/CompositionService/ResourceZones',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
path = '/redfish/v1/CompositionService/ResourceZones/1'
|
||||
self.res_zone_col._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.res_zone_col.redfish_version)
|
||||
self.assertEqual('Resource Zone Collection', self.res_zone_col.name)
|
||||
self.assertEqual((path,), self.res_zone_col.members_identities)
|
||||
|
||||
@mock.patch.object(resourcezone, 'ResourceZone', autospec=True)
|
||||
def test_get_member(self, mock_resourcezone):
|
||||
path = '/redfish/v1/CompositionService/ResourceZones/1'
|
||||
self.res_zone_col.get_member(path)
|
||||
mock_resourcezone.assert_called_once_with(
|
||||
self.res_zone_col._conn, path,
|
||||
redfish_version=self.res_zone_col.redfish_version)
|
||||
|
||||
@mock.patch.object(resourcezone, 'ResourceZone', autospec=True)
|
||||
def test_get_members(self, mock_resourcezone):
|
||||
path = '/redfish/v1/CompositionService/ResourceZones/1'
|
||||
members = self.res_zone_col.get_members()
|
||||
mock_resourcezone.assert_called_once_with(
|
||||
self.res_zone_col._conn, path,
|
||||
redfish_version=self.res_zone_col.redfish_version)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(1, len(members))
|
|
@ -22,6 +22,7 @@ from sushy import connector
|
|||
from sushy import exceptions
|
||||
from sushy import main
|
||||
from sushy.resources.chassis import chassis
|
||||
from sushy.resources.compositionservice import compositionservice
|
||||
from sushy.resources.manager import manager
|
||||
from sushy.resources.registry import message_registry_file
|
||||
from sushy.resources.sessionservice import session
|
||||
|
@ -69,6 +70,8 @@ class MainTestCase(base.TestCase):
|
|||
self.assertEqual('/redfish/v1/Chassis', self.root._chassis_path)
|
||||
self.assertEqual('/redfish/v1/SessionService',
|
||||
self.root._session_service_path)
|
||||
self.assertEqual('/redfish/v1/CompositionService',
|
||||
self.root._composition_service_path)
|
||||
|
||||
@mock.patch.object(connector, 'Connector', autospec=True)
|
||||
def test__init_throws_exception(self, mock_Connector):
|
||||
|
@ -161,6 +164,14 @@ class MainTestCase(base.TestCase):
|
|||
self.root._conn, '/redfish/v1/Registries',
|
||||
redfish_version=self.root.redfish_version)
|
||||
|
||||
@mock.patch.object(
|
||||
compositionservice, 'CompositionService', autospec=True)
|
||||
def test_get_composition_service(self, mock_comp_ser):
|
||||
self.root.get_composition_service()
|
||||
mock_comp_ser.assert_called_once_with(
|
||||
self.root._conn, '/redfish/v1/CompositionService',
|
||||
redfish_version=self.root.redfish_version)
|
||||
|
||||
|
||||
class BareMinimumMainTestCase(base.TestCase):
|
||||
|
||||
|
@ -198,5 +209,11 @@ class BareMinimumMainTestCase(base.TestCase):
|
|||
exceptions.MissingAttributeError,
|
||||
'UpdateService/@odata.id', self.root.get_update_service)
|
||||
|
||||
def test_get_composition_service_when_compositionservice_attr_absent(
|
||||
self):
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
'CompositionService/@odata.id', self.root.get_composition_service)
|
||||
|
||||
def test__get_registry_collection_when_registries_attr_absent(self):
|
||||
self.assertIsNone(self.root._get_registry_collection())
|
||||
|
|
Loading…
Reference in New Issue