Translating pysnmp oids to human readable strings

birdsong david.birdsong at gmail.com
Thu Mar 5 22:12:50 CET 2009


On Mar 5, 1:05 pm, birdsong <david.birds... at gmail.com> wrote:
> On Mar 5, 12:32 pm, SpamMePlease PleasePlease
>
>
>
> <spankthes... at googlemail.com> wrote:
> > Hey list,
>
> > I was given a task, to reproduce functionality of command specified
> > below by writing proper python functions to reuse in some monitoring
> > script:
>
> > rivendell# snmpwalk -Os -mALL -v1 -cgabilgathol 10.0.6.66
> > .1.3.6.1.4.1.2636.5.1.1.2
> > jnxBgpM2PeerIdentifier.0.ipv4."".unknown."".0.1.38.101.87.145 =
> > STRING: 66.250.1.253
> > jnxBgpM2PeerIdentifier.0.ipv4.38.101.161.119.1.38.101.161.118 =
> > STRING: 66.28.1.85
> > jnxBgpM2PeerIdentifier.0.ipv4.64.200.59.74.1.64.200.59.73 = STRING: 64.200.68.12
> > jnxBgpM2PeerIdentifier.0.ipv4.72.37.131.250.1.72.37.131.249 = STRING:
> > 64.235.224.240
> > jnxBgpM2PeerState.0.ipv4."".unknown."".0.1.38.101.87.145 = INTEGER:
> > established(6)
> > jnxBgpM2PeerState.0.ipv4.38.101.161.119.1.38.101.161.118 = INTEGER:
> > established(6)
> > jnxBgpM2PeerState.0.ipv4.64.200.59.74.1.64.200.59.73 = INTEGER: established(6)
> > jnxBgpM2PeerState.0.ipv4.72.37.131.250.1.72.37.131.249 = INTEGER: established(6)
> > (more output)
>
> > I have already found a pysnmp library to fetch the data from the
> > device with a minimal amount of code:
>
> > from pysnmp.entity.rfc3413.oneliner import cmdgen
> > from pysnmp.smi import *
> > import string
>
> > cmdGen = cmdgen.CommandGenerator()
> > errorIndication, errorStatus, errorIndex, varBinds =
> > cmdgen.CommandGenerator().nextCmd(cmdgen.CommunityData('AmonMuil',
> > 'gabilgathol', 0),
> > cmdgen.UdpTransportTarget(('fw-1.datacenter.gondor.net', 161)),
> > (1,3,6,1,4,1,2636,5,1,1,2))
>
> > print errorIndication, errorStatus
> > for i in varBinds:
> >     print i
>
> > The problem is that I have completely stuck on the result I am
> > experiencing being totally human unreadable, like this:
>
> > rivendell# python snmp.py
> > None 0
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.1.0.1.0.0.0.0.1.38.101.87.145'),
> > OctetString('B\xfa\x01\xfd'))]
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.1.0.1.38.101.161.119.1.38.101.161.118'),
> > OctetString('B\x1c\x01U'))]
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.1.0.1.64.200.59.74.1.64.200.59.73'),
> > OctetString('@\xc8D\x0c'))]
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.1.0.1.72.37.131.250.1.72.37.131.249'),
> > OctetString('@\xeb\xe0\xf0'))]
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.2.0.1.0.0.0.0.1.38.101.87.145'),
> > Integer32('6'))]
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.2.0.1.38.101.161.119.1.38.101.161.118'),
> > Integer32('6'))]
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.2.0.1.64.200.59.74.1.64.200.59.73'),
> > Integer32('6'))]
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.2.0.1.72.37.131.250.1.72.37.131.249'),
> > Integer32('6'))]
> > [(ObjectName('1.3.6.1.4.1.2636.5.1.1.2.1.1.1.3.0.1.0.0.0.0.1.38.101.87.145'),
> > Integer32('2'))]
>
> > Since I cant find any way to translate these numbers to the same thing
> > snmpwalk produce, is there any clue on how to achieve that? Is it
> > possible at all for different devices (this one happend to be Juniper
> > firewall if that does matter). Also, how can I know where does this
> > magic oid ends and where does additional information starts (like ip
> > addresses added to oid 0 they all looks like another oid string
> > numbers) ?
>
> > Any sample of code, or hint to another lib will be very appreciated!
>
> > --
> > --------------------
> > Spank The Spam!
>
> Here's an example of walk that's part of a class I wrote, hopefully
> indentation survives the paste.  I borrowed heavily from example code
> on the pysnmp site.
>
> from pysnmp import asn1, v2c
> from pysnmp import role
>
>   def walk(self, community_string, base_oids):
>
>     if type(base_oids) is str: base_oids = [base_oids]
>     # this this does what it says, dont bother asking for oids that
> we'll see in our walk
>     base_oids = self.remove_child_oids(base_oids)
>     # h_pair is just (host, port)
>     client = role.manager(self.h_pair)
>     client.timeout = 10
>     req = v2c.GETNEXTREQUEST(community=community_string)
>     rsp = v2c.GETRESPONSE()
>     req['encoded_oids'] = map(asn1.OBJECTID().encode, base_oids)
>
>     oids_values = {}
>     while req['encoded_oids']:
>       try:
>         answer, host_tuple = client.send_and_receive(req.encode())
>       except (role.NoResponse, role.NetworkError):
>         return oids_values
>
>       rsp.decode(answer)
>
>       parsed_oids_vals = self.parse_response(rsp, base_oids)
>       oids_values.update(parsed_oids_vals)
>
>       req['request_id'] += 1
>       req['encoded_oids'] = map(asn1.OBJECTID().encode,
> parsed_oids_vals.keys())
>
>     return oids_values

Just realized the parse_response() is needed to makes sense of it:

def parse_response(self, rsp, head_oids):
    # list of indices
    overshot_oids = []

    vals = map(lambda x: x[0](), map(asn1.decode, rsp
['encoded_vals']))
    oids = map(lambda x: asn1.OBJECTID().decode(x)[0], rsp
['encoded_oids'])
    oids_vals = dict(map(None, oids, vals))

    for oid in oids_vals:
      if not filter(lambda h: asn1.OBJECTID(h).isaprefix(oid),
head_oids):
        overshot_oids.append(oid)

    map(lambda x: oids_vals.pop(x), overshot_oids)

    return oids_vals


I welcome critique btw, I'm here to learn.



More information about the Python-list mailing list