treat virtual network devices a bit more like physical ones

in particular: have subiquitycore.netplan understand them. The goal of
all this is to make the recent change to not delete virtual interfaces
if their configuration has not changed actually work.
This commit is contained in:
Michael Hudson-Doyle 2020-04-03 09:17:19 +13:00
parent c8f53e87aa
commit fa476d54cc
2 changed files with 38 additions and 31 deletions

View File

@ -263,15 +263,6 @@ class NetworkModel(object):
def parse_netplan_configs(self, netplan_root):
self.config = netplan.Config()
self.config.load_from_root(netplan_root)
for typ, key in ('vlan', 'vlans'), ('bond', 'bonds'):
network = self.config.config.get('network', {})
for name, config in network.get(key, {}).items():
dev = self.devices_by_name.get(name)
if dev is None:
dev = self.devices_by_name[name] = NetworkDev(
self, name, typ)
# XXX What to do if types don't match??
dev.config = config
def new_link(self, ifindex, link):
log.debug("new_link %s %s %s", ifindex, link.name, link.type)
@ -292,13 +283,14 @@ class NetworkModel(object):
else:
dev.info = link
else:
if link.is_virtual:
config = self.config.config_for_device(link)
if link.is_virtual and not config:
# If we see a virtual device without there already
# being a config for it, we just ignore it.
return
dev = NetworkDev(self, link.name, link.type)
dev.info = link
dev.config = self.config.config_for_device(link)
dev.config = config
log.debug("new_link %s %s with config %s",
ifindex, link.name,
sanitize_interface_config(dev.config))

View File

@ -13,11 +13,12 @@ class Config:
Call parse_netplan_config() with each piece of yaml config, and then
call config_for_device to get the config that matches a particular
network devices, if any.
network device, if any.
"""
def __init__(self):
self.devices = []
self.physical_devices = []
self.virtual_devices = []
self.config = {}
def parse_netplan_config(self, config):
@ -34,25 +35,32 @@ class Config:
if version != 2:
log.info("network has no/unexpected version %s", version)
return
for ethernet, eth_config in network.get('ethernets', {}).items():
self.devices.append(_Device(ethernet, eth_config))
for wifi, wifi_config in network.get('wifis', {}).items():
self.devices.append(_Device(wifi, wifi_config))
for phys_key in 'ethernets', 'wifis':
for dev, dev_config in network.get(phys_key, {}).items():
self.physical_devices.append(_PhysicalDevice(dev, dev_config))
for virt_key in 'bonds', 'vlans':
for dev, dev_config in network.get(virt_key, {}).items():
self.virtual_devices.append(_VirtualDevice(dev, dev_config))
def config_for_device(self, link):
allowed_matches = ('macaddress',)
match_key = 'match'
for dev in self.devices:
if dev.matches_link(link):
config = copy.deepcopy(dev.config)
if match_key in config:
match = {k: v for k, v in config[match_key].items()
if k in allowed_matches}
if match:
config[match_key] = match
else:
del config[match_key]
return config
if link.is_virtual:
for dev in self.virtual_devices:
if dev.name == link.name:
return copy.deepcopy(dev.config)
else:
allowed_matches = ('macaddress',)
match_key = 'match'
for dev in self.physical_devices:
if dev.matches_link(link):
config = copy.deepcopy(dev.config)
if match_key in config:
match = {k: v for k, v in config[match_key].items()
if k in allowed_matches}
if match:
config[match_key] = match
else:
del config[match_key]
return config
return {}
def load_from_root(self, root):
@ -65,7 +73,7 @@ class Config:
self.parse_netplan_config(fp.read())
class _Device:
class _PhysicalDevice:
def __init__(self, name, config):
match = config.get('match')
if match is None:
@ -95,6 +103,13 @@ class _Device:
return matches_name and matches_mac and matches_driver
class _VirtualDevice:
def __init__(self, name, config):
self.name = name
self.config = config
log.debug("config for %s = %s" % (name, self.config))
def configs_in_root(root, masked=False):
"""Return a list of all netplan configs under root.