#!/usr/bin/env python # # XXX: Parsing snmpwalk is soo wrong todo, use a proper python library. # # # Rick van der Zwet # import gformat 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, m_snmp, m_traffic, m_uptime, host, rescan): data = gformat.get_yaml(host) nodename = data['nodename'] if m_snmp.has_key(nodename): ip = m_snmp[nodename] if not ip and rescan: logger.info("Re-scanning for new valid IP") ip = find_right_snmp_ip(logger, data) m_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) m_snmp[nodename] = ip else: logger.info("Running discovery for %s", nodename) ip = find_right_snmp_ip(logger, data) m_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') m_uptime[nodename] = int(uptime) traffic = {} for i,f in iface.iteritems(): traffic[f] = (int(ifin[i]), int(ifout[i])) m_traffic[nodename] = traffic except ConnectError: logger.error("Unable to get all data") pass def worker(i, input, m_snmp, m_traffic, m_uptime): logger = logging.getLogger('Worker%s' % i) logger.info("Worker") for (host, rescan) in iter(input.get, 'STOP'): process_file(logger, m_snmp, m_traffic, m_uptime, host, 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 # XXX: Manager.dict has bug of handling dicts inside dicts, using awefull quick # XXX: http://bugs.python.org/issue6766 m_snmp = manager.dict(store['snmp']) m_traffic = manager.dict(store['traffic']) m_uptime = manager.dict(store['uptime']) NUMBER_OF_PROCESSES = 10 RESCAN = True plist = {} for i in range(NUMBER_OF_PROCESSES): plist[i] = Process(target=worker, args=(i, task_queue,m_snmp,m_traffic,m_uptime)) plist[i].start() for host in sorted(gformat.get_hostlist()): if ff and not ff in host: continue task_queue.put((host, RESCAN)) for i in range(NUMBER_OF_PROCESSES): task_queue.put('STOP') for i in range(NUMBER_OF_PROCESSES): plist[i].join() store = {'snmp' : dict(m_snmp), 'traffic' : dict(m_traffic), 'uptime' : dict(m_uptime)} yaml.dump(store,open(DATASTORE,'w')) logger.info("Stored data at %s" % DATASTORE)