# HG changeset patch # User Tero Marttila # Date 1395183012 -7200 # Node ID 3b6fb4ae56fbe0608fe47b85241024c7a2f40300 # Parent e57c200f3e26bf7322cfbf457a26a66d90705304 pvl.hosts-graph: value-less attr handling, compat for apply_graph() diff -r e57c200f3e26 -r 3b6fb4ae56fb 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