net-snmp

DESCRIPTION

net-snmp is a Ruby object oriented wrapper around the C netsnmp libraries. It provides classes for sessions, pdus, varbinds, and more.

FEATURES

  • Supports SNMP versions 1, 2c, and 3

  • Supports both synchronous and asynchronous calls

  • Supports sending of snmpv1 traps and snmpv2 traps/informs using TrapSession

  • Integrates well with eventmachine, or can be used standalone.

  • In Ruby 1.9, uses fibers behind the scenes to emulate synchronous calls asynchronously

  • MIB support

  • Convenience methods such as session.walk, session.get_columns, and session.table

USAGE

You must have the net-snmp libraries installed and available on the system. Check to make sure they are available in your library path. If necessary, add them to your shell like so:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/local/lib/net-snmp

You can use the library in two styles: synchronously or asynchronously. If you use the synchronous style, calls will block until a result is returned or the request times out. If you use the asynchronous style, you must provide a block to the client methods, which will be called when the data is ready.

In order for your callbacks to fire, you must call Net::SNMP::Dispatcher.poll You may pass a timeout argument to the dispatcher. If you pass false, the call will block forever until data is ready. If you pass an integer, it will block for <timeout> seconds. If you pass nil (the default), it will do a poll and return immediately. In that case, you will have to arrange for the dispatcher to run periodically. This can be done in your main event loop or in a seperate thread. There are convenience class methods in Net::SNMP::Dispatcher called run_loop, fiber_loop, em_loop, thread_loop and so on for setting up various polling loops. Or, you can roll your own loop.

If you like eventmachine, it's very easy to set up the dispatcher to run periodically in the adaptor. If you're using eventmachine with ruby 1.9, the library uses fibers behind the scenes to turn your synchronous calls into asynchronous calls, while allowing you to use a synchronous calling style. Examples of all these scenarios are below.

FFI

This library uses ruby-ffi to access the net-snmp libraries. If you want to use the C library directly, the wrapper functions are defined in Net::SNMP::Wrapper. You can call them like so:

Net::SNMP::Wrapper.snmp_perror("some_error")

NOTES

You must call Session.close when you're done with a session to avoid leaking memory

ERROR HANDLING

In the synchronous versions, all session methods raise Net::SNMP:Error on any error.  Timeouts raise Net::SNMP::TimeoutError.
In the asynchronous versions, the first argument to your callback will be the return status.  Possible values include :success, :timeout, and :send_error.
If you need the underlying net-snmp session errors, you can call session.errno, session.snmp_err, and session.error_message.
PDU errors can be retreived with pdu.errstat, pdu.errindex giving the index of the offending varbind.  See constants.rb for possible errors.

EXAMPLES

A simple synchronous SNMP-GET

session = Net::SNMP::Session.open(:peername => "test.net-snmp.org", :community => "demopublic" )
begin
  pdu = session.get("sysDescr.0")
  puts pdu.varbinds.first.value
rescue Net::SNMP::Error => e
  puts e.message
end
session.close

An asynchronous SNMP-GET

session = Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :community => 'demopublic') do |session|
  session.get(["sysDescr.0", "sysContact.0"]) do |status, pdu|
    if status == :success
      puts pdu.varbinds[0].value
    else
      puts "something went wrong.  status is #{status}"
    end
  end
end
Net::SNMP::Dispatcher.select(false)  #Setting timeout to false causes dispatcher to block until data is ready
session.close

An SNMPv3 synchronous AuthPriv (encrypted) SNMP-GET

Net::SNMP::Session.open(:peername => "test.net-snmp.org",

:community => “demopublic”, :version => “3”, :security_level => Net::SNMP::Constants::SNMP_SEC_LEVEL_AUTHPRIV, :auth_protocol => :sha1, :priv_protocol => :des, :username => “myuser”, :password => “mypassword” ) {|session|

	begin
  	pdu = session.get("sysDescr.0")
  	puts pdu.varbinds.first.value
	rescue Net::SNMP::Error => e
  	puts e.message
	end

end

Running the dispatcher from eventmachine

EM.run do
  Net::SNMP::Dispatcher.em_loop
  session = Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :community => 'demopublic') do |session|
    session.get("sysDescr.0") do |status, pdu|
      if status == :success
        puts pdu.varbinds[0].value
      else
        puts "something went wrong.  status is #{status}"
      end
    end
  end
  EM.add_timer(2) do
    session.close
    EM.stop
  end
end

Using synchronous style with eventmachine in ruby 1.9

EM.run do
    Net::SNMP::Dispatcher.fiber_loop
    Fiber.new {
      session = Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :community => 'demopublic')
      begin
        pdu = session.get("sysDescr.0")
        puts pdu.varbinds[0].value
      rescue Net::SNMP::Error => e
        puts e.message
      end
      session.close
      EM.stop
    }.resume
end

In the last example, note that you must wrap your code in Fiber.new {}.resume. You could instead use the em-synchrony gem, and wrap your loop with EM.synchrony{}. Note that even though it appears you are making a blocking call, waiting for a return value, actually in the background, control is passed back to the reactor fiber to process other requests. get() will return once the data is available. This is all seemless to you, the developer. Behold the power of fibers!

MIBs

By default, net-snmp loads all of your system MIBS. You can add additional mibs by adding them to your MIBS environment variable. You can also explicitly add MIBs using the MIB api. For example:

Net::SNMP::MIB.add_mibdir("/usr/local/share/mibs")
Net::SNMP::MIB.read_mib("RFC1213-MIB.txt")

Having the appropriate MIBs loaded will allow you to pass names instead of numeric oids to net-snmp methods. You can also pass Net::SNMP::OID objects. For example

oid = Net::SNMP::OID.new('sysDescr.0') # or Net::SNMP::OID.new("1.3.6.1.2.1.1.1.0")
puts oid.to_s  --> '1.3.6.1.2.1.1.1.0'
puts oid.label --> 'sysDescr.0'
pdu = session.get([oid])

For more complex MIB parsing needs, see smi-ffi

EXPERIMENTAL THREAD SUPPORT

If you intent to use threads, you should set:

Net::SNMP.thread_safe = true

Thread support is experimental and may be dropped. Let me know if you're using this feature.

CAVEATS/DISCLAIMER

THIS GEM COULD CRASH YOUR SYSTEM AND EAT YOUR CHILDREN!

You have been warned.

The API is subject to change.

This is very much alpha software. For more information on usage, take a look at the specs. Currently it's only tested against net-snmp 5.5. The net-snmp api seems pretty stable, but if anything changes, it could break this gem. Please let me know if you find bugs or missing features. Or better yet, send a pull request.

TODO

  • Implement walk and get_table convenience methods.

  • SNMPv3 support needs testing for various security models

  • Better documentation

  • More tests

Note on Patches/Pull Requests

  • Fork the project.

  • Make your feature addition or bug fix.

  • Add tests for it. This is important so I don't break it in a future version unintentionally.

  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)

  • Send me a pull request. Bonus points for topic branches.

  • Bug reports including a failing rspec get priority treatment

== Copyright

Copyright © 2010 mixtli. See LICENSE for details.