#!/usr/bin/env python # # XXX: Parsing snmpwalk is soo wrong todo, use a proper python library. # # Rick van der Zwet # import glob import logging import subprocess import sys import yaml from multiprocessing import Process, Manager, Pool, Queue, freeze_support logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger() DATASTORE='store.yaml' class ConnectError(Exception): pass def get_snmp_stats(logger, ip,target): p = subprocess.Popen("snmpwalk -t 1 -r 1 -Oq -c public -v2c %s %s" % (ip, target), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() if p.returncode != 0: logger.error(stderr.strip()) raise ConnectError r = {} for line in stdout.strip().split('\n'): index = line.split()[0][len(target)+1:] value = line.split()[1] r[index] = value return r def get_snmp_value(logger, ip, target): p = subprocess.Popen("snmpget -t 1 -r 1 -Ovt -c public -v2c %s %s" % (ip, target), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() if p.returncode != 0: logger.error(stderr.strip()) raise ConnectError return stdout.strip() def find_right_snmp_ip(logger, data): for k,v in data.iteritems(): if k.startswith('iface_'): ip = v['ip'].split('/')[0] logger.info("Trying ip %s", ip) try: uptime = get_snmp_value(logger, ip, 'DISMAN-EVENT-MIB::sysUpTimeInstance') return ip except ConnectError: pass return None try: ff = sys.argv[1] except IndexError: ff = '' def process_file(logger, store, nf, rescan): data = yaml.load(open(nf,'r')) nodename = data['nodename'] if store['snmp'].has_key(nodename): ip = store['snmp'][nodename] if not ip and rescan: logger.info("Re-scanning for new valid IP") ip = find_right_snmp_ip(logger, data) store['snmp'][nodename] = ip else: try: uptime = get_snmp_value(logger, ip, 'DISMAN-EVENT-MIB::sysUpTimeInstance') except ConnectError: logger.info("Re-scanning for new valid IP") ip = find_right_snmp_ip(logger, data) store['snmp'][nodename] = ip else: logger.info("Running discovery for %s", nodename) ip = find_right_snmp_ip(logger, data) store['snmp'][nodename] = ip if ip == None: logger.error("No valid ip found for node %s", nodename) return logger.info("Processing %s via %s", nodename, ip) target = 'IF-MIB::ifDescr' try: iface = get_snmp_stats(logger, ip, 'IF-MIB::ifDescr') ifout = get_snmp_stats(logger, ip, 'IF-MIB::ifOutOctets') ifin = get_snmp_stats(logger, ip, 'IF-MIB::ifInOctets') uptime = get_snmp_value(logger, ip, 'DISMAN-EVENT-MIB::sysUpTimeInstance') store['uptime'][nodename] = int(uptime) traffic = {} for i,f in iface.iteritems(): traffic[f] = (int(ifin[i]), int(ifout[i])) store['traffic'][nodename] = traffic except ConnectError: logger.error("Unable to get all data") pass def worker(i, input, m_store): logger = logging.getLogger('Worker%s' % i) logger.info("Worker") for (nf, rescan) in iter(input.get, 'STOP'): process_file(logger, m_store, nf, rescan) logger.info("END") if __name__ == '__main__': freeze_support() task_queue = Queue() manager = Manager() try: store = yaml.load(open(DATASTORE,'r')) except IOError: store = { 'snmp' : {}, 'traffic' : {}, 'uptime' : {}} pass m_store = manager.dict(store) NUMBER_OF_PROCESSES = 10 RESCAN = True plist = {} for i in range(NUMBER_OF_PROCESSES): plist[i] = Process(target=worker, args=(i, task_queue,m_store)) plist[i].start() for nf in sorted(glob.glob('nodes/*%s*/wleiden.yaml' % ff)): task_queue.put((nf, RESCAN)) for i in range(NUMBER_OF_PROCESSES): task_queue.put('STOP') for i in range(NUMBER_OF_PROCESSES): plist[i].join() yaml.dump(store,open(DATASTORE,'w'))