--- a/bin/pvl.hosts-graph Wed Mar 19 00:49:43 2014 +0200
+++ b/bin/pvl.hosts-graph Wed Mar 19 00:50:12 2014 +0200
@@ -7,6 +7,7 @@
import pvl.args
import pvl.hosts
+from pvl.invoke import merge
import collections
import logging; log = logging.getLogger('pvl.hosts-graph')
@@ -46,6 +47,22 @@
for part in line.split() :
yield _parse_snmp_part(part)
+def _parse_snmp_attr (line) :
+ parts = line.split()
+
+ key = parts.pop(0)
+
+ if len(parts) == 0 :
+ return key, None
+
+ elif len(parts) == 1 :
+ value, = parts
+
+ return key, value
+
+ else :
+ return key, parts
+
def _load_snmp_data (options, file) :
"""
Load a data dict generated by pvl.hosts-snmp from a file.
@@ -68,7 +85,7 @@
line = line.strip()
if '\t' in line :
- args = line.split('\t', 1)
+ args = line.split('\t')
line = args.pop(0)
args = tuple(args)
@@ -88,7 +105,7 @@
attr = tuple(_parse_snmp_line(line))
if args :
- value = tuple(tuple(_parse_snmp_line(arg)) for arg in args)
+ value = dict(_parse_snmp_attr(arg) for arg in args)
else :
value = None
@@ -121,7 +138,7 @@
root = { }
for host_name, attr, value in _load_snmp_data(options, file) :
- host = hosts[host_name]
+ host = hosts.get(host_name)
log.info("[%s] %s%s", host, ' '.join(str(a) for a in attr), (': ' + str(value)) if value else '')
@@ -136,10 +153,77 @@
item.setdefault(a, set()).update(value)
else :
- item[a] = dict(value)
+ item[a] = value
return root
+def search_vlans (snmp) :
+ for host in snmp :
+ ports = set()
+ vlans_untagged = { }
+ vlans_tagged = collections.defaultdict(set)
+
+ if 'vlan' not in snmp[host] :
+ continue
+
+ for vlan in snmp[host]['vlan'] :
+ for port in snmp[host]['vlan'][vlan].get('tagged', ()) :
+ ports.add(port)
+ vlans_tagged[port].add(vlan)
+
+ for port in snmp[host]['vlan'][vlan].get('untagged', ()) :
+ vlans_untagged[port] = vlan
+
+ out = { }
+ for port in ports :
+ untag = vlans_untagged.get(port)
+ tagged = vlans_tagged.get(port)
+
+ log.info("%s: %s: untag=%s tag=%s", host, port, untag, tagged)
+
+ out[port] = (untag, tagged)
+
+ yield host, out
+
+def search_lldp (snmp) :
+ lldp_hosts = {}
+
+ # first pass to resolve chassis ID's
+ for host, host_attrs in snmp.iteritems() :
+ lldp = host_attrs.get('lldp')
+
+ if not lldp :
+ continue
+
+ lldp_local = lldp.get('local')
+
+ if not lldp_local :
+ continue
+
+ lldp_hosts[lldp_local['chassis']] = host
+
+ # second pass to resolve remote
+ for host, host_attrs in snmp.iteritems() :
+ lldp = host_attrs.get('lldp')
+
+ if not lldp :
+ continue
+
+ local_attrs = lldp.get('local')
+
+ for port, port_attrs in snmp[host]['lldp']['port'].iteritems() :
+ port_local_attrs = port_attrs['local']
+
+ for chassis, remote_attrs in port_attrs['remote'].iteritems() :
+ remote_host = lldp_hosts.get(chassis)
+
+ local = merge(local_attrs, port_local_attrs, port_id=port)
+ remote = merge(remote_attrs, chassis=chassis)
+
+ log.info("%s @ %s %s : %s %s @ %s", host, host.location, local, remote, remote_host.location if remote_host else '', remote_host)
+
+ yield host, local, remote, remote_host
+
def apply_graph (options, items, vlans={}) :
import pydot
@@ -326,14 +410,16 @@
hosts = dict((str(host), host) for host in pvl.hosts.apply(options, args))
# load raw snmp data
- data = load_snmp_data(options, options.snmp_data, hosts)
-
- import pprint; pprint.pprint(data)
+ snmp = load_snmp_data(options, options.snmp_data, hosts)
# TODO: process data into graph
+
+ # XXX: compat
+ vlans = dict(search_vlans(snmp))
+ lldp = list(search_lldp(snmp))
- # TODO: generate graph
- #apply_graph(options, items, vlans if options.vlans else None)
+ # generate graph
+ apply_graph(options, lldp, vlans if options.vlans else None)
return 0