Add 'meta' to bond properties

Dynamically generate 'meta' for bond and put there information
about DPDK availability and structure of available offloading modes.

Change-Id: Id030dda19b150b56db5624bd45c8f767d0748a47
Closes-bug: #1652068
This commit is contained in:
Fedor Zhadaev 2016-12-28 15:05:19 +04:00
parent 1e0d9278a2
commit 13be8e85c1
4 changed files with 129 additions and 2 deletions

View File

@ -21,6 +21,7 @@ from nailgun.objects.interface import DPDKMixin
from nailgun.objects import NailgunCollection
from nailgun.objects import NailgunObject
from nailgun.objects import NIC
from nailgun.objects import Release
from nailgun.objects.serializers.base import BasicSerializer
from nailgun.plugins.manager import PluginManager
from nailgun import utils
@ -65,6 +66,64 @@ class Bond(DPDKMixin, NailgunObject):
return attributes
@classmethod
def get_meta(cls, instance):
"""Get immutable attributes for bond.
:param instance: NodeBondInterface instance
:type instance: NodeBondInterface model
:returns: dict -- Object of bond attributes
"""
meta = {}
dpdk_drivers = Release.get_supported_dpdk_drivers(
instance.node.cluster.release)
meta['dpdk'] = {
'available': cls.dpdk_available(instance, dpdk_drivers)}
meta['offloading'] = {
'modes': Bond.get_available_offloading_modes(instance)
}
return meta
@classmethod
def get_available_offloading_modes(cls, instance):
structure = None
intersection_dict = {}
for interface in instance.slaves:
modes = interface.meta['offloading_modes']
if structure is None:
structure = modes
intersection_dict = \
NIC.offloading_modes_as_flat_dict(structure)
continue
intersection_dict = cls._intersect_offloading_dicts(
intersection_dict,
NIC.offloading_modes_as_flat_dict(modes)
)
return cls._apply_intersection(structure, intersection_dict)
@staticmethod
def _intersect_offloading_dicts(dict1, dict2):
result = dict()
for mode in dict1:
if mode in dict2:
result[mode] = dict1[mode] and dict2[mode]
return result
@classmethod
def _apply_intersection(cls, modes, intersection_dict):
result = list()
if modes is None:
return result
for mode in copy.deepcopy(modes):
if mode["name"] not in intersection_dict:
continue
mode["state"] = intersection_dict[mode["name"]]
if mode["sub"]:
mode["sub"] = \
cls._apply_intersection(mode["sub"], intersection_dict)
result.append(mode)
return result
@classmethod
def get_bond_default_attributes(cls, cluster):
"""Get native and plugin default attributes for bond.
@ -100,7 +159,7 @@ class Bond(DPDKMixin, NailgunObject):
@classmethod
def dpdk_available(cls, instance, dpdk_drivers):
return all(NIC.get_dpdk_driver(iface, dpdk_drivers)
return all(NIC.dpdk_available(iface, dpdk_drivers)
for iface in instance.slaves)

View File

@ -43,7 +43,6 @@ class DPDKMixin(object):
@classmethod
def refresh_interface_dpdk_properties(cls, interface, dpdk_drivers):
attributes = interface.attributes
meta = interface.meta
dpdk_attributes = copy.deepcopy(attributes.get('dpdk', {}))
dpdk_available = cls.dpdk_available(interface, dpdk_drivers)

View File

@ -140,6 +140,7 @@ class NodeInterfacesSerializer(BasicSerializer):
data_dict = BasicSerializer.serialize(instance, fields=fields)
data_dict['slaves'] = [{'name': s.name} for s in instance.slaves]
data_dict['attributes'] = Bond.get_attributes(instance)
data_dict['meta'] = Bond.get_meta(instance)
return data_dict

View File

@ -2197,6 +2197,74 @@ class TestBondObject(BaseTestCase):
objects.Bond.update(bond, copy.deepcopy(new_data))
self.assertEqual(new_data['attributes'], bond['attributes'])
def check_offloading_modes_intersection(self, modes_1, modes_2,
expected_result):
data = {
'name': 'bond0',
'slaves': self.node.nic_interfaces,
'node': self.node
}
bond = objects.Bond.create(data)
self.node.nic_interfaces[0].meta['offloading_modes'] = modes_1
self.node.nic_interfaces[1].meta['offloading_modes'] = modes_2
self.assertEquals(
objects.Bond.get_available_offloading_modes(bond),
expected_result)
def test_get_available_offloading_modes(self):
different_modes = [
[{
'name': 'mode_for_nic1',
'state': None,
'sub': [
{
'name': 'sub_mode_for_nic1',
'state': False,
'sub': []
}
]
}],
[{
'name': 'mode_for_nic2',
'state': True,
'sub': []
}],
]
self.check_offloading_modes_intersection(different_modes[0],
different_modes[1],
[])
common_mode = {'name': 'common_mode', 'state': True, 'sub': []}
for modes in different_modes:
modes.append(common_mode)
self.check_offloading_modes_intersection(different_modes[0],
different_modes[1],
[common_mode])
common_mode_2 = {
'name': 'common_mode_2',
'state': True, 'sub': [
{
'name': 'common_sub',
'state': False,
'sub': []
}
]}
for i, modes in enumerate(different_modes):
mode = copy.deepcopy(common_mode_2)
mode['sub'].append({'name': 'uncommon_sub_{}'.format(i),
'state': None,
'sub': []})
modes.append(mode)
self.check_offloading_modes_intersection(different_modes[0],
different_modes[1],
[common_mode, common_mode_2])
class TestNICObject(BaseTestCase):