terom@384: """ terom@384: Requirements: terom@384: pysnmp terom@384: pysnmp-mibs terom@384: """ terom@384: terom@384: import logging; log = logging.getLogger('pvl.snmp.snmp') terom@384: import optparse terom@384: terom@384: from pysnmp.entity.rfc3413.oneliner import cmdgen as pysnmp terom@384: import collections terom@384: terom@384: def options (parser) : terom@384: parser = optparse.OptionGroup(parser, "SNMP Agent") terom@384: terom@384: parser.add_option('--snmp-community', terom@384: help="SNMPv2 read community") terom@384: terom@384: return parser terom@384: terom@384: class SNMPError (Exception) : terom@384: pass terom@384: terom@384: class SNMPEngineError (SNMPError) : terom@384: """ terom@384: Internal SNMP Engine error (?) terom@384: """ terom@384: terom@384: class SNMPAgent (object) : terom@384: """ terom@384: GET SNMP shit from a remote host. terom@384: """ terom@384: terom@384: SNMP_PORT = 161 terom@384: snmp_cmdgen = pysnmp.CommandGenerator() terom@384: terom@384: @classmethod terom@384: def apply (cls, options, host, community=None) : terom@384: port = cls.SNMP_PORT terom@384: terom@384: if community is None : terom@384: community = options.snmp_community terom@384: terom@384: terom@384: if '@' in host : terom@384: community, host = host.split('@', 1) terom@384: terom@384: if ':' in host : terom@384: host, port = host.rsplit(':', 1) terom@384: terom@384: return cls( terom@384: pysnmp.CommunityData(community), terom@384: pysnmp.UdpTransportTarget((host, port)) terom@384: ) terom@384: terom@384: def __init__ (self, security, transport) : terom@384: self.security = security terom@384: self.transport = transport terom@384: terom@384: def get (self, *request) : terom@384: """ terom@384: request = ( terom@384: pysnmp.MibVariable('IF-MIB', 'ifInOctets', 1), terom@384: ) terom@384: """ terom@384: terom@384: opts = dict( terom@384: lookupNames = True, terom@384: lookupValues = True, terom@384: ) terom@384: terom@384: try : terom@384: error, error_status, error_index, response = self.snmp_cmdgen.getCmd(self.security, self.transport, *request, **opts) terom@384: except pysnmp.error.PySnmpError as ex : terom@384: raise SNMPEngineError(ex) terom@384: terom@384: if error : terom@384: raise SNMPEngineError(error) terom@384: terom@384: if error_status : terom@384: raise SNMPError(errorStatus.prettyPrint()) terom@384: terom@384: return response terom@384: #for name, value in response : terom@384: # yield name.getMibSymbol(), value.prettyPrint() terom@384: terom@384: def walk (self, *request) : terom@384: """ terom@384: request = ( terom@384: pysnmp.MibVariable('IF-MIB', 'ifInOctets'), terom@384: ) terom@384: """ terom@384: terom@384: opts = dict( terom@384: lookupNames = True, terom@384: lookupValues = True, terom@384: ) terom@384: terom@384: try : terom@384: error, error_status, error_index, responses = self.snmp_cmdgen.nextCmd(self.security, self.transport, *request, **opts) terom@384: except pysnmp.error.PySnmpError as ex : terom@384: raise SNMPEngineError(ex) terom@384: terom@384: if error : terom@384: raise SNMPEngineError(error) terom@384: terom@384: if error_status : terom@384: raise SNMPError(errorStatus.prettyPrint()) terom@384: terom@384: return responses terom@384: #for response in responses: terom@384: # for name, value in response : terom@384: # yield name.getMibSymbol(), value.prettyPrint() terom@384: terom@384: def table (self, *columns) : terom@384: """ terom@384: Given [oid] returns { idx: { oid: value } } terom@384: """ terom@384: terom@384: data = collections.defaultdict(dict) terom@384: terom@384: for row in self.walk(*columns) : terom@384: log.debug("%s", row) terom@384: terom@384: for column, (field, value) in zip(columns, row) : terom@384: mib, sym, idx = field.getMibSymbol() terom@384: terom@384: log.debug("%s::%s[%s]: %s: %s", mib, sym, ', '.join(str(x) for x in idx), column, value) terom@384: terom@384: data[idx][column] = value terom@384: terom@384: return data.items() terom@384: