snmp4em 0.2.1 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +7 -0
- data/Manifest +19 -6
- data/{README → README.rdoc} +40 -37
- data/Rakefile +17 -0
- data/lib/snmp4em/{snmp_v1.rb → common_requests.rb} +6 -32
- data/lib/snmp4em/extensions/snmp/integer.rb +7 -0
- data/lib/snmp4em/extensions/snmp/ip_address.rb +7 -0
- data/lib/snmp4em/extensions/snmp/null.rb +11 -0
- data/lib/snmp4em/extensions/snmp/object_id.rb +7 -0
- data/lib/snmp4em/extensions/snmp/octet_string.rb +7 -0
- data/lib/snmp4em/extensions/snmp/response_error.rb +17 -0
- data/lib/snmp4em/extensions.rb +6 -0
- data/lib/snmp4em/handler.rb +14 -5
- data/lib/snmp4em/manager.rb +69 -0
- data/lib/snmp4em/requests/snmp_get_request.rb +13 -36
- data/lib/snmp4em/requests/snmp_getbulk_request.rb +7 -21
- data/lib/snmp4em/requests/snmp_getnext_request.rb +11 -39
- data/lib/snmp4em/requests/snmp_set_request.rb +10 -6
- data/lib/snmp4em/requests/snmp_walk_request.rb +51 -67
- data/lib/snmp4em/snmp_request.rb +24 -13
- data/lib/snmp4em/snmp_v2c_requests.rb +25 -0
- data/lib/snmp4em.rb +10 -6
- data/snmp4em.gemspec +15 -22
- data/spec/models/test_message.rb +7 -0
- data/spec/models/test_request.rb +10 -0
- data/spec/models/test_response.rb +7 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/unit/handler_spec.rb +34 -0
- data/spec/unit/manager_spec.rb +82 -0
- metadata +77 -51
- data/lib/snmp4em/common.rb +0 -39
- data/lib/snmp4em/snmp_connection.rb +0 -43
- data/lib/snmp4em/snmp_v2.rb +0 -104
@@ -1,60 +1,32 @@
|
|
1
1
|
module SNMP4EM
|
2
2
|
|
3
|
-
#
|
4
|
-
# or errback() to retrieve the results.
|
3
|
+
# This implements EM::Deferrable, so you can hang a callback() or errback() to retrieve the results.
|
5
4
|
|
6
5
|
class SnmpGetNextRequest < SnmpRequest
|
7
|
-
|
6
|
+
attr_accessor :snmp_id
|
8
7
|
|
9
8
|
# For an SNMP-GETNEXT request, @pending_oids will be a ruby array of SNMP::ObjectNames that need to be fetched. As
|
10
9
|
# responses come back from the agent, this array will be pruned of any error-producing OIDs. Once no errors
|
11
10
|
# are returned, the @responses hash will be populated and returned. The values of the hash will consist of a
|
12
11
|
# two-element array, in the form of [OID, VALUE], showing the next oid & value.
|
13
|
-
|
14
|
-
def initialize(sender, oids, args = {}) #:nodoc:
|
15
|
-
@sender = sender
|
16
|
-
|
17
|
-
@timeout_timer = nil
|
18
|
-
@timeout_retries = @sender.retries
|
19
|
-
@error_retries = oids.size
|
20
|
-
|
21
|
-
@return_raw = args[:return_raw] || false
|
22
|
-
|
23
|
-
@responses = Hash.new
|
24
|
-
@pending_oids = SNMP::VarBindList.new(oids).collect{|r| r.name}
|
25
|
-
|
26
|
-
init_callbacks
|
27
|
-
send
|
28
|
-
end
|
29
12
|
|
30
13
|
def handle_response(response) #:nodoc:
|
31
|
-
if
|
14
|
+
if response.error_status == :noError
|
32
15
|
# No errors, populate the @responses object so it can be returned
|
33
16
|
response.each_varbind do |vb|
|
34
17
|
request_oid = @pending_oids.shift
|
35
|
-
@
|
18
|
+
value = @return_raw || !vb.value.respond_to?(:rubify) ? vb.value : vb.value.rubify
|
19
|
+
@responses[request_oid.to_s] = [vb.name.to_s, value]
|
36
20
|
end
|
37
|
-
|
38
21
|
else
|
39
22
|
# Got an error, remove that oid from @pending_oids so we can try again
|
40
23
|
error_oid = @pending_oids.delete_at(response.error_index - 1)
|
41
24
|
@responses[error_oid.to_s] = SNMP::ResponseError.new(response.error_status)
|
42
25
|
end
|
43
|
-
|
44
|
-
if (@pending_oids.empty? || @error_retries.zero?)
|
45
|
-
until @pending_oids.empty?
|
46
|
-
error_oid = @pending_oids.shift
|
47
|
-
@responses[error_oid.to_s] = SNMP::ResponseError.new(:genErr)
|
48
|
-
end
|
49
26
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
else
|
54
|
-
@responses[oid] = value.rubify if (!@return_raw && value.respond_to?(:rubify))
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
27
|
+
if @error_retries < 0
|
28
|
+
fail "exhausted all retries"
|
29
|
+
elsif @pending_oids.empty?
|
58
30
|
# Send the @responses back to the requester, we're done!
|
59
31
|
succeed @responses
|
60
32
|
else
|
@@ -66,13 +38,13 @@ module SNMP4EM
|
|
66
38
|
private
|
67
39
|
|
68
40
|
def send #:nodoc:
|
69
|
-
|
41
|
+
Manager.track_request(self)
|
70
42
|
|
71
|
-
|
43
|
+
# Send the contents of @pending_oids
|
72
44
|
|
73
45
|
vb_list = SNMP::VarBindList.new(@pending_oids)
|
74
46
|
request = SNMP::GetNextRequest.new(@snmp_id, vb_list)
|
75
|
-
message = SNMP::Message.new(
|
47
|
+
message = SNMP::Message.new(@sender.version, @sender.community_ro, request)
|
76
48
|
|
77
49
|
super(message)
|
78
50
|
end
|
@@ -4,7 +4,7 @@ module SNMP4EM
|
|
4
4
|
# or errback() to retrieve the results.
|
5
5
|
|
6
6
|
class SnmpSetRequest < SnmpRequest
|
7
|
-
|
7
|
+
attr_accessor :snmp_id
|
8
8
|
|
9
9
|
# For an SNMP-SET request, @pending_varbinds will by an SNMP::VarBindList, initially populated from the
|
10
10
|
# provided oids hash. Variables can be passed as specific types from the SNMP library (i.e. SNMP::IpAddress)
|
@@ -13,22 +13,26 @@ module SNMP4EM
|
|
13
13
|
# are produced, the @responses object is populated and returned.
|
14
14
|
|
15
15
|
def initialize(sender, oids, args = {}) #:nodoc:
|
16
|
+
_oids = [*oids]
|
17
|
+
|
16
18
|
@sender = sender
|
17
19
|
|
18
20
|
@timeout_timer = nil
|
19
21
|
@timeout_retries = @sender.retries
|
20
|
-
@error_retries =
|
22
|
+
@error_retries = _oids.size
|
21
23
|
|
22
24
|
@return_raw = args[:return_raw] || false
|
23
25
|
|
24
26
|
@responses = Hash.new
|
25
27
|
@pending_varbinds = SNMP::VarBindList.new()
|
26
28
|
|
27
|
-
|
29
|
+
_oids.each do |oid,value|
|
28
30
|
if value.is_a? Integer
|
29
31
|
snmp_value = SNMP::Integer.new(value)
|
30
32
|
elsif value.is_a? String
|
31
33
|
snmp_value = SNMP::OctetString.new(value)
|
34
|
+
else
|
35
|
+
snmp_value = value
|
32
36
|
end
|
33
37
|
|
34
38
|
@pending_varbinds << SNMP::VarBind.new(oid,snmp_value)
|
@@ -76,13 +80,13 @@ module SNMP4EM
|
|
76
80
|
private
|
77
81
|
|
78
82
|
def send
|
83
|
+
Manager.track_request(self)
|
84
|
+
|
79
85
|
# Send the contents of @pending_varbinds
|
80
|
-
|
81
|
-
@snmp_id = generate_snmp_id
|
82
86
|
|
83
87
|
vb_list = SNMP::VarBindList.new(@pending_varbinds)
|
84
88
|
request = SNMP::SetRequest.new(@snmp_id, vb_list)
|
85
|
-
message = SNMP::Message.new(
|
89
|
+
message = SNMP::Message.new(@sender.version, @sender.community_ro, request)
|
86
90
|
|
87
91
|
super(message)
|
88
92
|
end
|
@@ -1,74 +1,47 @@
|
|
1
1
|
module SNMP4EM
|
2
2
|
|
3
|
-
#
|
4
|
-
# or errback() to retrieve the results.
|
3
|
+
# This implements EM::Deferrable, so you can hang a callback() or errback() to retrieve the results.
|
5
4
|
|
6
5
|
class SnmpWalkRequest < SnmpRequest
|
7
|
-
|
6
|
+
attr_accessor :snmp_id
|
8
7
|
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@timeout_timer = nil
|
20
|
-
@timeout_retries = @sender.retries
|
21
|
-
@error_retries = oids.size
|
22
|
-
|
23
|
-
@return_raw = args[:return_raw] || false
|
24
|
-
@max_results = args[:max_results] || nil
|
25
|
-
|
26
|
-
@responses = Hash.new
|
27
|
-
@pending_oids = SNMP::VarBindList.new(oids).collect{|r| r.name}
|
28
|
-
|
29
|
-
init_callbacks
|
30
|
-
send
|
31
|
-
end
|
32
|
-
|
8
|
+
# SNMP-WALK is faked using GETNEXT queries until the returned OID isn't a subtree of the walk OID.
|
9
|
+
#
|
10
|
+
# @next_oids is a hash that maps the base walk OID to the next OID to be queried.
|
11
|
+
#
|
12
|
+
# @query_indexes simply tracks the order in which the next_oids were packaged up, in order to
|
13
|
+
# determine which query left the subtree
|
14
|
+
#
|
15
|
+
# Note that this library supports walking multiple base OIDs in parallel, and that the walk fails
|
16
|
+
# atomically with a list of OIDS that failed to gather.
|
17
|
+
#
|
33
18
|
def handle_response(response) #:nodoc:
|
34
|
-
|
19
|
+
if response.error_status == :noError
|
35
20
|
|
36
|
-
if (response.error_status == :noError)
|
37
21
|
response.varbind_list.each_index do |i|
|
38
|
-
walk_oid = @pending_oids[i]
|
39
22
|
response_vb = response.varbind_list[i]
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@responses[walk_oid.to_s] << [response_vb.name, response_vb.value]
|
23
|
+
response_oid = response_vb.name
|
24
|
+
response_walk_oid = response_oid.dup; response_walk_oid.pop
|
25
|
+
|
26
|
+
if response_walk_oid.subtree_of?(@query_indexes[i])
|
27
|
+
value = @return_raw || !response_vb.value.respond_to?(:rubify) ? response_vb.value : response_vb.value.rubify
|
28
|
+
@responses[response_walk_oid.to_s][response_oid.dup.pop] = value
|
29
|
+
@next_oids[response_walk_oid] = response_oid
|
48
30
|
else
|
49
|
-
|
50
|
-
# @pending_oids[i] call above.
|
51
|
-
oids_to_delete << walk_oid
|
31
|
+
@next_oids.delete(@query_indexes[i])
|
52
32
|
end
|
53
33
|
end
|
54
34
|
|
55
35
|
@max_results -= 1 unless @max_results.nil?
|
56
|
-
|
57
36
|
else
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
@
|
37
|
+
@errors ||= []
|
38
|
+
error_oid = response.varbind_list[response.error_index].name
|
39
|
+
@errors << SNMP::ResponseError.new("Couldn't gather: #{error_oid} -> #{response.error_status}")
|
40
|
+
fail @errors if @error_retries < 1
|
62
41
|
@error_retries -= 1
|
63
42
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
if (@pending_oids.empty? || (@error_retries < 0) || (@max_results.to_i < 0))
|
68
|
-
@responses.each_pair do |oid, value|
|
69
|
-
@responses[oid] = value.rubify if (!@return_raw && value.respond_to?(:rubify))
|
70
|
-
end
|
71
|
-
|
43
|
+
|
44
|
+
if @next_oids.empty? || @max_results.to_i < 0
|
72
45
|
# Send the @responses back to the requester, we're done!
|
73
46
|
succeed @responses
|
74
47
|
else
|
@@ -79,24 +52,35 @@ module SNMP4EM
|
|
79
52
|
private
|
80
53
|
|
81
54
|
def send
|
82
|
-
|
55
|
+
Manager.track_request(self)
|
83
56
|
|
84
|
-
#
|
85
|
-
|
86
|
-
|
87
|
-
@
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
oids << oid
|
57
|
+
#
|
58
|
+
# @next_oids maps the walk oid to its next getnext oid
|
59
|
+
#
|
60
|
+
unless @next_oids
|
61
|
+
@responses = {}
|
62
|
+
@next_oids = {}
|
63
|
+
@pending_oids.each do |walk_oid|
|
64
|
+
@next_oids[walk_oid] = walk_oid
|
65
|
+
@responses[walk_oid.to_s] = {}
|
94
66
|
end
|
95
67
|
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# @query_indexes maps the index of the requested oid to the walk oid
|
71
|
+
#
|
72
|
+
i = 0
|
73
|
+
@query_indexes = {}
|
74
|
+
query_oids = \
|
75
|
+
@next_oids.collect do |walk_oid, next_oid|
|
76
|
+
@query_indexes[i] = walk_oid
|
77
|
+
i += 1
|
78
|
+
next_oid
|
79
|
+
end
|
96
80
|
|
97
|
-
vb_list = SNMP::VarBindList.new(
|
81
|
+
vb_list = SNMP::VarBindList.new(query_oids)
|
98
82
|
request = SNMP::GetNextRequest.new(@snmp_id, vb_list)
|
99
|
-
message = SNMP::Message.new(
|
83
|
+
message = SNMP::Message.new(@sender.version, @sender.community_ro, request)
|
100
84
|
|
101
85
|
super(message)
|
102
86
|
end
|
data/lib/snmp4em/snmp_request.rb
CHANGED
@@ -1,24 +1,35 @@
|
|
1
1
|
module SNMP4EM
|
2
2
|
class SnmpRequest #:nodoc:
|
3
3
|
include EM::Deferrable
|
4
|
-
|
5
|
-
def generate_snmp_id
|
6
|
-
begin
|
7
|
-
snmp_id = rand(1073741823) # Largest Fixnum
|
8
|
-
end until (SnmpConnection.pending_requests.select{|r| r.snmp_id == snmp_id}.empty?)
|
9
4
|
|
10
|
-
|
11
|
-
|
5
|
+
attr_accessor :timeout_timer
|
6
|
+
|
7
|
+
def initialize(sender, oids, args = {}) #:nodoc:
|
8
|
+
_oids = [*oids]
|
9
|
+
|
10
|
+
@sender = sender
|
11
|
+
|
12
|
+
@timeout_timer = nil
|
13
|
+
@timeout_retries = @sender.retries
|
14
|
+
@error_retries = _oids.size
|
15
|
+
|
16
|
+
@return_raw = args[:return_raw] || false
|
17
|
+
|
18
|
+
@responses = {}
|
19
|
+
@pending_oids = _oids.collect { |oid_str| SNMP::ObjectId.new(oid_str) }
|
12
20
|
|
21
|
+
init_callbacks
|
22
|
+
send
|
23
|
+
end
|
24
|
+
|
13
25
|
def init_callbacks
|
14
26
|
self.callback do
|
15
|
-
|
16
|
-
@timeout_timer.cancel
|
27
|
+
Manager.pending_requests.delete(@snmp_id)
|
17
28
|
end
|
18
29
|
|
19
30
|
self.errback do
|
20
|
-
SnmpConnection.pending_requests.delete_if {|r| r.snmp_id == @snmp_id}
|
21
31
|
@timeout_timer.cancel
|
32
|
+
Manager.pending_requests.delete(@snmp_id)
|
22
33
|
end
|
23
34
|
end
|
24
35
|
|
@@ -28,13 +39,13 @@ module SNMP4EM
|
|
28
39
|
@timeout_timer.cancel if @timeout_timer.is_a?(EM::Timer)
|
29
40
|
|
30
41
|
@timeout_timer = EM::Timer.new(@sender.timeout) do
|
31
|
-
if
|
42
|
+
if @timeout_retries > 0
|
32
43
|
send
|
33
44
|
@timeout_retries -= 1
|
34
45
|
else
|
35
|
-
fail
|
46
|
+
fail "exhausted all timeout retries"
|
36
47
|
end
|
37
48
|
end
|
38
49
|
end
|
39
50
|
end
|
40
|
-
end
|
51
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# The SNMP4EM library
|
2
|
+
|
3
|
+
module SNMP4EM
|
4
|
+
module SNMPv2cRequests
|
5
|
+
# Sends an SNMPv2 GET-BULK request to fetch multiple OID-value pairings simultaneously. This produces similar results to an SNMP-WALK using a single
|
6
|
+
# request/response transaction (SNMP-WALK is actually an inefficient series of GET-NEXTs). Multiple OIDs can be passed into the _oids_ array. Two
|
7
|
+
# additional parameters control how this list is processed. Setting the parameter _nonrepeaters_ to value _N_ indicates that the first _N_ OIDs will
|
8
|
+
# fetch a single value. This is identical to running a single GET-NEXT for the OID. Any remaining OIDs will fetch multiple values. The number of values
|
9
|
+
# fetched is controlled by the parameter _maxrepetitions_. The function returns a SnmpGetBulkRequest object, which implements EM::Deferrable. From there,
|
10
|
+
# implement a callback/errback to fetch the result. On success, the result will be a hash, mapping requested OID prefixes to the returned value.
|
11
|
+
# Successful fetches will be mapped to an array of two-element arrays, each of which consists of [_oid_ , _value_]. Unsuccessful fetches will be mapped to a
|
12
|
+
# symbol representing the error.
|
13
|
+
|
14
|
+
# For more information, see http://tools.ietf.org/html/rfc1905#section-4.2.3
|
15
|
+
|
16
|
+
# Optional arguments can be passed into _args_, including:
|
17
|
+
# * _return_raw_ - Return objects and errors as their raw SNMP types, such as SNMP::Integer instead of native Ruby integers, SNMP::OctetString instead of native Ruby strings, etc. (default: false)
|
18
|
+
# * _nonrepeaters_ - Number of OIDs passed to which exactly one result will be returned (default is 0)
|
19
|
+
# * _maxrepetitions_ - Number of OID-value pairs to be returned for each OID (default is 10)
|
20
|
+
|
21
|
+
def getbulk(oids, args = {})
|
22
|
+
SnmpGetBulkRequest.new(self, oids, args.merge(:version => @version))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/snmp4em.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
|
-
$:.unshift File.
|
1
|
+
$:.unshift File.dirname(File.expand_path(__FILE__))
|
2
|
+
|
3
|
+
gem "eventmachine", ">= 0.12.10"
|
4
|
+
gem "snmp", ">= 1.0.2"
|
2
5
|
|
3
6
|
require 'eventmachine'
|
4
7
|
require 'snmp'
|
5
|
-
|
8
|
+
|
9
|
+
require 'snmp4em/extensions'
|
6
10
|
require 'snmp4em/handler'
|
7
|
-
require 'snmp4em/
|
8
|
-
require 'snmp4em/
|
9
|
-
require 'snmp4em/
|
11
|
+
require 'snmp4em/common_requests'
|
12
|
+
require 'snmp4em/manager'
|
13
|
+
require 'snmp4em/snmp_v2c_requests'
|
10
14
|
require 'snmp4em/snmp_request'
|
11
15
|
require 'snmp4em/requests/snmp_get_request'
|
12
16
|
require 'snmp4em/requests/snmp_getbulk_request'
|
13
17
|
require 'snmp4em/requests/snmp_getnext_request'
|
14
18
|
require 'snmp4em/requests/snmp_set_request'
|
15
|
-
require 'snmp4em/requests/snmp_walk_request'
|
19
|
+
require 'snmp4em/requests/snmp_walk_request'
|
data/snmp4em.gemspec
CHANGED
@@ -1,30 +1,23 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
-
s.name =
|
5
|
-
s.version = "0.
|
4
|
+
s.name = "snmp4em"
|
5
|
+
s.version = "0.3"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Norman Elton"]
|
9
|
-
s.date =
|
10
|
-
s.description =
|
11
|
-
s.email =
|
12
|
-
s.extra_rdoc_files = ["README"]
|
13
|
-
s.files = ["lib/snmp4em.rb", "lib/snmp4em/
|
14
|
-
s.homepage =
|
15
|
-
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Snmp4em", "--main", "README"]
|
9
|
+
s.date = "2012-02-23"
|
10
|
+
s.description = "A high-performance SNMP engine built on EventMachine and Ruby-SNMP"
|
11
|
+
s.email = "normelton@gmail.com"
|
12
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
13
|
+
s.files = ["Gemfile", "README.rdoc", "Rakefile", "lib/snmp4em.rb", "lib/snmp4em/common_requests.rb", "lib/snmp4em/extensions.rb", "lib/snmp4em/extensions/snmp/integer.rb", "lib/snmp4em/extensions/snmp/ip_address.rb", "lib/snmp4em/extensions/snmp/null.rb", "lib/snmp4em/extensions/snmp/object_id.rb", "lib/snmp4em/extensions/snmp/octet_string.rb", "lib/snmp4em/extensions/snmp/response_error.rb", "lib/snmp4em/handler.rb", "lib/snmp4em/manager.rb", "lib/snmp4em/requests/snmp_get_request.rb", "lib/snmp4em/requests/snmp_getbulk_request.rb", "lib/snmp4em/requests/snmp_getnext_request.rb", "lib/snmp4em/requests/snmp_set_request.rb", "lib/snmp4em/requests/snmp_walk_request.rb", "lib/snmp4em/snmp_request.rb", "lib/snmp4em/snmp_v2c_requests.rb", "snmp4em.gemspec", "spec/models/test_message.rb", "spec/models/test_request.rb", "spec/models/test_response.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/unit/handler_spec.rb", "spec/unit/manager_spec.rb", "Manifest"]
|
14
|
+
s.homepage = "http://github.com/normelton/snmp4em"
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Snmp4em", "--main", "README.rdoc"]
|
16
16
|
s.require_paths = ["lib"]
|
17
|
-
s.rubyforge_project =
|
18
|
-
s.rubygems_version =
|
19
|
-
s.summary =
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
s.specification_version = 3
|
24
|
-
|
25
|
-
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
-
else
|
27
|
-
end
|
28
|
-
else
|
29
|
-
end
|
17
|
+
s.rubyforge_project = "snmp4em"
|
18
|
+
s.rubygems_version = "1.8.16"
|
19
|
+
s.summary = "A high-performance SNMP engine built on EventMachine and Ruby-SNMP"
|
20
|
+
s.add_runtime_dependency 'snmp', '>= 1.0.2'
|
21
|
+
s.add_runtime_dependency 'eventmachine', '>= 1.0.0'
|
22
|
+
|
30
23
|
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
3
|
+
|
4
|
+
MODELS = File.join(File.dirname(__FILE__), "models")
|
5
|
+
$LOAD_PATH.unshift(MODELS)
|
6
|
+
Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require "spec"
|
10
|
+
require "snmp4em"
|
11
|
+
|
12
|
+
def em
|
13
|
+
EM.run {
|
14
|
+
yield
|
15
|
+
EM.stop
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SNMP4EM::Handler do
|
4
|
+
|
5
|
+
before do
|
6
|
+
SNMP4EM::Manager.class_eval do
|
7
|
+
@pending_requests = {}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#receive_data" do
|
12
|
+
|
13
|
+
it "should match responses to requests" do
|
14
|
+
em do
|
15
|
+
response = SNMP4EM::TestResponse.new
|
16
|
+
response.request_id = 1
|
17
|
+
|
18
|
+
message = SNMP4EM::TestMessage.new
|
19
|
+
message.pdu = response
|
20
|
+
SNMP::Message.should_receive(:decode).and_return(message)
|
21
|
+
|
22
|
+
request = SNMP4EM::TestRequest.new
|
23
|
+
SNMP4EM::Manager.should_receive(:rand).and_return(1)
|
24
|
+
SNMP4EM::Manager.track_request(request)
|
25
|
+
|
26
|
+
request.should_receive(:handle_response).with(response)
|
27
|
+
SNMP4EM::Handler.new(nil).receive_data(nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SNMP4EM::Manager do
|
4
|
+
|
5
|
+
before do
|
6
|
+
SNMP4EM::Manager.class_eval do
|
7
|
+
@pending_requests = {}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#track_request" do
|
12
|
+
|
13
|
+
it "should assign a random and unique id to each request" do
|
14
|
+
em do
|
15
|
+
request = SNMP4EM::TestRequest.new
|
16
|
+
other_request = SNMP4EM::TestRequest.new
|
17
|
+
|
18
|
+
SNMP4EM::Manager.should_receive(:rand).and_return(1, 1, 2)
|
19
|
+
SNMP4EM::Manager.track_request(request)
|
20
|
+
SNMP4EM::Manager.track_request(other_request)
|
21
|
+
|
22
|
+
request.snmp_id.should == 1
|
23
|
+
other_request.snmp_id.should == 2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should prune requests when their request id changes" do
|
28
|
+
em do
|
29
|
+
request = SNMP4EM::TestRequest.new
|
30
|
+
|
31
|
+
SNMP4EM::Manager.should_receive(:rand).and_return(1, 2)
|
32
|
+
SNMP4EM::Manager.track_request(request)
|
33
|
+
request.snmp_id.should == 1
|
34
|
+
SNMP4EM::Manager.pending_requests.size.should == 1
|
35
|
+
|
36
|
+
SNMP4EM::Manager.track_request(request)
|
37
|
+
request.snmp_id.should == 2
|
38
|
+
SNMP4EM::Manager.pending_requests.size.should == 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#initialize" do
|
45
|
+
|
46
|
+
it "should default to v2c" do
|
47
|
+
em do
|
48
|
+
SNMP4EM::Manager.new.version.should == :SNMPv2c
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should create the class' UDP socket" do
|
53
|
+
em do
|
54
|
+
SNMP4EM::Manager.new
|
55
|
+
SNMP4EM::Manager.socket.should be_a EventMachine::Connection
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
context "when using v2c" do
|
61
|
+
|
62
|
+
it "should acquire the #getbulk method" do
|
63
|
+
em do
|
64
|
+
SNMP4EM::Manager.new.methods.should include :getbulk
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when using v1" do
|
71
|
+
|
72
|
+
it "should not acquire the #getbulk method" do
|
73
|
+
em do
|
74
|
+
SNMP4EM::Manager.new(:version => :SNMPv1).methods.should_not include :getbulk
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|