Merge "Import sushy lib and extend it as well as show its usage for mutli-podm"
This commit is contained in:
commit
019d3e3f5f
@ -20,3 +20,4 @@ oslo.i18n>=2.1.0 # Apache-2.0
|
|||||||
python-ironicclient>=1.11.0 # Apache-2.0
|
python-ironicclient>=1.11.0 # Apache-2.0
|
||||||
python-keystoneclient>=3.8.0 # Apache-2.0
|
python-keystoneclient>=3.8.0 # Apache-2.0
|
||||||
stevedore>=1.20.0 # Apache-2.0
|
stevedore>=1.20.0 # Apache-2.0
|
||||||
|
sushy>=0.1.0 # Apache-2.0
|
||||||
|
0
valence/podmanagers/__init__.py
Normal file
0
valence/podmanagers/__init__.py
Normal file
54
valence/podmanagers/podm_base.py
Normal file
54
valence/podmanagers/podm_base.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# Copyright (c) 2016 Intel, Inc.
|
||||||
|
#
|
||||||
|
# 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 valence.redfish.sushy import sushy_instance
|
||||||
|
|
||||||
|
|
||||||
|
class PodManagerBase(object):
|
||||||
|
|
||||||
|
def __init__(self, username, password, podm_url):
|
||||||
|
self.podm_url = podm_url
|
||||||
|
self.driver = sushy_instance.RedfishInstance(username=username,
|
||||||
|
password=password,
|
||||||
|
base_url=podm_url)
|
||||||
|
|
||||||
|
def get_podm_info(self):
|
||||||
|
return self.get_resource_info_by_url(self.podm_url)
|
||||||
|
|
||||||
|
def get_resource_info_by_url(self, resource_url):
|
||||||
|
return self.driver.get_resources_by_url(resource_url)
|
||||||
|
|
||||||
|
def get_chassis_collection(self):
|
||||||
|
chassis_collection_url = self.podm_url + '/Chassis'
|
||||||
|
return self.driver.get_resources_by_url(chassis_collection_url)
|
||||||
|
|
||||||
|
def get_chassis_info(self, chassis_id):
|
||||||
|
chassis_url = self.podm_url + '/Chassis/' + chassis_id
|
||||||
|
return self.driver.get_resources_by_url(chassis_url)
|
||||||
|
|
||||||
|
def get_system_collection(self):
|
||||||
|
system_collection_url = self.podm_url + '/Systems'
|
||||||
|
return self.driver.get_resources_by_url(system_collection_url)
|
||||||
|
|
||||||
|
def get_system_info(self, system_id):
|
||||||
|
system_url = self.podm_url + '/Systems/' + system_id
|
||||||
|
return self.driver.get_resources_by_url(system_url)
|
||||||
|
|
||||||
|
def get_node_collection(self):
|
||||||
|
node_collection_url = self.podm_url + '/Nodes'
|
||||||
|
return self.driver.get_resources_by_url(node_collection_url)
|
||||||
|
|
||||||
|
def get_node_info(self, node_id):
|
||||||
|
node_url = self.podm_url + '/Nodes/' + node_id
|
||||||
|
return self.driver.get_resources_by_url(node_url)
|
0
valence/redfish/sushy/__init__.py
Normal file
0
valence/redfish/sushy/__init__.py
Normal file
0
valence/redfish/sushy/resources/__init__.py
Normal file
0
valence/redfish/sushy/resources/__init__.py
Normal file
83
valence/redfish/sushy/resources/chassis.py
Normal file
83
valence/redfish/sushy/resources/chassis.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Copyright 2017 Red Hat, 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 Chassis(base.ResourceBase):
|
||||||
|
asset_tag = base.Field('AssetTag')
|
||||||
|
"""The chassis asset tag"""
|
||||||
|
|
||||||
|
description = base.Field('Description')
|
||||||
|
"""The chassis description"""
|
||||||
|
|
||||||
|
identity = base.Field('Id', required=True)
|
||||||
|
"""The chassis identity string"""
|
||||||
|
|
||||||
|
manufacturer = base.Field('Manufacturer')
|
||||||
|
"""The chassis manufacturer"""
|
||||||
|
|
||||||
|
name = base.Field('Name')
|
||||||
|
"""The chassis name"""
|
||||||
|
|
||||||
|
part_number = base.Field('PartNumber')
|
||||||
|
"""The chassis part number"""
|
||||||
|
|
||||||
|
serial_number = base.Field('SerialNumber')
|
||||||
|
"""The chassis serial number"""
|
||||||
|
|
||||||
|
sku = base.Field('SKU')
|
||||||
|
"""The chassis stock-keeping unit"""
|
||||||
|
|
||||||
|
chassis_type = base.Field('ChassisType')
|
||||||
|
"""The chassis type"""
|
||||||
|
|
||||||
|
oem = base.Field('Oem')
|
||||||
|
"""The chassis oem options values (dict)"""
|
||||||
|
|
||||||
|
def __init__(self, connector, identity, redfish_version=None):
|
||||||
|
"""A class representing a Chassis
|
||||||
|
|
||||||
|
:param connector: A Connector instance
|
||||||
|
:param identity: The identity of the chassis resource
|
||||||
|
:param redfish_version: The version of RedFish. Used to construct
|
||||||
|
the object according to schema of the given version.
|
||||||
|
"""
|
||||||
|
super(Chassis, self).__init__(connector, identity, redfish_version)
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
super(Chassis, self).refresh()
|
||||||
|
|
||||||
|
|
||||||
|
class ChassisCollection(base.ResourceCollectionBase):
|
||||||
|
@property
|
||||||
|
def _resource_type(self):
|
||||||
|
return Chassis
|
||||||
|
|
||||||
|
def __init__(self, connector, path, redfish_version=None):
|
||||||
|
"""A class representing a ComputerchassisCollection
|
||||||
|
|
||||||
|
:param connector: A Connector instance
|
||||||
|
:param path: The canonical path to the chassis collection resource
|
||||||
|
:param redfish_version: The version of RedFish. Used to construct
|
||||||
|
the object according to schema of the given version.
|
||||||
|
"""
|
||||||
|
super(ChassisCollection, self).__init__(connector,
|
||||||
|
path,
|
||||||
|
redfish_version)
|
63
valence/redfish/sushy/sushy_instance.py
Normal file
63
valence/redfish/sushy/sushy_instance.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) 2016 Intel, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import sushy
|
||||||
|
from sushy import exceptions
|
||||||
|
|
||||||
|
from resources import chassis
|
||||||
|
|
||||||
|
|
||||||
|
class RedfishInstance(sushy.Sushy):
|
||||||
|
|
||||||
|
def __init__(self, base_url, username, password):
|
||||||
|
"""A class representing a Sushy Object Instance
|
||||||
|
|
||||||
|
:param base_url: The base URL to the Redfish controller. It
|
||||||
|
should include scheme and authority portion of the URL.
|
||||||
|
For example: https://valence.podm:443/
|
||||||
|
:param username: User account with admin/server-profile access
|
||||||
|
privilege
|
||||||
|
:param password: User account password
|
||||||
|
"""
|
||||||
|
super(RedfishInstance, self).__init__(base_url=base_url,
|
||||||
|
username=username,
|
||||||
|
password=password)
|
||||||
|
|
||||||
|
def _get_chassis_collection_path(self):
|
||||||
|
"""Helper function to find the Chassis Collection path"""
|
||||||
|
chassis_col = self.json.get('Chassis')
|
||||||
|
if not chassis_col:
|
||||||
|
raise exceptions.MissingAttributeError(attribute='Chassis',
|
||||||
|
resource=self._path)
|
||||||
|
return chassis_col.get('@odata.id')
|
||||||
|
|
||||||
|
def get_chassis_collection(self):
|
||||||
|
"""Get the Chassis Collection object
|
||||||
|
|
||||||
|
:returns: a Chassis Collection object
|
||||||
|
"""
|
||||||
|
return chassis.ChassisCollection(self._conn,
|
||||||
|
self._get_chassis_collection_path(),
|
||||||
|
redfish_version=self.redfish_version)
|
||||||
|
|
||||||
|
def get_chassis(self, identity):
|
||||||
|
"""Given the identity return a Chassis object
|
||||||
|
|
||||||
|
:param identity: The identity of the Chassis resource
|
||||||
|
:returns: The Chassis object
|
||||||
|
"""
|
||||||
|
return chassis.Chassis(self._conn,
|
||||||
|
identity,
|
||||||
|
redfish_version=self.redfish_version)
|
0
valence/tests/unit/redfish/sushy/__init__.py
Normal file
0
valence/tests/unit/redfish/sushy/__init__.py
Normal file
73
valence/tests/unit/redfish/sushy/json_samples/chassis.json
Normal file
73
valence/tests/unit/redfish/sushy/json_samples/chassis.json
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#Chassis/Members/$entity",
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Chassis1",
|
||||||
|
"@odata.type": "#Chassis.1.0.0.Chassis",
|
||||||
|
"AssetTag": "FlexChassis1",
|
||||||
|
"ChassisType": "Drawer",
|
||||||
|
"Description": "this is a chassis",
|
||||||
|
"Id": "Chassis1",
|
||||||
|
"IndicatorLED": "On",
|
||||||
|
"Links": {
|
||||||
|
"ComputerSystems": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Systems/system1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Systems/system2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Systems/system3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Systems/system4"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ContainedBy": {
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Rack1"
|
||||||
|
},
|
||||||
|
"Contains": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Chassis1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ManagedBy": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Managers/manager1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ManagersIn": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Managers/manager1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Oem": { },
|
||||||
|
"Switches": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/EthernetSwitches/switch1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Manufacturer": "Intel Corporaion",
|
||||||
|
"Model": "Lenovo FLEX 8731",
|
||||||
|
"Name": "FLEX-1",
|
||||||
|
"Oem": {
|
||||||
|
"Intel:RackScale": {
|
||||||
|
"@odata.type": "#Intel.Oem.Chassis",
|
||||||
|
"Location": {
|
||||||
|
"Rack": "Rack1",
|
||||||
|
"UHeight": "10 U",
|
||||||
|
"ULocation": "25 U",
|
||||||
|
"UWidth": "1 U"
|
||||||
|
},
|
||||||
|
"UUID": "e1c2d764-5c72-36d6-9945-a78255edab51"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PartNumber": "5c72-36d6",
|
||||||
|
"SKU": "e1c2d764-5c72",
|
||||||
|
"SerialNumber": "a78255edab51",
|
||||||
|
"Status": {
|
||||||
|
"Health": "OK",
|
||||||
|
"HealthRollup": "OK",
|
||||||
|
"State": "Enabled"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#Chassis",
|
||||||
|
"@odata.id": "/redfish/v1/Chassis",
|
||||||
|
"@odata.type": "#ChassisCollection.ChassisCollection",
|
||||||
|
"Members": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Rack1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Rack2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Chassis1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Chassis2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Drawer1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/Drawer2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/NVMEChassis1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/NVMEChassis2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Members@odata.count": 8,
|
||||||
|
"Name": "Chassis Collection"
|
||||||
|
|
||||||
|
}
|
88
valence/tests/unit/redfish/sushy/resources/test_chassis.py
Normal file
88
valence/tests/unit/redfish/sushy/resources/test_chassis.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# 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.tests.unit import base
|
||||||
|
|
||||||
|
from valence.redfish.sushy.resources import chassis
|
||||||
|
|
||||||
|
|
||||||
|
class TestChassis(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestChassis, self).setUp()
|
||||||
|
self.conn = mock.Mock()
|
||||||
|
|
||||||
|
with open('valence/tests/unit/redfish/sushy/json_samples/chassis.json',
|
||||||
|
'r') as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.chassis_inst = chassis.Chassis(self.conn,
|
||||||
|
'/redfish/v1/Chassis/chassis1',
|
||||||
|
redfish_version='1.0.2')
|
||||||
|
|
||||||
|
def test_parse_attributes(self):
|
||||||
|
self.chassis_inst._parse_attributes()
|
||||||
|
self.assertEqual('1.0.2', self.chassis_inst.redfish_version)
|
||||||
|
self.assertEqual('FlexChassis1', self.chassis_inst.asset_tag)
|
||||||
|
self.assertEqual('Drawer', self.chassis_inst.chassis_type)
|
||||||
|
self.assertEqual('this is a chassis', self.chassis_inst.description)
|
||||||
|
self.assertEqual('Chassis1', self.chassis_inst.identity)
|
||||||
|
self.assertEqual('Intel Corporaion', self.chassis_inst.manufacturer)
|
||||||
|
self.assertEqual('FLEX-1', self.chassis_inst.name)
|
||||||
|
self.assertEqual('5c72-36d6', self.chassis_inst.part_number)
|
||||||
|
self.assertEqual('a78255edab51', self.chassis_inst.serial_number)
|
||||||
|
self.assertEqual('e1c2d764-5c72', self.chassis_inst.sku)
|
||||||
|
self.assertEqual('e1c2d764-5c72-36d6-9945-a78255edab51',
|
||||||
|
self.chassis_inst.oem['Intel:RackScale']['UUID'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestChassisCollection(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestChassisCollection, self).setUp()
|
||||||
|
self.conn = mock.Mock()
|
||||||
|
|
||||||
|
with open('valence/tests/unit/redfish/sushy/json_samples/'
|
||||||
|
'chassis_collection.json', 'r') as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.chassis_col = chassis.ChassisCollection(self.conn,
|
||||||
|
'/redfish/v1/Systems',
|
||||||
|
redfish_version='1.0.2')
|
||||||
|
|
||||||
|
def test__parse_attributes(self):
|
||||||
|
self.chassis_col._parse_attributes()
|
||||||
|
self.assertEqual('1.0.2', self.chassis_col.redfish_version)
|
||||||
|
self.assertEqual('Chassis Collection', self.chassis_col.name)
|
||||||
|
self.assertIn('/redfish/v1/Chassis/Chassis1',
|
||||||
|
self.chassis_col.members_identities)
|
||||||
|
|
||||||
|
@mock.patch.object(chassis, 'Chassis', autospec=True)
|
||||||
|
def test_get_member(self, mock_chassis):
|
||||||
|
self.chassis_col.get_member('/redfish/v1/Chassis/Chassis1')
|
||||||
|
|
||||||
|
mock_chassis.assert_called_once_with(
|
||||||
|
self.chassis_col._conn,
|
||||||
|
'/redfish/v1/Chassis/Chassis1',
|
||||||
|
redfish_version=self.chassis_col.redfish_version
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(chassis, 'Chassis', autospec=True)
|
||||||
|
def test_get_members(self, mock_chassis):
|
||||||
|
members = self.chassis_col.get_members()
|
||||||
|
self.assertEqual(mock_chassis.call_count, 8)
|
||||||
|
self.assertIsInstance(members, list)
|
||||||
|
self.assertEqual(8, len(members))
|
Loading…
x
Reference in New Issue
Block a user