Add a persist_mapping option to the mapping file
This adds the option to permanently rewrite the configuration so the aliases are used instead of the system name. This is useful where you have a variety of hardware and you want to have consistent device naming accross all platforms - this allows you to essentially rename the interfaces permanently so they match the abstracted nicN names. Note, this needs to be run with --cleanup or the old (now conflicting) configs will still be in place, and it may require a reboot before the changes are fully applied. Change-Id: I5af146e764b72c4beaa41c549fabff0af8802152
This commit is contained in:
parent
6945fe5afd
commit
a4ad189558
@ -1,6 +1,10 @@
|
||||
# This can be used with the -m option to override the
|
||||
# default mapping of the nicN aliases in configs
|
||||
# The mapping can specify either a device name or a mac address
|
||||
# If --persist-mapping is specified, we write the device aliases
|
||||
# config instead of the system names, e.g we actually configure
|
||||
# nic1 intead of em3. This is probably best used with --cleanup
|
||||
# to remove the stale configs e.g for em3
|
||||
interface_mapping:
|
||||
nic1: em3
|
||||
nic2: em1
|
||||
|
@ -74,6 +74,14 @@ def parse_opts(argv):
|
||||
help="Cleanup unconfigured interfaces.",
|
||||
required=False)
|
||||
|
||||
parser.add_argument(
|
||||
'--persist-mapping',
|
||||
dest="persist_mapping",
|
||||
action='store_true',
|
||||
help="Make aliases defined in the mapping file permanent "
|
||||
"(WARNING, permanently renames nics).",
|
||||
required=False)
|
||||
|
||||
opts = parser.parse_args(argv[1:])
|
||||
|
||||
return opts
|
||||
@ -139,13 +147,18 @@ def main(argv=sys.argv):
|
||||
# mappings by specifying a specific nicN->name or nicN->MAC mapping
|
||||
if os.path.exists(opts.mapping_file):
|
||||
with open(opts.mapping_file) as cf:
|
||||
iface_mapping = yaml.load(cf.read()).get("interface_mapping")
|
||||
iface_map = yaml.load(cf.read())
|
||||
iface_mapping = iface_map.get("interface_mapping")
|
||||
logger.debug('interface_mapping JSON: %s' % str(iface_mapping))
|
||||
persist_mapping = opts.persist_mapping
|
||||
logger.debug('persist_mapping: %s' % persist_mapping)
|
||||
else:
|
||||
iface_mapping = None
|
||||
persist_mapping = False
|
||||
|
||||
for iface_json in iface_array:
|
||||
iface_json.update({'nic_mapping': iface_mapping})
|
||||
iface_json.update({'persist_mapping': persist_mapping})
|
||||
obj = objects.object_from_json(iface_json)
|
||||
provider.add_object(obj)
|
||||
files_changed = provider.apply(noop=opts.noop, cleanup=opts.cleanup)
|
||||
|
@ -129,6 +129,9 @@ class ENINetConfig(os_net_config.NetConfig):
|
||||
if interface.mtu != 1500:
|
||||
data += " mtu %i\n" % interface.mtu
|
||||
|
||||
if interface.hwaddr:
|
||||
raise NotImplemented("hwaddr is not implemented.")
|
||||
|
||||
if ovs_extra:
|
||||
data += " ovs_extra %s\n" % " -- ".join(ovs_extra)
|
||||
|
||||
|
@ -142,6 +142,8 @@ class IfcfgNetConfig(os_net_config.NetConfig):
|
||||
first_v6 = v6_addresses[0]
|
||||
data += "IPV6_AUTOCONF=no\n"
|
||||
data += "IPV6ADDR=%s\n" % first_v6.ip
|
||||
if base_opt.hwaddr:
|
||||
data += "HWADDR=%s\n" % base_opt.hwaddr
|
||||
if ovs_extra:
|
||||
data += "OVS_EXTRA=\"%s\"\n" % " -- ".join(ovs_extra)
|
||||
return data
|
||||
|
@ -129,12 +129,20 @@ class _BaseOpts(object):
|
||||
"""Base abstraction for logical port options."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=[],
|
||||
routes=[], mtu=1500, primary=False, nic_mapping=None):
|
||||
routes=[], mtu=1500, primary=False, nic_mapping=None,
|
||||
persist_mapping=False):
|
||||
numbered_nic_names = _numbered_nics(nic_mapping)
|
||||
self.hwaddr = None
|
||||
if name in numbered_nic_names:
|
||||
self.name = numbered_nic_names[name]
|
||||
if persist_mapping:
|
||||
self.name = name
|
||||
hwname = numbered_nic_names[name]
|
||||
self.hwaddr = utils.interface_mac(hwname)
|
||||
else:
|
||||
self.name = numbered_nic_names[name]
|
||||
else:
|
||||
self.name = name
|
||||
|
||||
self.mtu = mtu
|
||||
self.use_dhcp = use_dhcp
|
||||
self.use_dhcpv6 = use_dhcpv6
|
||||
@ -192,22 +200,25 @@ class _BaseOpts(object):
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
nic_mapping = json.get('nic_mapping')
|
||||
persist_mapping = json.get('persist_mapping')
|
||||
|
||||
if include_primary:
|
||||
return (use_dhcp, use_dhcpv6, addresses, routes, mtu, primary,
|
||||
nic_mapping)
|
||||
nic_mapping, persist_mapping)
|
||||
else:
|
||||
return (use_dhcp, use_dhcpv6, addresses, routes, mtu,
|
||||
nic_mapping)
|
||||
nic_mapping, persist_mapping)
|
||||
|
||||
|
||||
class Interface(_BaseOpts):
|
||||
"""Base class for network interfaces."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=[],
|
||||
routes=[], mtu=1500, primary=False, nic_mapping=None):
|
||||
routes=[], mtu=1500, primary=False, nic_mapping=None,
|
||||
persist_mapping=False):
|
||||
super(Interface, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping)
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping)
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
@ -225,10 +236,11 @@ class Vlan(_BaseOpts):
|
||||
|
||||
def __init__(self, device, vlan_id, use_dhcp=False, use_dhcpv6=False,
|
||||
addresses=[], routes=[], mtu=1500, primary=False,
|
||||
nic_mapping=None):
|
||||
nic_mapping=None, persist_mapping=False):
|
||||
name = 'vlan%i' % vlan_id
|
||||
super(Vlan, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping)
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping)
|
||||
self.vlan_id = int(vlan_id)
|
||||
|
||||
numbered_nic_names = _numbered_nics(nic_mapping)
|
||||
@ -251,9 +263,10 @@ class OvsBridge(_BaseOpts):
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=[],
|
||||
routes=[], mtu=1500, members=[], ovs_options=None,
|
||||
ovs_extra=[], nic_mapping=None):
|
||||
ovs_extra=[], nic_mapping=None, persist_mapping=False):
|
||||
super(OvsBridge, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, False, nic_mapping)
|
||||
routes, mtu, False, nic_mapping,
|
||||
persist_mapping)
|
||||
self.members = members
|
||||
self.ovs_options = ovs_options
|
||||
self.ovs_extra = ovs_extra
|
||||
@ -272,8 +285,9 @@ class OvsBridge(_BaseOpts):
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'OvsBridge')
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping
|
||||
) = _BaseOpts.base_opts_from_json(json, include_primary=False)
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
ovs_options = json.get('ovs_options')
|
||||
ovs_extra = json.get('ovs_extra', [])
|
||||
members = []
|
||||
@ -291,7 +305,8 @@ class OvsBridge(_BaseOpts):
|
||||
return OvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, ovs_options=ovs_options,
|
||||
ovs_extra=ovs_extra, nic_mapping=nic_mapping)
|
||||
ovs_extra=ovs_extra, nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping)
|
||||
|
||||
|
||||
class OvsBond(_BaseOpts):
|
||||
@ -299,9 +314,11 @@ class OvsBond(_BaseOpts):
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=[],
|
||||
routes=[], mtu=1500, primary=False, members=[],
|
||||
ovs_options=None, ovs_extra=[], nic_mapping=None):
|
||||
ovs_options=None, ovs_extra=[], nic_mapping=None,
|
||||
persist_mapping=False):
|
||||
super(OvsBond, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping)
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping)
|
||||
self.members = members
|
||||
self.ovs_options = ovs_options
|
||||
self.ovs_extra = ovs_extra
|
||||
@ -318,8 +335,9 @@ class OvsBond(_BaseOpts):
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'OvsBond')
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping
|
||||
) = _BaseOpts.base_opts_from_json(json, include_primary=False)
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
ovs_options = json.get('ovs_options')
|
||||
ovs_extra = json.get('ovs_extra', [])
|
||||
members = []
|
||||
@ -337,4 +355,5 @@ class OvsBond(_BaseOpts):
|
||||
return OvsBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, ovs_options=ovs_options,
|
||||
ovs_extra=ovs_extra, nic_mapping=nic_mapping)
|
||||
ovs_extra=ovs_extra, nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping)
|
||||
|
@ -36,9 +36,10 @@ class TestCase(testtools.TestCase):
|
||||
|
||||
super(TestCase, self).setUp()
|
||||
self.stubs = stubout.StubOutForTesting()
|
||||
self.stubbed_numbered_nics = {}
|
||||
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return {}
|
||||
return self.stubbed_numbered_nics
|
||||
if self.stub_numbered_nics:
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
|
@ -36,6 +36,8 @@ IPADDR=192.168.1.2
|
||||
NETMASK=255.255.255.0
|
||||
"""
|
||||
|
||||
_V4_IFCFG_MAPPED = _V4_IFCFG.replace('em1', 'nic1') + "HWADDR=a1:b2:c3:d4:e5\n"
|
||||
|
||||
_V6_IFCFG = _BASE_IFCFG + """IPV6INIT=yes
|
||||
IPV6_AUTOCONF=no
|
||||
IPV6ADDR=2001:abc:a::
|
||||
@ -141,6 +143,23 @@ class TestIfcfgNetConfig(base.TestCase):
|
||||
self.assertEqual(_V4_IFCFG, self.get_interface_config())
|
||||
self.assertEqual('', self.get_route_config())
|
||||
|
||||
def test_add_interface_map_persisted(self):
|
||||
def test_interface_mac(name):
|
||||
macs = {'em1': 'a1:b2:c3:d4:e5'}
|
||||
return macs[name]
|
||||
self.stubs.Set(utils, 'interface_mac', test_interface_mac)
|
||||
|
||||
nic_mapping = {'nic1': 'em1'}
|
||||
self.stubbed_numbered_nics = nic_mapping
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('nic1', addresses=[v4_addr],
|
||||
nic_mapping=nic_mapping,
|
||||
persist_mapping=True)
|
||||
self.assertEqual('a1:b2:c3:d4:e5', interface.hwaddr)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFCFG_MAPPED, self.get_interface_config('nic1'))
|
||||
self.assertEqual('', self.get_route_config('nic1'))
|
||||
|
||||
def test_add_interface_with_v6(self):
|
||||
v6_addr = objects.Address('2001:abc:a::/64')
|
||||
interface = objects.Interface('em1', addresses=[v6_addr])
|
||||
|
Loading…
Reference in New Issue
Block a user