Use os-net-config mapping file when interface in bond or bridge

Os-net-config was not using the user supplied mapping file to map
interface names for interfaces in bonds or bridges.  Fix is to set
the mapping file info when creating interface objects in bonds/bridges.

Closes-Bug: 1695122

Change-Id: I063256b93c44c2e7a05d9820b0c1f6bf5b73d7a0
(cherry picked from commit 58a913e155)
This commit is contained in:
Bob Fournier 2017-06-01 21:07:40 -04:00
parent 909bc03e4a
commit 60e32735b1
2 changed files with 162 additions and 84 deletions

View File

@ -79,6 +79,32 @@ def _get_required_field(json, name, object_name):
return field
def _update_members(json, nic_mapping, persist_mapping):
"""Update object's members fields and pass mapping info to each member.
:param json: dictionary containing object values
:param nic_mapping: mapping of abstractions to actual nic names
:param persist_mapping: bool indicating mapping file should be permanent
:returns members: updated members
"""
members = []
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
# If this member already has a nic mapping, don't overwrite it
if not member.get('nic_mapping'):
member.update({'nic_mapping': nic_mapping})
member.update({'persist_mapping': persist_mapping})
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
return members
def _mapped_nics(nic_mapping=None):
mapping = nic_mapping or {}
global _MAPPED_NICS
@ -458,17 +484,8 @@ class OvsBridge(_BaseOpts):
ovs_options = json.get('ovs_options')
ovs_extra = json.get('ovs_extra')
fail_mode = json.get('ovs_fail_mode', DEFAULT_OVS_BRIDGE_FAIL_MODE)
members = []
# members
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
members = _update_members(json, nic_mapping, persist_mapping)
return OvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@ -524,17 +541,8 @@ class OvsUserBridge(_BaseOpts):
ovs_options = json.get('ovs_options')
ovs_extra = json.get('ovs_extra')
fail_mode = json.get('ovs_fail_mode', DEFAULT_OVS_BRIDGE_FAIL_MODE)
members = []
# members
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
members = _update_members(json, nic_mapping, persist_mapping)
return OvsUserBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@ -582,17 +590,8 @@ class LinuxBridge(_BaseOpts):
persist_mapping, defroute, dhclient_args,
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
members = []
# members
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
members = _update_members(json, nic_mapping, persist_mapping)
return LinuxBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@ -645,17 +644,8 @@ class IvsBridge(_BaseOpts):
persist_mapping, defroute, dhclient_args,
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
members = []
# members
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
members = _update_members(json, nic_mapping, persist_mapping)
return IvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@ -705,16 +695,7 @@ class NfvswitchBridge(_BaseOpts):
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
# members
members = []
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
members = _update_members(json, nic_mapping, persist_mapping)
cpus = ''
cpus_json = json.get('cpus')
@ -776,17 +757,8 @@ class LinuxTeam(_BaseOpts):
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
bonding_options = json.get('bonding_options')
members = []
# members
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
members = _update_members(json, nic_mapping, persist_mapping)
return LinuxTeam(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@ -835,17 +807,8 @@ class LinuxBond(_BaseOpts):
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
bonding_options = json.get('bonding_options')
members = []
# members
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
members = _update_members(json, nic_mapping, persist_mapping)
return LinuxBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@ -898,17 +861,8 @@ class OvsBond(_BaseOpts):
json, include_primary=False)
ovs_options = json.get('ovs_options')
ovs_extra = json.get('ovs_extra', [])
members = []
# members
members_json = json.get('members')
if members_json:
if isinstance(members_json, list):
for member in members_json:
members.append(object_from_json(member))
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
members = _update_members(json, nic_mapping, persist_mapping)
return OvsBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@ -1033,6 +987,10 @@ class OvsDpdkPort(_BaseOpts):
def from_json(json):
name = _get_required_field(json, 'name', 'OvsDpdkPort')
# driver name by default will be 'vfio-pci' if not specified
(use_dhcp, use_dhcpv6, addresses, routes, mtu, primary, nic_mapping,
persist_mapping, defroute, dhclient_args,
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(json)
driver = json.get('driver')
if not driver:
driver = 'vfio-pci'
@ -1043,7 +1001,11 @@ class OvsDpdkPort(_BaseOpts):
if members_json:
if isinstance(members_json, list):
if len(members_json) == 1:
iface = object_from_json(members_json[0])
member = members_json[0]
if not member.get('nic_mapping'):
member.update({'nic_mapping': nic_mapping})
member.update({'persist_mapping': persist_mapping})
iface = object_from_json(member)
if isinstance(iface, Interface):
# TODO(skramaja): Add checks for IP and route not to
# be set in the interface part of DPDK Port
@ -1064,9 +1026,15 @@ class OvsDpdkPort(_BaseOpts):
ovs_options = json.get('ovs_options', [])
ovs_options = ['options:%s' % opt for opt in ovs_options]
ovs_extra = json.get('ovs_extra', [])
opts = _BaseOpts.base_opts_from_json(json)
return OvsDpdkPort(name, *opts, members=members, driver=driver,
ovs_options=ovs_options, ovs_extra=ovs_extra)
return OvsDpdkPort(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
primary=primary, nic_mapping=nic_mapping,
persist_mapping=persist_mapping, defroute=defroute,
dhclient_args=dhclient_args,
dns_servers=dns_servers,
nm_controlled=nm_controlled, members=members,
driver=driver, ovs_options=ovs_options,
ovs_extra=ovs_extra)
class OvsDpdkBond(_BaseOpts):
@ -1116,6 +1084,9 @@ class OvsDpdkBond(_BaseOpts):
if members_json:
if isinstance(members_json, list):
for member in members_json:
if not member.get('nic_mapping'):
member.update({'nic_mapping': nic_mapping})
member.update({'persist_mapping': persist_mapping})
obj = object_from_json(member)
if isinstance(obj, OvsDpdkPort):
members.append(obj)

View File

@ -547,6 +547,17 @@ class TestBond(base.TestCase):
interface2 = bridge.members[1]
self.assertEqual("em2", interface2.name)
def _stub_active_nics(self, nics):
def dummy_ordered_active_nics():
return nics
self.stubs.Set(utils, 'ordered_active_nics', dummy_ordered_active_nics)
def _stub_available_nics(self, nics):
def dummy_ordered_available_nics():
return nics
self.stubs.Set(utils, 'ordered_available_nics',
dummy_ordered_available_nics)
class TestLinuxTeam(base.TestCase):
@ -931,6 +942,102 @@ class TestNicMapping(base.TestCase):
# This only emits a warning, so it should still work
self.assertEqual(expected, objects._mapped_nics())
# Test that mapping file is passed to interface members from parent object
def _test_mapped_nics_with_parent(self, type, name):
self._stub_available_nics(['foo', 'bar'])
mapping = {"nic1": "foo", "nic2": "bar"}
data = """{
"members": [{"type": "interface", "name": "nic1"},
{"type": "interface", "name": "nic2"}]
}
"""
json_output = json.loads(data)
json_output.update({'type': type})
json_output.update({'name': name})
json_output.update({'nic_mapping': mapping})
obj = objects.object_from_json(json_output)
self.assertEqual("foo", obj.members[0].name)
self.assertEqual("bar", obj.members[1].name)
def test_mapped_nics_ovs_bond(self):
self._test_mapped_nics_with_parent("ovs_bond", "bond1")
def test_mapped_nics_linux_bond(self):
self._test_mapped_nics_with_parent("linux_bond", "bond1")
def test_mapped_nics_ovs_bridge(self):
self._test_mapped_nics_with_parent("ovs_bridge", "br-foo")
def test_mapped_nics_ovs_user_bridge(self):
self._test_mapped_nics_with_parent("ovs_user_bridge", "br-foo")
def test_mapped_nics_linux_bridge(self):
self._test_mapped_nics_with_parent("linux_bridge", "br-foo")
def test_mapped_nics_ivs_bridge(self):
self._test_mapped_nics_with_parent("ivs_bridge", "br-foo")
def test_mapped_nics_linux_team(self):
self._test_mapped_nics_with_parent("team", "team-foo")
def test_mapped_nics_bridge_and_bond(self):
self._stub_available_nics(['foo', 'bar'])
mapping = {"nic1": "foo", "nic2": "bar"}
data = """{
"type": "ovs_bridge",
"name": "br-foo",
"members": [
{
"type": "ovs_bond",
"name": "bond0",
"members": [{"type": "interface", "name": "nic1"},
{"type": "interface", "name": "nic2"}]
}
]
}
"""
json_output = json.loads(data)
json_output.update({'nic_mapping': mapping})
obj = objects.object_from_json(json_output)
interface1 = obj.members[0].members[0]
interface2 = obj.members[0].members[1]
self.assertEqual("foo", interface1.name)
self.assertEqual("bar", interface2.name)
def test_mapped_nics_ovs_dpdk_bond(self):
self._stub_available_nics(['foo', 'bar'])
mapping = {"nic2": "foo", "nic3": "bar"}
data = """{
"type": "ovs_dpdk_bond",
"name": "dpdkbond0",
"members": [
{
"type": "ovs_dpdk_port",
"name": "dpdk0",
"members": [{"type": "interface", "name": "nic2"}]
},
{
"type": "ovs_dpdk_port",
"name": "dpdk1",
"members": [{"type": "interface", "name": "nic3"}]
}
]
}
"""
json_output = json.loads(data)
json_output.update({'nic_mapping': mapping})
dpdk_port = objects.object_from_json(json_output)
interface1 = dpdk_port.members[0].members[0]
interface2 = dpdk_port.members[1].members[0]
self.assertEqual("foo", interface1.name)
self.assertEqual("bar", interface2.name)
class TestOvsDpdkBond(base.TestCase):