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:
Manuel Schönlaub
2021-10-13 16:20:07 +02:00
parent eda4ea115c
commit d0ee9b9101
9 changed files with 308 additions and 1 deletions

View File

@@ -0,0 +1,4 @@
---
features:
- |
Adds support for the NetworkAdapter resource to the library.

View File

@@ -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):

View 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

View File

@@ -38,6 +38,9 @@
"Thermal": {
"@odata.id": "/redfish/v1/Chassis/Blade1/Thermal"
},
"NetworkAdapters": {
"@odata.id": "/redfish/v1/Chassis/Blade1/NetworkAdapters"
},
"Links": {
"ComputerSystems": [
{

View 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"
}
}

View File

@@ -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"
}

View File

@@ -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):

View 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))