net-snmp2 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -1
  3. data/examples/agent.rb +1 -0
  4. data/examples/inform.rb +23 -0
  5. data/examples/trap_handler.rb +15 -0
  6. data/examples/{v1_trap_session.rb → v1_trap.rb} +2 -7
  7. data/examples/{v2_trap_session.rb → v2_trap.rb} +2 -7
  8. data/history.md +17 -0
  9. data/lib/net-snmp2.rb +1 -1
  10. data/lib/net/snmp/agent/agent.rb +44 -13
  11. data/lib/net/snmp/agent/provider.rb +56 -1
  12. data/lib/net/snmp/agent/provider_dsl.rb +11 -0
  13. data/lib/net/snmp/debug.rb +10 -19
  14. data/lib/net/snmp/error.rb +13 -6
  15. data/lib/net/snmp/listener.rb +2 -4
  16. data/lib/net/snmp/message.rb +52 -25
  17. data/lib/net/snmp/mib/mib.rb +2 -1
  18. data/lib/net/snmp/mib/node.rb +1 -1
  19. data/lib/net/snmp/oid.rb +5 -2
  20. data/lib/net/snmp/pdu.rb +15 -10
  21. data/lib/net/snmp/repl/manager_repl.rb +20 -7
  22. data/lib/net/snmp/session.rb +78 -45
  23. data/lib/net/snmp/trap_handler/trap_handler.rb +13 -9
  24. data/lib/net/snmp/trap_handler/v2_inform_dsl.rb +16 -0
  25. data/lib/net/snmp/trap_session.rb +64 -42
  26. data/lib/net/snmp/version.rb +1 -1
  27. data/lib/net/snmp/wrapper.rb +2 -8
  28. data/net-snmp2.gemspec +1 -1
  29. data/spec/README.md +36 -40
  30. data/spec/async_spec.rb +92 -87
  31. data/spec/em_spec.rb +3 -3
  32. data/spec/error_spec.rb +2 -2
  33. data/spec/fiber_spec.rb +8 -7
  34. data/spec/mib_spec.rb +8 -8
  35. data/spec/net-snmp_spec.rb +3 -3
  36. data/spec/oid_spec.rb +5 -5
  37. data/spec/spec_helper.rb +5 -0
  38. data/spec/sync_spec.rb +50 -56
  39. data/spec/test_agent.rb +150 -0
  40. data/spec/test_mib.rb +6 -0
  41. data/spec/thread_spec.rb +4 -4
  42. data/spec/trap_spec.rb +3 -12
  43. data/spec/utility_spec.rb +4 -4
  44. data/spec/wrapper_spec.rb +6 -6
  45. metadata +11 -6
  46. data/lib/net/snmp/agent/request_dispatcher.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b281e88b9dc311d024200f3c6a1490a275aeeb2
4
- data.tar.gz: 7d0fd5cf86fd4bd509458de1bc0ce77fbcc03dcf
3
+ metadata.gz: 764e833cea5160e1dcd90749dc1e34497bc19cd7
4
+ data.tar.gz: dab11ed0e33675f7d37848b71a9eea33f94584e8
5
5
  SHA512:
6
- metadata.gz: 2de1bdd8d99a79ed0849d4546c8af674fed288657c08dfff5631b41c23237ac87ac454f81d5059f4f579c4819da75659a3c324f304246b023ae9375df44cd3a1
7
- data.tar.gz: 86dfd53cd984247500282b01108d96addac69ef79229edc8ea26c1eca4d05861e733c97a81b637ef4ccfe57c95904d6bcc64751bfd0b196cf86696a69ba8c371
6
+ metadata.gz: 9af6ba3d026772a98ee3d08d988859324b53f7e552e938ec400509f59a8fd0598c2716290af3a21b1c1374d8ff81c5b64f3905d21540b17ca5b46edf79b3d67d
7
+ data.tar.gz: 232ffa5c7ffdbe94a06cae89a545bc8795dfaf9f9ba0011c81edd6c85ebdefaa6ca4ab84bbcf20236aa18c5f2375efe76f48ff3ee93ee63e0b1ecce5c3d6404e
data/README.md CHANGED
@@ -1,12 +1,15 @@
1
1
  net-snmp2
2
2
  =========
3
3
 
4
- (Checkout the [wiki](https://github.com/jbreeden/net-snmp2/wiki))
4
+ [![Gem Version](https://badge.fury.io/rb/net-snmp2.svg)](http://badge.fury.io/rb/net-snmp2)
5
+
6
+ Just getting started? Checkout the [wiki](https://github.com/jbreeden/net-snmp2/wiki)
5
7
 
6
8
  An object oriented Ruby wrapper around the C [netsnmp](http://www.net-snmp.org) libraries.
7
9
  It provides classes for manager sessions, agents, pdus, varbinds, MIB inspection, and more.
8
10
 
9
11
  The gem also includes some useful executables including:
12
+
10
13
  - **net-snmp2**
11
14
  + An interactive REPL for inspecting the MIB, and acting as an SNMP manager.
12
15
  + Supports managing multiple agents at once.
@@ -18,6 +21,7 @@ The gem also includes some useful executables including:
18
21
  Features
19
22
  --------
20
23
 
24
+ * Improved Windows support over original net-snmp gem
21
25
  * Supports SNMP versions 1, 2c, and 3
22
26
  * Supports both synchronous and asynchronous calls
23
27
  * Supports sending of snmpv1 traps and snmpv2 traps/informs using TrapSession
@@ -26,3 +30,16 @@ Features
26
30
  * MIB support
27
31
  * Convenience methods such as session.walk, session.get_columns, and session.table
28
32
  * SNMP Agent support
33
+ * Trap handler support
34
+
35
+ Notes
36
+ -----
37
+
38
+ - TrapHandler & Agent support doesn't work on default Windows build of net-snmp libraries, due to certain functions not being exported in the dll.
39
+ + There is a [net-snmp-clone](https://github.com/jbreeden/net-snmp-clone) repo with the fixes made if you'd like to build this from source.
40
+ + Or, you can try my [pre-built DLL](https://github.com/jbreeden/net-snmp-clone/raw/master/win32/bin/release/netsnmp.dll) from the same repo.
41
+ + I've submitted this as a [feature request](https://sourceforge.net/p/net-snmp/feature-requests/181/) & patch to the net-snmp team. If it works for you, please go make a comment indicating that on the feature request to help it get pulled into the core library.
42
+ - Original gem was using a different comment format... I've opted for markdown. The generated rdocs are probably garbage.
43
+ + The [wiki](https://github.com/jbreeden/net-snmp2/wiki) has the best documentation for now.
44
+ + All the specs are passing, so that's another good place to go for information.
45
+ + There is also the built-in net-snmp2 program you can run. This is an interactive Pry shell that is very useful for digging around the code and getting a feel for how to do things.
@@ -1,4 +1,5 @@
1
1
  $: << '../lib'
2
+
2
3
  require 'net-snmp2'
3
4
 
4
5
  # Initialize SNMP and give it a logger
@@ -0,0 +1,23 @@
1
+ $: << '../lib'
2
+ require 'net-snmp2'
3
+
4
+ # Initialize SNMP and give it a logger
5
+ Net::SNMP.init
6
+ Net::SNMP::Debug.logger = Logger.new(STDOUT)
7
+ Net::SNMP::Debug.logger.level = Logger::INFO
8
+
9
+ session = Net::SNMP::TrapSession.open(:peername => 'localhost', :version => '2c', :community => 'public')
10
+
11
+ extend Net::SNMP::Debug
12
+
13
+ 100000.times do |i|
14
+ time "Inform ##{i}" do
15
+ puts "Inform #{i}: " + session.inform(
16
+ oid: '1.3.1.1',
17
+ uptime: 1000,
18
+ varbinds: [
19
+ {oid: '1.3.2.2', value: 'test'}
20
+ ]
21
+ ).to_s
22
+ end
23
+ end
@@ -35,6 +35,21 @@ handler = Net::SNMP::TrapHandler.new do
35
35
  Varbinds: #{varbinds.map {|vb| "#{vb.oid.label}(#{vb.oid}) = #{vb.value}"}.join(', ')}
36
36
  EOF
37
37
  end
38
+
39
+ inform do
40
+ info <<-EOF
41
+
42
+
43
+ Got Inform
44
+ ----------
45
+
46
+ Trap OID: #{trap_oid}
47
+ Uptime: #{uptime}
48
+ Varbinds: #{varbinds.map {|vb| "#{vb.oid.label}(#{vb.oid}) = #{vb.value}"}.join(', ')}
49
+ EOF
50
+
51
+ ok
52
+ end
38
53
  end
39
54
 
40
55
  # If the program gets the interrupt signal, tell the trap handler
@@ -6,19 +6,14 @@ Net::SNMP.init
6
6
  Net::SNMP::Debug.logger = Logger.new(STDOUT)
7
7
  Net::SNMP::Debug.logger.level = Logger::DEBUG
8
8
 
9
- puts "Opening session"
10
9
  session = Net::SNMP::TrapSession.open(:peername => 'localhost', :version => '1', :community => 'public')
11
10
 
12
- puts "Sending trap"
13
-
14
11
  100000.times do |i|
15
- session.trap(
12
+ puts "#{i + 1}: " + session.trap(
16
13
  enterprise: '1.3.1',
17
14
  trap_type: 6,
18
15
  specific_type: 1,
19
16
  uptime: 1000,
20
17
  agent_addr: '127.0.0.1'
21
- )
18
+ ).to_s
22
19
  end
23
-
24
- sleep 20
@@ -6,16 +6,11 @@ Net::SNMP.init
6
6
  Net::SNMP::Debug.logger = Logger.new(STDOUT)
7
7
  Net::SNMP::Debug.logger.level = Logger::DEBUG
8
8
 
9
- puts "Opening session"
10
9
  session = Net::SNMP::TrapSession.open(:peername => 'localhost', :version => '2c', :community => 'public')
11
10
 
12
- puts "Sending trap"
13
-
14
11
  100000.times do |i|
15
- puts session.trap_v2(
12
+ puts "#{i + 1}: " + session.trap_v2(
16
13
  oid: '1.3.1.1',
17
14
  uptime: 1000
18
- )
15
+ ).to_s
19
16
  end
20
-
21
- sleep 20
@@ -0,0 +1,17 @@
1
+ History
2
+ =======
3
+
4
+ Version 0.3.1
5
+ -------------
6
+
7
+ - Internal changes
8
+ + Adding source_address & source_port to message object
9
+ * Changes the callback signature for Listener#on_message
10
+ + Adding Message#respond method
11
+ * Used for creating a one-off session for responding to a message
12
+ and sending a single pdu over it. (Used in TrapHandler & Agent)
13
+
14
+ Version 0.3.0
15
+ -------------
16
+
17
+ - First gem release as net-snmp2
@@ -21,6 +21,7 @@ require 'logger'
21
21
  snmp/trap_handler/trap_handler
22
22
  snmp/trap_handler/v1_trap_dsl
23
23
  snmp/trap_handler/v2_trap_dsl
24
+ snmp/trap_handler/v2_inform_dsl
24
25
  snmp/mib/mib
25
26
  snmp/mib/node
26
27
  snmp/mib/module
@@ -29,7 +30,6 @@ require 'logger'
29
30
  snmp/agent/agent
30
31
  snmp/agent/provider
31
32
  snmp/agent/provider_dsl
32
- snmp/agent/request_dispatcher
33
33
  snmp/message
34
34
  ).each do |f|
35
35
  require "#{File.dirname(__FILE__)}/net/#{f}"
@@ -1,10 +1,8 @@
1
1
  module Net::SNMP
2
2
 
3
- # - Manages the request/response cycle for incoming messages
4
- # + Listens for incoming requests
5
- # + Parses request packets into Message objects
6
- # + Dispatches the messages to (sub) Agents
7
- # + Serializes the response from the subagents and sends it to the caller
3
+ # Agents delegate messages from the Net::SNMP::Listener to
4
+ # providers, which supply the actual responses to the varbinds
5
+ # in the request. See Net::SNMP::ProviderDsl
8
6
 
9
7
  class Agent
10
8
  include Debug
@@ -19,10 +17,16 @@ module Net::SNMP
19
17
  @listener.on_message(&method(:process_message))
20
18
  end
21
19
 
20
+ # This method is called with a block to define a provider
21
+ # for some subtree of the MIB. When a request comes in with varbinds
22
+ # in that providers subtree, the provider's handlers will be called
23
+ # to generate the varbind to send back in the response PDU.
24
+ #
25
+ # Arguments
26
+ #
27
+ # - oid: The root OID of the MIB subtree this provider is responsible for.
28
+ # - &block: A block, to be instance_evaled on the new Provider.
22
29
  def provide(oid = :all, &block)
23
- # Need a trailing dot on the oid so we can avoid
24
- # considering 1.3.22 a child of 1.3.2
25
- oid = (oid.to_sym == :all || oid.end_with?('.')) ? oid : "#{oid}."
26
30
  provider = Provider.new(oid)
27
31
  provider.instance_eval(&block)
28
32
 
@@ -35,13 +39,40 @@ module Net::SNMP
35
39
 
36
40
  private
37
41
 
38
- def process_message(message, from_address, from_port)
39
- response_pdu = RequestDispatcher.dispatch(message, providers)
40
- if response_pdu
41
- Session.open(peername: from_address, port: from_port, version: message.version_name) do |sess|
42
- sess.send_pdu response_pdu
42
+ # The callback given to the Listener object for handling an SNMP message.
43
+ # Calls `dispatch`, then sends the response PDU, if one is returned.
44
+ def process_message(message)
45
+ # TODO: May want to ignore some messages (say, if the community string is wrong)
46
+ message.respond(dispatch(message))
47
+ end
48
+
49
+ # Collects responses for the given message from the available providers
50
+ def dispatch(message)
51
+ response_pdu = message.make_response_pdu
52
+ context = ProviderDsl.new
53
+ context.message = message
54
+ context.response_pdu = response_pdu
55
+ message.pdu.varbinds.each_with_index do |vb, index|
56
+ context.varbind = vb
57
+ provider = providers.find { |p| p.provides?(vb.oid) }
58
+ if provider
59
+ if message.pdu.command == Constants::SNMP_MSG_GETBULK && index < message.pdu.non_repeaters
60
+ handler = provider.handler_for(Constants::SNMP_MSG_GETNEXT)
61
+ else
62
+ handler = provider.handler_for(message)
63
+ end
64
+ if handler
65
+ context.instance_exec(&handler)
66
+ else
67
+ warn "No handler for command: #{message.pdu.command} @ #{vb.oid}"
68
+ context.no_such_object
69
+ end
70
+ else
71
+ warn "No provider for oid: #{vb.oid}"
72
+ context.no_such_object
43
73
  end
44
74
  end
75
+ response_pdu
45
76
  end
46
77
 
47
78
  end
@@ -5,6 +5,39 @@ module Net::SNMP
5
5
  # of the subtree provided, and handlers for the various request types.
6
6
  # The handlers are executed for each varbind of the incoming message
7
7
  # individually in the context of a ProviderDsl object.
8
+ #
9
+ # Clients do not create Providers directly. Instead, they call `provide` on
10
+ # an Agent, passing in a block. Within the block they use the `get`, `get_next`,
11
+ # `get_bulk`, and `set` methods to configure handlers for these request types.
12
+ # Within these handlers, the DSL methods from the ProviderDsl class can be
13
+ # used to inspect the current request.
14
+ #
15
+ # Example
16
+ #
17
+ # require 'net-snmp2'
18
+ # agent = Net::SNMP::Agent.new
19
+ # agent.provide :all do
20
+ #
21
+ # get do
22
+ # reply get_value_somehow(oid)
23
+ # end
24
+ #
25
+ # set do
26
+ # reply set_value_somehow(oid)
27
+ # end
28
+ #
29
+ # get_next do
30
+ # reply get_next_value_somehow(oid)
31
+ # end
32
+ #
33
+ # get_bulk do
34
+ # (0..max_repetitions).each do |i|
35
+ # add get_bulk_vlue_somehow(oid, i)
36
+ # end
37
+ # end
38
+ #
39
+ # end
40
+ # agent.listen(161)
8
41
 
9
42
  class Provider
10
43
  attr_accessor :oid,
@@ -13,10 +46,26 @@ module Net::SNMP
13
46
  :get_next_handler,
14
47
  :get_bulk_handler
15
48
 
49
+ # Creates a new Provider with `oid` as the root of its subtree
16
50
  def initialize(oid)
17
- @oid = oid
51
+ if oid.kind_of?(Symbol)
52
+ unless oid == :all
53
+ raise "Cannot provide symbol '#{oid}'. (Did you mean to use :all?)"
54
+ end
55
+ @oid = oid
56
+ else
57
+ # Guarantee OID is in numeric form
58
+ @oid = OID.new(oid).to_s
59
+ end
18
60
  end
19
61
 
62
+ # Gets the handler for the given command type from this provider.
63
+ #
64
+ # Arguments
65
+ #
66
+ # - command
67
+ # + As an integer, specifies the command type a handler is needed for.
68
+ # + May also be a Message or PDU object, from which the command type is read.
20
69
  def handler_for(command)
21
70
  # User might be tempted to just pass in the message, or pdu,
22
71
  # if so, just pluck the command off of it.
@@ -40,6 +89,12 @@ module Net::SNMP
40
89
  end
41
90
  end
42
91
 
92
+ # Returns a boolean indicating whether this provider provides
93
+ # the given `oid`
94
+ def provides?(oid)
95
+ self.oid == :all || oid.to_s =~ %r[#{self.oid.to_s}(\.|$)]
96
+ end
97
+
43
98
  [:get, :set, :get_next, :get_bulk].each do |request_type|
44
99
  self.class_eval %Q[
45
100
  def #{request_type}(&proc)
@@ -38,6 +38,11 @@ module Net::SNMP
38
38
  varbind.oid
39
39
  end
40
40
 
41
+ # The MIB variable name of the current varbind
42
+ def variable
43
+ oid.label
44
+ end
45
+
41
46
  # The OID of the current varbind being processed as a string.
42
47
  def oid_str
43
48
  varbind.oid.to_s
@@ -101,6 +106,12 @@ module Net::SNMP
101
106
  add_varbind(oid: oid, type: Constants::SNMP_NOSUCHINSTANCE)
102
107
  end
103
108
 
109
+ # Adds a varbind to the response indicating that the END OF MIB has been reached
110
+ def end_of_mib
111
+ oid ||= varbind.oid
112
+ add_varbind(oid: oid, type: Constants::SNMP_ENDOFMIBVIEW)
113
+ end
114
+
104
115
  # Adds a varbind to the response PDU.
105
116
  # MUST use this method (or one that delegates to it)
106
117
  # to set response varbinds on the response_pdu to make sure
@@ -5,31 +5,22 @@ module Debug
5
5
  attr_accessor :logger
6
6
  end
7
7
 
8
- def debug(msg)
9
- Debug.logger.debug msg if Debug.logger
10
- end
11
-
12
- def info(msg)
13
- Debug.logger.info msg if Debug.logger
14
- end
15
-
16
- def warn(msg)
17
- Debug.logger.warn msg if Debug.logger
18
- end
19
-
20
- def error(msg)
21
- Debug.logger.error msg if Debug.logger
22
- end
23
-
24
- def fatal(msg)
25
- Debug.logger.fatal msg if Debug.logger
8
+ [:debug, :info, :warn, :error, :fatal].each do |log_level|
9
+ self.module_eval %Q{
10
+ def #{log_level}(msg = nil, &block)
11
+ if Debug.logger && (Debug.logger.level <= Logger::#{log_level.upcase})
12
+ Debug.logger.send(:#{log_level}, msg)
13
+ block[] if block_given?
14
+ end
15
+ end
16
+ }
26
17
  end
27
18
 
28
19
  def time(label, &block)
29
20
  t_start = Time.now
30
21
  block[]
31
22
  t_end = Time.now
32
- info "#{label}: #{(t_end - t_start)*1000}ms"
23
+ debug "#{label}: #{(t_end - t_start)*1000}ms"
33
24
  end
34
25
 
35
26
  def print_packet(packet)
@@ -1,6 +1,8 @@
1
1
  module Net
2
2
  module SNMP
3
3
  class Error < RuntimeError
4
+ include Debug
5
+
4
6
  attr_accessor :status, :errno, :snmp_err, :snmp_msg
5
7
  def initialize(opts = {})
6
8
  @status = opts[:status]
@@ -14,12 +16,17 @@ module Net
14
16
  end
15
17
 
16
18
  def print
17
- puts "SNMP Error: #{self.class.to_s}"
18
- puts "message = #{message}"
19
- puts "status = #{@status}"
20
- puts "errno = #{@errno}"
21
- puts "snmp_err = #{@snmp_err}"
22
- puts "snmp_msg = #{@snmp_msg}"
19
+ message = <<-EOF
20
+
21
+ SNMP Error: #{self.class.to_s}
22
+ message = #{message}
23
+ status = #{@status}
24
+ errno = #{@errno}
25
+ snmp_err = #{@snmp_err}
26
+ snmp_msg = #{@snmp_msg}
27
+ EOF
28
+
29
+ error(message.gsub /^\s*/, '')
23
30
  end
24
31
  end
25
32
 
@@ -37,13 +37,11 @@ module Net::SNMP
37
37
  #
38
38
  # The block provided will be called back for each message as follows:
39
39
  #
40
- # block[message, from_address, from_port]
40
+ # block[message]
41
41
  #
42
42
  # Where
43
43
  #
44
44
  # - `message` is the parsed Net::SNMP::Message object
45
- # - `from_address` is a string representing the address of the host sending the request
46
- # - `from_port` is the port the host sent the request from
47
45
  def on_message(&block)
48
46
  @callback = block
49
47
  end
@@ -62,7 +60,7 @@ module Net::SNMP
62
60
  return if @killed
63
61
  time "Message Processing" do
64
62
  message = Message.parse(@packet)
65
- @callback[message, @packet[1][3], @packet[1][1]] if @callback
63
+ @callback[message] if @callback
66
64
  end
67
65
  rescue Timeout::Error => timeout
68
66
  next