From 250e067316d2789c02b253e24d670d2d8f85302d Mon Sep 17 00:00:00 2001 From: Ludovic Pouzenc Date: Sun, 15 May 2016 23:26:10 +0200 Subject: inspectors : refactor done --- haircontrol/discovery.py | 57 +++++++++-------------- haircontrol/inspectors.py | 114 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 129 insertions(+), 42 deletions(-) (limited to 'haircontrol') diff --git a/haircontrol/discovery.py b/haircontrol/discovery.py index 680eb4c..243e3b6 100644 --- a/haircontrol/discovery.py +++ b/haircontrol/discovery.py @@ -1,56 +1,41 @@ -import re -import xml.etree.ElementTree from haircontrol.data import * +from haircontrol.inspectors import * class Discovery: - IPNEIGH = re.compile("(?P[a-f0-9:.]+) dev (?P.*) lladdr (?P[a-f0-9:]*)") - IPLINKSHOW = re.compile("(?P\d+):\s+(?P[^:]*):.+\s+(?:link/ether\s+(?P[a-f0-9:]*)\s+brd|link/none)") - def __init__(self, inspector): - self.inspector = inspector + def __init__(self): #, inspector): + self.linux_inspector = LinuxInspector() + self.ubnt_inspector = UbntInspector() self.net = EtherDomain() def discover_hinting_from_lldp(self, e_lldp): self.net.add_equipment(e_lldp) - self.inspector.connect(e_lldp) + self.linux_inspector.connect(e_lldp) # Learn local interfaces of e_lldp - fd = self.inspector.command('ip-link') - for line in fd: - matches = Discovery.IPLINKSHOW.match(line) - if matches: - ifname, mac = [ matches.group(k) for k in ['ifname','mac'] ] - e_lldp.ifaces[ifname] = Interface(ifname, mac) - fd.close() + result = self.linux_inspector.command('ip-link') + for (_, ifname, mac) in result: + e_lldp.ifaces[ifname] = Interface(ifname, mac) # Create equipments and ifaces from LLDP neighbour discovery - fd = self.inspector.command('lldp') - root = xml.etree.ElementTree.parse(fd).getroot() - for iface in root.iter('interface'): - local_ifname = iface.get('name') - local_mac = e_lldp.ifaces[local_ifname].mac - chassis = iface.find('chassis') - remote_name = chassis.find('name').text - remote_ipmgmt = chassis.find('mgmt-ip').text + result = self.linux_inspector.command('lldpctl') + for (local_ifname, local_mac, remote_name, remote_ipmgmt, ports) in result: e = Equipment(remote_name, remote_ipmgmt) self.net.add_equipment(e) - for port in iface.findall('port'): - remote_ifname = port.find('id').text + for remote_ifname in ports: e.add_seen_mac(remote_ifname, local_mac) - fd.close() - self.inspector.disconnect() + + self.linux_inspector.disconnect() def discover_from_root(self, e_root): self.net.add_equipment(e_root) - self.inspector.connect(e_root) - fd = self.inspector.command('ip-neigh') - for line in fd: - matches = Discovery.IPNEIGH.match(line) - if matches: - ip, ifname, mac = [ matches.group(k) for k in ['ip','ifname','mac'] ] - self.net.index_mac_ip(mac, ip) - e_root.add_seen_mac(ifname, mac) - fd.close() - self.inspector.disconnect() + self.linux_inspector.connect(e_root) + + result = self.linux_inspector.command('ip-neigh') + for (ip, ifname, mac) in result: + self.net.index_mac_ip(mac, ip) + e_root.add_seen_mac(ifname, mac) + + self.linux_inspector.disconnect() diff --git a/haircontrol/inspectors.py b/haircontrol/inspectors.py index 9b797fe..33bf360 100644 --- a/haircontrol/inspectors.py +++ b/haircontrol/inspectors.py @@ -1,21 +1,123 @@ import re +import xml.etree.ElementTree class Inspector(): cmds = {} - fd = None - def parse(self): - return None #XXX Implement + def __init__(self): + #XXX in a mockup class ? + self.testDataPath = '../test-data/input' + self.e = None + + def connect(self, e): + self.e = e + + def disconnect(self): + self.e = None + + def command(self, cmdname): + cmddef = self.cmds.get(cmdname) + if not cmddef: + return None + fd = self._exec(cmdname, cmddef['cmd']) + result = [] + re = cmddef.get('re') + func = cmddef.get('func') + if re: + for line in fd: + matches = re.match(line) + if matches: + result.append(matches.groups()) + elif func: + result = func(self, fd) + fd.close() + return result + + def _exec(self, cmdname, cmd): + #XXX in a mockup class ? + mockfile = self.testDataPath + '/' + self.e.name + '-' + cmdname + '.out' + return open(mockfile) + + class LinuxInspector(Inspector): + + def parse_lldpctl_xml(self, fd): + result = [] + root = xml.etree.ElementTree.parse(fd).getroot() + for iface in root.iter('interface'): + local_ifname = iface.get('name') + local_mac = self.e.ifaces[local_ifname].mac + chassis = iface.find('chassis') + remote_name = chassis.find('name').text + remote_ipmgmt = chassis.find('mgmt-ip').text + ports = [] + for port in iface.findall('port'): + remote_ifname = port.find('id').text + ports.append(remote_ifname) + result.append( (local_ifname, local_mac, remote_name, remote_ipmgmt, ports) ) + return result + cmds = { 'ip-neigh': { 'cmd': 'ip neigh', + 're': re.compile("(?P[a-f0-9:.]+) dev (?P.*) lladdr (?P[a-f0-9:]*)") # fe80::8300 dev eth1 lladdr 10:fe:ed:f1:e1:f3 router STALE # 172.16.20.210 dev eth1 lladdr c0:4a:00:fe:1f:87 REACHABLE + }, + 'ip-link': { + 'cmd': 'ip -o link', 'kind': 'text', - 'fields': ['ip','ifname','mac'], - 're': re.compile("(?P[a-f0-9:.]+) dev (?P.*) lladdr (?P[a-f0-9:]*)") - } + 're': re.compile("(?P\d+):\s+(?P[^:]*):.+\s+(?:link/ether\s+(?P[a-f0-9:]*)\s+brd|link/none)") + # 1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default \ link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + # 2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000\ link/ether 8c:89:a5:c7:be:88 brd ff:ff:ff:ff:ff:ff + }, + 'lldpctl': { + 'cmd': 'lldpctl -f xml', + 'func': parse_lldpctl_xml + # + # + # + # + # Robert_VILO + # Robert_VILO + # LM5 running on + #XM.v5.5.10 + # 172.16.10.26 + # 169.254.227.212 + # + # + # + # br0 + # br0 + # + # + # + # ... + # + # + }, } + + +class UbntInspector(Inspector): + + def parse_status_json(self, fd): + return 'parse_status_json' + + def parse_brmacs_json(self, fd): + return 'parse_brmacs_json' + + cmds = { + 'status.cgi': { + 'cmd':'..', + 'kind': 'cgi-json', + 'func': parse_status_json + }, + 'brmacs.cgi': { + 'cmd':'..', + 'kind': 'cgi-json', + 'func': parse_brmacs_json + } + } -- cgit v1.1