Add support for NetworkAdapter resources
Adds support for ``NetworkAdapter`` resources installed in a ``Chassis``. Change-Id: I41ffde617e86d18c57e12fa6547273c7431eb051 Signed-off-by: Manuel Schönlaub <mschoenlaub@anexia-it.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for the NetworkAdapter resource to the library.
|
||||
@@ -23,9 +23,9 @@ from sushy.resources.chassis.thermal import thermal
|
||||
from sushy.resources import common
|
||||
from sushy.resources import constants as res_cons
|
||||
from sushy.resources.manager import manager
|
||||
from sushy.resources.system.network import adapter
|
||||
from sushy import utils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -292,6 +292,21 @@ class Chassis(base.ResourceBase):
|
||||
redfish_version=self.redfish_version, registries=self.registries,
|
||||
root=self.root)
|
||||
|
||||
@property
|
||||
@utils.cache_it
|
||||
def network_adapters(self):
|
||||
"""Property to reference `NetworkAdapterCollection` instance
|
||||
|
||||
It is set once when the first time it is queried. On refresh,
|
||||
this property is marked as stale (greedy-refresh not done).
|
||||
Here the actual refresh of the sub-resource happens, if stale.
|
||||
"""
|
||||
return adapter.NetworkAdapterCollection(
|
||||
self._conn,
|
||||
utils.get_sub_resource_path_by(self, "NetworkAdapters"),
|
||||
redfish_version=self.redfish_version,
|
||||
registries=self.registries, root=self.root)
|
||||
|
||||
|
||||
class ChassisCollection(base.ResourceCollectionBase):
|
||||
|
||||
|
||||
51
sushy/resources/system/network/adapter.py
Normal file
51
sushy/resources/system/network/adapter.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2021 Anexia Internetdienstleistungs GmbH
|
||||
# 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/v1/NetworkAdapter.v1_3_0.json
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
|
||||
|
||||
class NetworkAdapter(base.ResourceBase):
|
||||
description = base.Field('Description')
|
||||
"""Human-readable description of the BIOS resource"""
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The network adapter identity string"""
|
||||
|
||||
manufacturer = base.Field("Manufacturer")
|
||||
"""The manufacturer of this network adapter"""
|
||||
|
||||
model = base.Field("Model")
|
||||
"""The model of this network adapter"""
|
||||
|
||||
name = base.Field('Name')
|
||||
"""The name of the network adapter"""
|
||||
|
||||
part_number = base.Field("PartNumber")
|
||||
"""The part number of the network adapter"""
|
||||
|
||||
serial_number = base.Field("SerialNumber")
|
||||
"""The serial number of the network adapter"""
|
||||
|
||||
status = common.StatusField("Status")
|
||||
"""The status"""
|
||||
|
||||
|
||||
class NetworkAdapterCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return NetworkAdapter
|
||||
@@ -38,6 +38,9 @@
|
||||
"Thermal": {
|
||||
"@odata.id": "/redfish/v1/Chassis/Blade1/Thermal"
|
||||
},
|
||||
"NetworkAdapters": {
|
||||
"@odata.id": "/redfish/v1/Chassis/Blade1/NetworkAdapters"
|
||||
},
|
||||
"Links": {
|
||||
"ComputerSystems": [
|
||||
{
|
||||
|
||||
77
sushy/tests/unit/json_samples/network_adapter.json
Normal file
77
sushy/tests/unit/json_samples/network_adapter.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#NetworkAdapter.NetworkAdapter",
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1",
|
||||
"@odata.type": "#NetworkAdapter.v1_3_0.NetworkAdapter",
|
||||
"Assembly": {
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1/Assembly"
|
||||
},
|
||||
"Controllers": [
|
||||
{
|
||||
"ControllerCapabilities": {
|
||||
"DataCenterBridging": {
|
||||
"Capable": true
|
||||
},
|
||||
"NPAR": {
|
||||
"NparCapable": false,
|
||||
"NparEnabled": false
|
||||
},
|
||||
"NPIV": {
|
||||
"MaxDeviceLogins": 0,
|
||||
"MaxPortLogins": 0
|
||||
},
|
||||
"NetworkDeviceFunctionCount": 2,
|
||||
"NetworkPortCount": 2,
|
||||
"VirtualizationOffload": {
|
||||
"SRIOV": {
|
||||
"SRIOVVEPACapable": true
|
||||
},
|
||||
"VirtualFunction": {
|
||||
"DeviceMaxCount": 254,
|
||||
"MinAssignmentGroupSize": 8,
|
||||
"NetworkPortMaxCount": 127
|
||||
}
|
||||
}
|
||||
},
|
||||
"FirmwarePackageVersion": "14.25.80.0",
|
||||
"Links": {
|
||||
"NetworkDeviceFunctions": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1/NetworkDeviceFunctions/NIC.Integrated.1-2-1"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1/NetworkDeviceFunctions/NIC.Integrated.1-1-1"
|
||||
}
|
||||
],
|
||||
"NetworkDeviceFunctions@odata.count": 2,
|
||||
"NetworkPorts": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1/NetworkPorts/NIC.Integrated.1-2"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1/NetworkPorts/NIC.Integrated.1-1"
|
||||
}
|
||||
],
|
||||
"NetworkPorts@odata.count": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"Controllers@odata.count": 1,
|
||||
"Description": "Network Adapter View",
|
||||
"Id": "NIC.Integrated.1",
|
||||
"Manufacturer": "Mellanox Technologies",
|
||||
"Model": "MLNX 25GbE 2P ConnectX4LX RNDC",
|
||||
"Name": "Network Adapter View",
|
||||
"NetworkDeviceFunctions": {
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1/NetworkDeviceFunctions"
|
||||
},
|
||||
"NetworkPorts": {
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1/NetworkPorts"
|
||||
},
|
||||
"PartNumber": "0R887V",
|
||||
"SerialNumber": "IL7403101N00ZJ",
|
||||
"Status": {
|
||||
"Health": "OK",
|
||||
"HealthRollup": "OK",
|
||||
"State": "Enabled"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#NetworkAdapterCollection.NetworkAdapterCollection",
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters",
|
||||
"@odata.type": "#NetworkAdapterCollection.NetworkAdapterCollection",
|
||||
"Description": "Collection Of Network Adapter",
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/NIC.Integrated.1"
|
||||
}
|
||||
],
|
||||
"Members@odata.count": 1,
|
||||
"Name": "Network Adapter Collection"
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import sushy
|
||||
from sushy import exceptions
|
||||
from sushy.resources.chassis import chassis
|
||||
from sushy.resources.manager import manager
|
||||
from sushy.resources.system.network import adapter
|
||||
from sushy.resources.system import system
|
||||
from sushy.tests.unit import base
|
||||
|
||||
@@ -180,6 +181,49 @@ class ChassisTestCase(base.TestCase):
|
||||
self.assertEqual(
|
||||
'/redfish/v1/Systems/529QB9450R6', actual_systems[0].path)
|
||||
|
||||
def test_network_adapters(self):
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('sushy/tests/unit/'
|
||||
'json_samples/network_adapter_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
actual_adapters = self.chassis.network_adapters
|
||||
self.assertIsInstance(actual_adapters,
|
||||
adapter.NetworkAdapterCollection)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
|
||||
def test_network_adapters_cached(self):
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('sushy/tests/unit/'
|
||||
'json_samples/network_adapter_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
actual_adapters = self.chassis.network_adapters
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
self.assertIs(actual_adapters,
|
||||
self.chassis.network_adapters)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_network_adapters_refresh(self):
|
||||
with open('sushy/tests/unit/'
|
||||
'json_samples/network_adapter_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
adapters = self.chassis.network_adapters
|
||||
self.assertIsInstance(adapters, adapter.NetworkAdapterCollection)
|
||||
|
||||
with open('sushy/tests/unit/'
|
||||
'json_samples/chassis.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.chassis.invalidate()
|
||||
self.chassis.refresh(force=False)
|
||||
|
||||
self.assertTrue(adapters._is_stale)
|
||||
|
||||
with open('sushy/tests/unit/'
|
||||
'json_samples/network_adapter_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
self.assertIsInstance(self.chassis.network_adapters,
|
||||
adapter.NetworkAdapterCollection)
|
||||
|
||||
|
||||
class ChassisCollectionTestCase(base.TestCase):
|
||||
|
||||
|
||||
100
sushy/tests/unit/resources/system/network/test_adapter.py
Normal file
100
sushy/tests/unit/resources/system/network/test_adapter.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# Copyright (c) 2021 Anexia Internetdienstleistungs GmbH
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
from unittest import mock
|
||||
|
||||
from sushy.resources import constants as res_cons
|
||||
from sushy.resources.system.network import adapter
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class NetworkAdapterTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(NetworkAdapterTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/network_adapter.json') as f:
|
||||
self.json_doc = json.load(f)
|
||||
|
||||
self.conn.get.return_value.json.return_value = self.json_doc
|
||||
|
||||
self.adapter = adapter.NetworkAdapter(
|
||||
self.conn, '/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters/'
|
||||
'NIC.Integrated.1',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.adapter._parse_attributes(self.json_doc)
|
||||
self.assertEqual('1.0.2', self.adapter.redfish_version)
|
||||
self.assertEqual('NIC.Integrated.1', self.adapter.identity)
|
||||
self.assertEqual('Network Adapter View', self.adapter.name)
|
||||
self.assertEqual('Network Adapter View', self.adapter.description)
|
||||
self.assertEqual('0R887V', self.adapter.part_number)
|
||||
self.assertEqual('IL7403101N00ZJ', self.adapter.serial_number)
|
||||
self.assertEqual('Mellanox Technologies', self.adapter.manufacturer)
|
||||
self.assertEqual('MLNX 25GbE 2P ConnectX4LX RNDC', self.adapter.model)
|
||||
self.assertEqual(res_cons.STATE_ENABLED, self.adapter.status.state)
|
||||
self.assertEqual(res_cons.HEALTH_OK, self.adapter.status.health)
|
||||
self.assertEqual(res_cons.HEALTH_OK, self.adapter.status.health_rollup)
|
||||
|
||||
|
||||
class NetworkAdapterCollectionTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(NetworkAdapterCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'network_adapter_collection.json') as f:
|
||||
self.json_doc = json.load(f)
|
||||
|
||||
self.conn.get.return_value.json.return_value = self.json_doc
|
||||
|
||||
self.adapter_col = adapter.NetworkAdapterCollection(
|
||||
self.conn, '/redfish/v1/Chassis/System.Embedded.1/NetworkAdapters',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.adapter_col._parse_attributes(self.json_doc)
|
||||
self.assertEqual('1.0.2', self.adapter_col.redfish_version)
|
||||
self.assertEqual('Network Adapter Collection', self.adapter_col.name)
|
||||
self.assertEqual(('/redfish/v1/Chassis/System.Embedded.1/'
|
||||
'NetworkAdapters/NIC.Integrated.1',),
|
||||
self.adapter_col.members_identities)
|
||||
|
||||
@mock.patch.object(adapter, 'NetworkAdapter', autospec=True)
|
||||
def test_get_member(self, mock_interface):
|
||||
self.adapter_col.get_member(
|
||||
'/redfish/v1/Chassis/System.Embedded.1/'
|
||||
'NetworkAdapters/NIC.Integrated.1'
|
||||
)
|
||||
mock_interface.assert_called_once_with(
|
||||
self.adapter_col._conn,
|
||||
'/redfish/v1/Chassis/System.Embedded.1/'
|
||||
'NetworkAdapters/NIC.Integrated.1',
|
||||
redfish_version=self.adapter_col.redfish_version,
|
||||
registries=None, root=self.adapter_col.root)
|
||||
|
||||
@mock.patch.object(adapter, 'NetworkAdapter', autospec=True)
|
||||
def test_get_members(self, mock_interface):
|
||||
members = self.adapter_col.get_members()
|
||||
calls = [
|
||||
mock.call(self.adapter_col._conn,
|
||||
'/redfish/v1/Chassis/System.Embedded.1/'
|
||||
'NetworkAdapters/NIC.Integrated.1',
|
||||
redfish_version=self.adapter_col.redfish_version,
|
||||
registries=None, root=self.adapter_col.root),
|
||||
]
|
||||
mock_interface.assert_has_calls(calls)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(1, len(members))
|
||||
Reference in New Issue
Block a user