[Twisted-Python] SNMP support

Neil Blakey-Milner nbm at mithrandr.moria.org
Mon Dec 23 16:46:02 EST 2002


On Mon 2002-12-23 (17:26), Neil Blakey-Milner wrote:
> Anyway, I'd like to know how people would like this reworked, especially
> if they can tell me how to think about it in a more twisted and/or
> pythonic way.

Thanks to Itamar and Moshez for comments.  Updated to 1.0.1 udp (much
nicer), and added multiple oid queries.

I don't like the way things fail when they do.  If the host does not
exist in DNS, I get:
exceptions.AttributeError: 'NoneType' object has no attribute 'getHost'
because the transport doesn't exist if the DNS fails.

If the server is not running SNMP, I get:
socket.error: (61, 'Connection refused')
from udp.Port.doRead(), since it excepts to calling log.deferr.  My
requests do subsequently timeout, though, but I can't remove them from
my queries list.

Am I doing anything wrong? I just copied the general idea from the DNS
code again.

I also wonder whether I should be setting a timeout within the "boss",
even a configurable one.  Would it be better to leave it to the user as
to whether to wait, or assume a default if they don't pass a timeout to
the query and/or "boss"?

Thanks again,

Neil
-- 
Neil Blakey-Milner
nbm at mithrandr.moria.org
-------------- next part --------------
#!/usr/local/bin/python
#
# Copyright (c) 2002 Neil Blakey-Milner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

from twisted.internet import defer, protocol, reactor, udp

from pysnmp.proto import v1, v2c

class SNMPv1Boss:
    def __init__(self, server, port = 161, community = "public"):
        self.snmp = v1
        self.community = community

        self.queries = {}
        self.server = server
        self.port = port

    def gotResponse(self, peerinfo, data):
        if self.queries.has_key(peerinfo):
            (snmp, deferred) = self.queries[peerinfo]
            rsp = snmp.GetResponse()
            rsp.decode(data)
            deferred.callback(rsp)
            del self.queries[peerinfo]

    def makeRequest(self, oids):
        d = defer.Deferred()
        req = SNMPRequest()
        req.boss = self
        reactor.connectUDP(self.server, self.port, req)
        req.id = req.transport.getHost()
        self.queries[req.id] = (self.snmp, d)
        req.query(self.snmp, self.community, oids)
        d.setTimeout(5)
        return d

class SNMPv2Boss(SNMPv1Boss):
    def __init__(self, server, port = 161, community = "public"):
        SNMPv1Boss.__init__(self, server, port, community)
        self.snmp = v2c

class SNMPRequest(protocol.ConnectedDatagramProtocol):
    def query(self, snmp, community, oids):
        self.snmp = snmp
        self.req = snmp.GetRequest()
        self.req['community'].set(community)
        self.req['pdu']['get_request']['variable_bindings'].extend(map(lambda x: snmp.VarBind(name=snmp.ObjectName(x)), oids))
        self.transport.write(self.req.encode())

    def datagramReceived(self, answer):
        self.boss.gotResponse(self.id, answer)
        self.transport.loseConnection()

def success(rsp):
    oids = map(lambda x: x['name'].get(), \
        rsp['pdu'].values()[0]['variable_bindings'])
    vals = map(lambda x: x['value'], \
        rsp['pdu'].values()[0]['variable_bindings'])
    # Print out results
    for (oid, val) in map(None, oids, vals):
        print oid, ' ---> ', val.values()[0]

def failed(reason):
    print reason

def makeQuery(boss):
    d = boss.makeRequest(["1.3.6.1.2.1.2.2.1.10.2"])
    d2 = boss.makeRequest(["1.3.6.1.2.1.2.2.1.10.3"])
    d.addCallbacks(success, failed)
    d2.addCallbacks(success, failed)
    d3 = boss.makeRequest(["1.3.6.1.2.1.2.2.1.10.2", "1.3.6.1.2.1.2.2.1.10.3"])
    d3.addCallbacks(success, failed)
    reactor.callLater(5, makeQuery, (boss))

def main():
    boss = SNMPv2Boss("archive", 161)
    reactor.callLater(1, makeQuery, (boss))
    reactor.run()

if __name__ == "__main__":
    main()


More information about the Twisted-Python mailing list