From 7f7e1543a578f93b442f576603cdaac8ff81f986 Mon Sep 17 00:00:00 2001 From: "T. Tran" Date: Fri, 29 Apr 2016 09:38:46 +0700 Subject: [PATCH 1/5] Support ipv6, nameservers, source, hooks --- adapter.py | 21 +++++++++++++++++++-- interfaces.py | 8 +++++++- interfacesReader.py | 30 ++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/adapter.py b/adapter.py index ee3d924..5ddbd79 100644 --- a/adapter.py +++ b/adapter.py @@ -14,9 +14,11 @@ class NetworkAdapter: 'network': {'type': 'IP'}, 'broadcast': {'type': 'IP'}, 'gateway': {'type': 'IP'}, + 'nameservers': {'type': list}, 'bridge-opts': {'type': dict}, 'addrFam': {'in': ['inet', 'inet6', 'ipx']}, 'source': {'in': ['dhcp', 'static', 'loopback', 'manual', 'bootp', 'ppp', 'wvdial', 'dynamic', 'ipv4ll', 'v4tunnel']}, + 'includes': {'type': list}, 'hostapd': {} } @@ -58,7 +60,10 @@ def validateIP(self, ip): Raise socket.error on invalid IP Works for subnet masks too. ''' - socket.inet_aton(ip) + try: + socket.inet_aton(ip) + except socket.error: + socket.inet_pton(socket.AF_INET6, ip) def setName(self, n): ''' Set the name option of an interface. ''' @@ -107,6 +112,18 @@ def setNetwork(self, w): self.validateOne('network', self._valid['network'], w) self._ifAttributes['network'] = w + def setNameservers(self, n): + ''' Set the ipaddress of an interface. ''' + + self.validateOne('nameservers', self._valid['nameservers'], n) + self._ifAttributes['nameservers'] = n + + def setIncludes(self, i): + self._ifAttributes['includes'] = i + + def appendIncludes(self, i): + self._ifAttributes['includes'].append(i); + def setAuto(self, t): ''' Set the option to autostart the interface. ''' @@ -245,7 +262,7 @@ def set_options(self, options): for key in options.keys(): if key == 'name': self.setName(options[key]) - if key == 'addrFam': + elif key == 'addrFam': self.setAddrFam(options[key]) elif key == 'source': self.setAddressSource(options[key]) diff --git a/interfaces.py b/interfaces.py index cf939c0..77356f8 100644 --- a/interfaces.py +++ b/interfaces.py @@ -31,9 +31,15 @@ def interfaces_path(self): def backup_path(self): return self._backup_path + @property + def includes(self): + return self._includes + def updateAdapters(self): ''' (re)read interfaces file and save adapters ''' - self._adapters = InterfacesReader(self._interfaces_path).parse_interfaces() + reader = InterfacesReader(self._interfaces_path) + self._adapters = reader.parse_interfaces() + self._includes = reader.includes if not self._adapters: self._adapters = [] diff --git a/interfacesReader.py b/interfacesReader.py index f016376..d0ceaa3 100644 --- a/interfacesReader.py +++ b/interfacesReader.py @@ -15,6 +15,10 @@ def __init__(self, interfaces_path): def adapters(self): return self._adapters + @property + def includes(self): + return self._include_list + def parse_interfaces(self): ''' Read /etc/network/interfaces. ''' self._reset() @@ -67,6 +71,7 @@ def _read_lines_from_file(self, fileObj): self._parse_details(line) self._read_auto(line) self._read_hotplug(line) + self._read_source(line) def _parse_iface(self, line): if line.startswith('iface'): @@ -78,8 +83,9 @@ def _parse_iface(self, line): self._adapters[self._context].setAddrFam(sline[2]) def _parse_details(self, line): - if line[0].isspace() is True: - sline = line.split() + sline = line.split() + #if line[0].isspace() is True: + if not sline[0] in {'auto', 'iface', 'allow-auto', 'allow-hotplug', 'source'}: if sline[0] == 'address': self._adapters[self._context].setAddress(sline[1]) elif sline[0] == 'netmask': @@ -95,12 +101,15 @@ def _parse_details(self, line): sline.pop(0) ifs = " ".join(sline) self._adapters[self._context].replaceBropt(opt[1], ifs) - elif sline[0] == 'up' or sline[0] == 'down' or sline[0] == 'pre-up' or sline[0] == 'post-down': + if sline[0] == 'nameservers' or sline[0] == 'dns-nameservers': + ns = sline.pop(0) + self._adapters[self._context].setNameservers(sline) + elif sline[0] == 'pre-up' or sline[0] == 'up' or sline[0] == 'post-up' or sline[0] == 'down' or sline[0] == 'pre-down' or sline[0] == 'post-down': ud = sline.pop(0) cmd = ' '.join(sline) - if ud == 'up': + if ud == 'up' or ud == 'post-up': self._adapters[self._context].appendUp(cmd) - elif ud == 'down': + elif ud == 'down' or ud == 'pre-down': self._adapters[self._context].appendDown(cmd) elif ud == 'pre-up': self._adapters[self._context].appendPreUp(cmd) @@ -108,7 +117,9 @@ def _parse_details(self, line): self._adapters[self._context].appendPostDown(cmd) else: # store as if so as not to loose it - self._adapters[self._context].setUnknown(sline[0], sline[1]) + key = sline.pop(0) + if self._context and self._context in self._adapters: + self._adapters[self._context].setUnknown(key, ' '.join(sline)) def _read_auto(self, line): ''' Identify which adapters are flagged auto. ''' @@ -130,6 +141,12 @@ def _read_hotplug(self, line): else: self._hotplug_list.append(word) + def _read_source(self, line): + if line.startswith('source'): + sline = line.split() + sline.pop(0) + self._include_list.append(' '.join(sline)) + def _reset(self): # Initialize a place to store created networkAdapter objects. self._adapters = [] @@ -137,6 +154,7 @@ def _reset(self): # Keep a list of adapters that have the auto or allow-hotplug flags set. self._auto_list = [] self._hotplug_list = [] + self._include_list = [] # Store the interface context. # This is the index of the adapters collection. From f0f8abe8991695aa4cc28d98277e953b918ab4a3 Mon Sep 17 00:00:00 2001 From: "T. Tran" Date: Fri, 29 Apr 2016 10:26:17 +0700 Subject: [PATCH 2/5] Better check --- interfacesReader.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interfacesReader.py b/interfacesReader.py index d0ceaa3..aa1eb59 100644 --- a/interfacesReader.py +++ b/interfacesReader.py @@ -101,7 +101,7 @@ def _parse_details(self, line): sline.pop(0) ifs = " ".join(sline) self._adapters[self._context].replaceBropt(opt[1], ifs) - if sline[0] == 'nameservers' or sline[0] == 'dns-nameservers': + elif sline[0] == 'nameservers' or sline[0] == 'dns-nameservers': ns = sline.pop(0) self._adapters[self._context].setNameservers(sline) elif sline[0] == 'pre-up' or sline[0] == 'up' or sline[0] == 'post-up' or sline[0] == 'down' or sline[0] == 'pre-down' or sline[0] == 'post-down': @@ -118,8 +118,10 @@ def _parse_details(self, line): else: # store as if so as not to loose it key = sline.pop(0) - if self._context and self._context in self._adapters: + try self._adapters[self._context].setUnknown(key, ' '.join(sline)) + except: + pass def _read_auto(self, line): ''' Identify which adapters are flagged auto. ''' From 10d9c88a48b42d8288d19ec7a6da8e3eaa13ad32 Mon Sep 17 00:00:00 2001 From: "T. Tran" Date: Fri, 29 Apr 2016 10:27:50 +0700 Subject: [PATCH 3/5] Correct syntax --- interfacesReader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfacesReader.py b/interfacesReader.py index aa1eb59..847d6e2 100644 --- a/interfacesReader.py +++ b/interfacesReader.py @@ -118,7 +118,7 @@ def _parse_details(self, line): else: # store as if so as not to loose it key = sline.pop(0) - try + try: self._adapters[self._context].setUnknown(key, ' '.join(sline)) except: pass From 3c2d31cb97078e001ec00576c00e619ef4ae6270 Mon Sep 17 00:00:00 2001 From: "T. Tran" Date: Fri, 29 Apr 2016 11:31:25 +0700 Subject: [PATCH 4/5] Switch gateway to string --- adapter.py | 2 +- interfacesReader.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/adapter.py b/adapter.py index 5ddbd79..b5ecfc7 100644 --- a/adapter.py +++ b/adapter.py @@ -13,7 +13,7 @@ class NetworkAdapter: 'netmask': {'type': 'IP'}, 'network': {'type': 'IP'}, 'broadcast': {'type': 'IP'}, - 'gateway': {'type': 'IP'}, + 'gateway': {'type': str}, 'nameservers': {'type': list}, 'bridge-opts': {'type': dict}, 'addrFam': {'in': ['inet', 'inet6', 'ipx']}, diff --git a/interfacesReader.py b/interfacesReader.py index 847d6e2..2088d9b 100644 --- a/interfacesReader.py +++ b/interfacesReader.py @@ -91,7 +91,8 @@ def _parse_details(self, line): elif sline[0] == 'netmask': self._adapters[self._context].setNetmask(sline[1]) elif sline[0] == 'gateway': - self._adapters[self._context].setGateway(sline[1]) + ud = sline.pop(0) + self._adapters[self._context].setGateway(' '.join(sline)) elif sline[0] == 'broadcast': self._adapters[self._context].setBroadcast(sline[1]) elif sline[0] == 'network': From c6d4befa2dfb1f598091677396cab10421dad765 Mon Sep 17 00:00:00 2001 From: "T. Tran" Date: Wed, 1 Feb 2017 20:50:10 +0700 Subject: [PATCH 5/5] Add a parser --- parser.py | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100755 parser.py diff --git a/parser.py b/parser.py new file mode 100755 index 0000000..b6e021c --- /dev/null +++ b/parser.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +import debinterface +import debinterface.interfaces +import debinterface.adapter +import sys + +if __name__ == "__main__": + intfile = sys.argv[1] + interfaces = debinterface.interfaces.Interfaces(interfaces_path=intfile) + interfaces.updateAdapters() + + adapters = interfaces.adapters + options = { + 'hotplug' + , 'auto' + , 'name' + , 'hwaddress' + , 'address' + , 'netmask' + , 'network' + , 'broadcast' + , 'gateway' + , 'bridge-opts' + , 'addrFam' + , 'source' + , 'nameservers' + , 'unknown' + , 'up' + , 'pre-up' + , 'post-up' + , 'down' + , 'post-down' + } + + print "network_managed_by_ansible: True" + print "network_manage_devices: True" + print "network_host_interfaces:" + for apt in adapters: + attrs = apt.export(options) + if attrs['auto'] == None: + attrs['auto'] = True + if attrs['name'] == 'lo' and attrs['source'] == 'loopback': + continue + else: + print " - device: %s" % attrs['name'] + print " description: %s network configs" % attrs['name'] + print " auto: %s" % attrs['auto'] + print " family: %s" % attrs['addrFam'] + print " method: %s" % attrs['source'] + if attrs['address']: + print " address: %s" % attrs['address'] + if attrs['unknown'] and 'hwaddress' in attrs['unknown'] and attrs['unknown']['hwaddress']: + print " hwaddress: %s" % attrs['unknown']['hwaddress'] + if 'network' in attrs and attrs['network']: + print " network: %s" % attrs['network'] + if attrs['broadcast']: + print " broadcast: %s" % attrs['broadcast'] + if 'netmask' in attrs and attrs['netmask']: + print " netmask: %s" % attrs['netmask'] + if 'gateway' in attrs and attrs['gateway']: + print " gateway: %s" % attrs['gateway'] + if 'nameservers' in attrs and attrs['nameservers']: + print " nameservers:" + for ns in attrs['nameservers']: + print " - %s" % ns + if attrs['unknown'] and 'dns-nameservers' in attrs['unknown'] and attrs['unknown']['dns-nameservers']: + print " nameservers: %s" % attrs['unknown']['dns-nameservers'] + if attrs['unknown']: + if 'dns-search' in attrs['unknown'] and attrs['unknown']['dns-search']: + print " dns_search: %s" % attrs['unknown']['dns-search'] + else: + print " dns_search: %s" % argv[2] + if 'up' in attrs and attrs['up']: + print " up:" + for cmd in attrs['up']: + if cmd.startswith('ip addr add 10.'): + print " - /usr/local/sbin/do_anchor_ip.sh %s" % attrs['name'] + else: + print " - %s" % cmd + if 'pre-up' in attrs and attrs['pre-up']: + print " pre-up:" + for cmd in attrs['pre-up']: + print " - %s" % cmd + if attrs['unknown'] and len(attrs['unknown']) > 0: + bond = {} + vlan = {} + for key in attrs['unknown']: + if not key in ['hwaddress', 'address', 'netmask', 'network', 'broadcast', 'gateway', 'dns-search', 'dns-nameservers']: + if key.startswith('bond-'): + skey = key[5:] + bond[skey] = attrs['unknown'][key] + elif key.startswith('vlan-'): + skey = key[5:] + vlan[skey] = attrs['unknown'][key] + else: + print " %s: %s ## unknown option" % (key, attrs['unknown'][key]) + if len(bond) > 0: + print " bond:" + for key in bond: + print " %s: %s" % (key, bond[key]) + if len(vlan) > 0: + print " vlan:" + for key in vlan: + print " %s: %s" % (key, vlan[key]) + + if interfaces.includes: + print "## WARNING: there are more configs for this host"