Skip to content

normelton/snmp4em

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SNMP Library for EventMachine

Summary

This gem extends Ruby-SNMP to use the asynchronous EventMachine library for added performance and scalability. This allows code to scale monitoring applications to access a very high number of devices without the need for complex asynchronous I/O handling.

Features

The library currently supports:

  • SNMP v1 and v2

  • SNMP Get, GetNext, Set, and Walk requests. For SNMPv2 clients, GetBulk and WalkBulk

  • Ability to query/set/walk multiple OIDs in parallel.

  • For Ruby 1.9 and above, fiber support to streamline asychronous code

Future revisions of this library may support:

  • Ability to act as an SNMP agent, responding to external queries.

There are no plans to support SNMP v3 or the parsing of MIB files.

Options

You may set the following options:

SNMP4EM::Manager.new(
  :version => :SNMPv2c,
  :host => "127.0.0.1",
  :port => 161,
  :community => "public",      # Shorthand for setting both :community_ro and :community_rw
  :community_ro => "public",
  :community_rw => "public",
  :fiber => false,
  :timeout => 1,
  :retries => 3                # Can also be specified as an array of individual timeouts
                               # For instance, [0.5, 1, 2.5] would send three requests with increasing timeout values
)

These options may also be passed to an individual query method, for instance:

snmp = SNMP4EM::Manager.new(...)
snmp.get(OID, :retries => 2, :timeout => 1)

And when receiving traps:

SNMP4EM::NotificationManager.new(
  :host => "127.0.0.1",        # Local interface on which to listen for traps. By default, localhost only!
  :port => 161                 # Port on which to listen for traps.
)

Backwards compatibility

Version 1.0.0 tweaks the return values of a few functions. Please test code thoroughly before upgrading to 1.0.0 in production!

Running tests

This library now includes a full suite of functional tests. They communicate with an SNMP daemon running on the localhost. The library comes with the necessary configuration, but it’s much easier to fire up the provided rake task (‘rake server`), running in a separate terminal window, before running `rspec`. This works fine on a Mac OS X machine using homebrew (`brew install net-snmp`).

Acknowledgements

  • The SNMP packet processing is handled by the Ruby-SNMP library, by David Halliday

  • EventMachine, by Francis Cianfrocca and Aman Gupta

  • All the helpful folks on the Freenode #eventmachine channel

Examples

A few definitions:

OID_SYSTEM = "1.3.6.1.2.1.1"
OID_SYSNAME = "1.3.6.1.2.1.1.5.0"
OID_SYSLOCATION = "1.3.6.1.2.1.1.6.0"

A simple SNMP-GET:

EM.run {
  snmp = SNMP4EM::Manager.new(:host => "192.168.1.1")

  request = snmp.get([OID_SYSNAME, OID_SYSLOCATION])

  request.callback do |response|
    puts "System name = #{response[OID_SYSNAME]}"
    puts "System location = #{response[OID_SYSLOCATION]}"
  end

  request.errback do |error|
    puts "GET got error #{error}"
  end
}

A simple SNMP-GETNEXT:

EM.run {
  snmp = SNMP4EM::Manager.new(:host => "192.168.1.1")

  request = snmp.getnext(OID_SYSNAME)

  request.callback do |response|
    r = response[OID_SYSNAME]
    puts "The next OID is #{r[0]}, the next value is #{r[1]}"
  end

  request.errback do |error|
    puts "GETNEXT got error #{error}"
  end
}

A simple SNMP-SET:

EM.run {
  snmp = SNMP4EM::Manager.new(:host => "192.168.1.1")

  request = snmp.set({OID_SYSNAME => "My System Name", OID_SYSLOCATION => "My System Location"})

  request.callback do |response|
    if (response[OID_SYSNAME] == true)
      puts "System name set successful"
    else
      puts "System name set unsuccessful: #{response[OID_SYSNAME]}"
    end

    if (response[OID_SYSLOCATION] == true)
      puts "System location set successful"
    else
      puts "System location set unsuccessful: #{response[OID_SYSLOCATION]}"
    end
  end

  request.errback do |error|
    puts "SET got error #{error}"
  end
}

A simple SNMP-WALK:

EM.run {
  snmp = SNMP4EM::Manager.new(:host => "192.168.1.1")

  request = snmp.walk(OID_SYSTEM)

  request.callback do |response|
    response[OID_SYSTEM].each do |oid, value|
      puts "#{oid} = #{value}"
    end
  end

  request.errback do |error|
    puts "WALK got error #{error}"
  end
}

A simple SNMP-BULKWALK:

EM.run {
  snmp = SNMP4EM::Manager.new(:host => "192.168.1.1")

  request = snmp.bulkwalk(OID_SYSTEM)

  request.callback do |response|
    response[OID_SYSTEM].each do |oid, value|
      puts "#{oid} = #{value}"
    end
  end

  request.errback do |error|
    puts "BULK-WALK got error #{error}"
  end
}

A simple SNMP-GET-BULK:

EM.run {
  snmp = SNMP4EM::Manager.new(:host => "192.168.1.1")

  request = snmp.getbulk(OID_SYSTEM)

  request.callback do |response|
    response[OID_SYSTEM].each do |oid, value|
      puts "#{oid} = #{value}"
    end
  end

  request.errback do |error|
    puts "GET-BULK got error #{error}"
  end
}

Handling traps:

EM.run {
  manager = SNMP4EM::NotificationManager.new

  manager.on_trap do |trap|
    if trap.is_a? SNMP::SNMPv1_Trap
      puts "Got a SNMPv1_Trap"
    elsif trap.is_a? SNMP::SNMPv2_Trap
      puts "Got a SNMPv2_Trap"
    end
  end
}

Fiber Support

If your Ruby supports it, you can pass enable fibers, either per-manager or per-request. This unwinds much of the complexity in writing event-driven code. Instead of receiving an object on which to hang callbacks, the current fiber will be suspended until the response is available. If an error occurs, it will be returned as a SNMP::RequestTimeout. Unfortunately, there is no way to raise this error, you are responsible for manually checking whether the returned object is an error or not.

For example:

EM.run {
  snmp = SNMP4EM::Manager.new(:host => "192.168.1.1")

  f = Fiber.new do
    response = snmp.get([OID_SYSNAME, OID_SYSLOCATION])

    if response.is_a? SNMP::RequestTimeout
      puts "Uh oh!"
    else
      puts "System name = #{response[OID_SYSNAME]}"
      puts "System location = #{response[OID_SYSLOCATION]}"
    end
  end
}

Change Log

Version 1.1.5:

  • Fix memory leak (#10), many thanks to paddor

Version 1.1.5:

  • Fix an error when constructing a GetBulkRequest when using version >= 1.3.1 of the SNMP gem

Version 1.1.2:

  • Changed timeout error handling. We now raise a SNMP::RequestTimeout instead of a StandardError.

Version 1.1.0:

  • Fiber support

Version 1.0.2:

Version 1.0.1:

  • Requests resulting in an error now return nil unless return_raw is enabled

Version 1.0.0:

  • Added SNMPv2 BULKWALK support

  • Added ability to receive SNMP traps / informs

  • Added functional tests (finally!)

  • Moved documentation to Yard

  • Lots of code cleanup

Version 0.2.1:

  • Code cleanups, speed boosts

Version 0.2.0:

  • Added support for SNMPv2, including GET-BULK operations

Version 0.1.0:

  • Initial deployment, ability to run get/getnext/set/walk requests in parallel

Credits

Author: Norman Elton [email protected]

About

Bridge between Ruby-SNMP and EventMachine

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages