Source code for noc.core.script.snmp.base

# -*- coding: utf-8 -*-
##----------------------------------------------------------------------
## SNMP methods implementation
##----------------------------------------------------------------------
## Copyright (C) 2007-2015 The NOC Project
## See LICENSE for details
##----------------------------------------------------------------------

## Third-party modules
import tornado.ioloop
import tornado.gen
## NOC modules
from noc.core.ioloop.snmp import (snmp_get, snmp_count, snmp_getnext,
                                  snmp_set)
from noc.core.snmp.error import SNMPError, TIMED_OUT
from noc.core.snmp.version import SNMP_v1, SNMP_v2c, SNMP_v3
from noc.lib.log import PrefixLoggerAdapter


class SNMP(object):
    class TimeOutError(Exception):
        pass

    def __init__(self, script, beef=None):
        self.script = script
        self.ioloop = None
        self.result = None
        self.beef = beef
        self.logger = PrefixLoggerAdapter(script.logger, "snmp")

    def close(self):
        if self.ioloop:
            self.logger.debug("Closing IOLoop")
            self.ioloop.close(all_fds=True)
            self.ioloop = None

    def get_ioloop(self):
        if not self.ioloop:
            self.logger.debug("Creating IOLoop")
            self.ioloop = tornado.ioloop.IOLoop()
        return self.ioloop

    def _get_snmp_version(self, version=None):
        if version is not None:
            return version
        if self.script.has_snmp_v2c():
            return SNMP_v2c
        elif self.script.has_snmp_v3():
            return SNMP_v3
        elif self.script.has_snmp_v1():
            return SNMP_v1
        return SNMP_v2c

[docs] def get(self, oids, cached=False, version=None): """Perform SNMP GET request :param string oid: string or list of oids :param bool cached: True if get results can be cached during session :returns: eigther result scalar or dict of name -> value """ @tornado.gen.coroutine def run(): try: self.result = yield snmp_get( address=self.script.credentials["address"], oids=oids, community=str(self.script.credentials["snmp_ro"]), tos=self.script.tos, ioloop=self.get_ioloop(), version=version ) if self.beef: # Restore from beef self.beef.set_snmp_get(oids, self.result) except SNMPError as e: if e.code == TIMED_OUT: raise self.TimeOutError() else: raise version = self._get_snmp_version(version) self.get_ioloop().run_sync(run) return self.result
def set(self, *args): """ Perform SNMP GET request :param oid: string or list of oids :returns: eigther result scalar or dict of name -> value """ @tornado.gen.coroutine def run(): try: self.result = yield snmp_set( address=self.script.credentials["address"], varbinds=varbinds, community=str(self.script.credentials["snmp_rw"]), tos=self.script.tos, ioloop=self.get_ioloop() ) except SNMPError as e: if e.code == TIMED_OUT: raise self.TimeOutError() else: raise if len(args) == 1: varbinds = args elif len(args) == 2: varbinds = [(args[0], args[1])] else: raise ValueError("Invalid varbinds") self.get_ioloop().run_sync(run) return self.result def count(self, oid, filter=None, version=None): """ Iterate MIB subtree and count matching instances :param oid: OID :param filter: Callable accepting oid and value and returning boolean """ @tornado.gen.coroutine def run(): try: self.result = yield snmp_count( address=self.script.credentials["address"], oid=oid, community=str(self.script.credentials["snmp_ro"]), bulk=self.script.has_snmp_bulk, filter=filter, tos=self.script.tos, ioloop=self.get_ioloop(), version=version ) except SNMPError as e: if e.code == TIMED_OUT: raise self.TimeOutError() else: raise version = self._get_snmp_version(version) self.get_ioloop().run_sync(run) return self.result
[docs] def getnext(self, oid, community_suffix=None, filter=None, cached=False, only_first=False, bulk=None, max_repetitions=None, version=None): @tornado.gen.coroutine def run(): try: self.result = yield snmp_getnext( address=self.script.credentials["address"], oid=oid, community=str(self.script.credentials["snmp_ro"]), bulk=self.script.has_snmp_bulk if bulk is None else bulk, max_repetitions=max_repetitions, filter=filter, only_first=only_first, tos=self.script.tos, ioloop=self.get_ioloop(), version=version ) except SNMPError as e: if e.code == TIMED_OUT: raise self.TimeOutError() else: raise version = self._get_snmp_version(version) self.get_ioloop().run_sync(run) return self.result
[docs] def get_table(self, oid, community_suffix=None, cached=False): """ GETNEXT wrapper. Returns a hash of <index> -> <value> """ r = {} for o, v in self.getnext(oid, community_suffix=community_suffix, cached=cached): r[int(o.split(".")[-1])] = v return r
def join_tables(self, oid1, oid2, community_suffix=None, cached=False): """ Generator returning a rows of two snmp tables joined by index """ t1 = self.get_table(oid1, community_suffix=community_suffix, cached=cached) t2 = self.get_table(oid2, community_suffix=community_suffix, cached=cached) for k1, v1 in t1.items(): try: yield (v1, t2[k1]) except KeyError: pass
[docs] def get_tables(self, oids, community_suffix=None, bulk=False, min_index=None, max_index=None, cached=False): """ Query list of SNMP tables referenced by oids and yields tuples of (key, value1, ..., valueN) :param oids: List of OIDs :param community_suffix: Optional suffix to be added to community :param bulk: Use BULKGETNEXT if true :param min_index: Not use :param max_index: Not use :param cached: Optional parameter. If True - getting value will be cached :return: """ def gen_table(oid): l = len(oid) + 1 for o, v in self.getnext(oid, community_suffix=community_suffix, cached=cached): yield tuple([int(x) for x in o[l:].split(".")]), v # Retrieve tables tables = [dict(gen_table(oid)) for oid in oids] # Generate index index = set() for t in tables: index.update(t) # Yield result for i in sorted(index): yield [".".join([str(x) for x in i])] + [t.get(i) for t in tables]
def join(self, oids, community_suffix=None, cached=False, join="left"): """ Query list of tables, merge by oid index Tables are records of: * <oid>.<index> = value join may be one of: * left * inner * outer Yield records of (<index>, <value1>, ..., <valueN>) """ tables = [ self.get_table(o, community_suffix=community_suffix, cached=cached) for o in oids ] if join == "left": lt = tables[1:] for k in sorted(tables[0]): yield tuple([k, tables[0][k]] + [t.get(k) for t in lt]) elif join == "inner": keys = set(tables[0]) for lt in tables[1:]: keys &= set(lt) for k in sorted(keys): yield tuple([k] + [t.get(k) for t in tables]) elif join == "outer": keys = set(tables[0]) for lt in tables[1:]: keys |= set(lt) for k in sorted(keys): yield tuple([k] + [t.get(k) for t in tables])