pvl.hosts-graph: value-less attr handling, compat for apply_graph()
authorTero Marttila <terom@paivola.fi>
Wed, 19 Mar 2014 00:50:12 +0200
changeset 402 3b6fb4ae56fb
parent 401 e57c200f3e26
child 403 9bae04e1780c
pvl.hosts-graph: value-less attr handling, compat for apply_graph()
bin/pvl.hosts-graph
--- 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