snmp4em 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest +16 -0
- data/README +156 -0
- data/lib/snmp4em/common.rb +39 -0
- data/lib/snmp4em/handler.rb +18 -0
- data/lib/snmp4em/requests/snmp_get_request.rb +76 -0
- data/lib/snmp4em/requests/snmp_getbulk_request.rb +103 -0
- data/lib/snmp4em/requests/snmp_getnext_request.rb +80 -0
- data/lib/snmp4em/requests/snmp_set_request.rb +90 -0
- data/lib/snmp4em/requests/snmp_walk_request.rb +104 -0
- data/lib/snmp4em/snmp_connection.rb +43 -0
- data/lib/snmp4em/snmp_request.rb +40 -0
- data/lib/snmp4em/snmp_v1.rb +82 -0
- data/lib/snmp4em/snmp_v2.rb +104 -0
- data/lib/snmp4em.rb +15 -0
- data/snmp4em.gemspec +30 -0
- metadata +74 -0
data/Manifest
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
README
|
2
|
+
Rakefile
|
3
|
+
lib/snmp4em.rb
|
4
|
+
lib/snmp4em/common.rb
|
5
|
+
lib/snmp4em/handler.rb
|
6
|
+
lib/snmp4em/requests/snmp_get_request.rb
|
7
|
+
lib/snmp4em/requests/snmp_getbulk_request.rb
|
8
|
+
lib/snmp4em/requests/snmp_getnext_request.rb
|
9
|
+
lib/snmp4em/requests/snmp_set_request.rb
|
10
|
+
lib/snmp4em/requests/snmp_walk_request.rb
|
11
|
+
lib/snmp4em/snmp_connection.rb
|
12
|
+
lib/snmp4em/snmp_request.rb
|
13
|
+
lib/snmp4em/snmp_v1.rb
|
14
|
+
lib/snmp4em/snmp_v2.rb
|
15
|
+
snmp4em.gemspec
|
16
|
+
Manifest
|
data/README
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
= SNMP Library for EventMachine
|
2
|
+
|
3
|
+
== Summary
|
4
|
+
|
5
|
+
This library extends the Ruby-SNMP[http://snmplib.rubyforge.org] to use the asynchronous EventMachine[http://rubyeventmachine.com] 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.
|
6
|
+
|
7
|
+
|
8
|
+
== Features
|
9
|
+
|
10
|
+
The initial version 0.1.0 of this software supports:
|
11
|
+
|
12
|
+
* SNMP v1 and v2 only
|
13
|
+
* SNMP Get, GetNext, GetBulk (v2 only), Set, and Walk requests.
|
14
|
+
* Ability to query/set/walk multiple OIDs in parallel.
|
15
|
+
|
16
|
+
Future revisions of this library may support:
|
17
|
+
|
18
|
+
* Ability to act as an SNMP agent, responding to external queries.
|
19
|
+
* Ability to send/receive SNMP traps
|
20
|
+
|
21
|
+
There are no plans to support SNMP v3.
|
22
|
+
|
23
|
+
|
24
|
+
== Acknowledgements
|
25
|
+
|
26
|
+
* The SNMP packet processing is handled by the Ruby-SNMP[http://snmplib.rubyforge.org] library, by David Halliday
|
27
|
+
* EventMachine[http://rubyeventmachine.com], by Francis Cianfrocca and Aman Gupta
|
28
|
+
* All the helpful folks on the Freenode #eventmachine channel
|
29
|
+
|
30
|
+
|
31
|
+
== Examples
|
32
|
+
|
33
|
+
A few definitions:
|
34
|
+
|
35
|
+
OID_SYSTEM = "1.3.6.1.2.1.1"
|
36
|
+
OID_SYSNAME = "1.3.6.1.2.1.1.5.0"
|
37
|
+
OID_SYSLOCATION = "1.3.6.1.2.1.1.6.0"
|
38
|
+
|
39
|
+
A simple SNMP-GET:
|
40
|
+
|
41
|
+
EM::run do
|
42
|
+
snmp = SNMP4EM::SNMPv1.new(:host => "192.168.1.1")
|
43
|
+
|
44
|
+
request = snmp.get([OID_SYSNAME, OID_SYSLOCATION])
|
45
|
+
|
46
|
+
request.callback do |response|
|
47
|
+
puts "System name = #{response[OID_SYSNAME]}"
|
48
|
+
puts "System location = #{response[OID_SYSLOCATION]}"
|
49
|
+
end
|
50
|
+
|
51
|
+
request.errback do |error|
|
52
|
+
puts "GET got error #{error}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
A simple SNMP-GETNEXT:
|
57
|
+
|
58
|
+
EM::run do
|
59
|
+
snmp = SNMP4EM::SNMPv1.new(:host => "192.168.1.1")
|
60
|
+
|
61
|
+
request = snmp.getnext([OID_SYSNAME])
|
62
|
+
|
63
|
+
request.callback do |response|
|
64
|
+
r = response[OID_SYSNAME]
|
65
|
+
puts "The next OID is #{r[0]}, the next value is #{r[1]}"
|
66
|
+
end
|
67
|
+
|
68
|
+
request.errback do |error|
|
69
|
+
puts "GET got error #{error}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
A simple SNMP-SET:
|
74
|
+
|
75
|
+
EM::run do
|
76
|
+
snmp = SNMP4EM::SNMPv1.new(:host => "192.168.1.1")
|
77
|
+
|
78
|
+
request = snmp.set({OID_SYSNAME => "My System Name", OID_SYSLOCATION => "My System Location"})
|
79
|
+
|
80
|
+
request.callback do |response|
|
81
|
+
if (response[OID_SYSNAME] == true)
|
82
|
+
puts "System name set successful"
|
83
|
+
else
|
84
|
+
puts "System name set unsuccessful: #{response[OID_SYSNAME]}"
|
85
|
+
end
|
86
|
+
|
87
|
+
if (response[OID_SYSLOCATION] == true)
|
88
|
+
puts "System location set successful"
|
89
|
+
else
|
90
|
+
puts "System location set unsuccessful: #{response[OID_SYSLOCATION]}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
request.errback do |error|
|
95
|
+
puts "GET got error #{error}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
A simple SNMP-WALK:
|
100
|
+
|
101
|
+
EM::run do
|
102
|
+
snmp = SNMP4EM::SNMPv1.new(:host => "192.168.1.1")
|
103
|
+
|
104
|
+
request = snmp.walk([OID_SYSTEM])
|
105
|
+
|
106
|
+
request.callback do |response|
|
107
|
+
if (response[OID_SYSTEM].is_a? Array)
|
108
|
+
response[OID_SYSTEM].each do |vb|
|
109
|
+
puts "#{vb[0]} = #{vb[1]}"
|
110
|
+
end
|
111
|
+
else
|
112
|
+
puts "Got error: #{response[OID_SYSTEM]}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
request.errback do |error|
|
117
|
+
puts "GET got error #{error}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
A simple SNMP-GET-BULK:
|
122
|
+
|
123
|
+
EM::run do
|
124
|
+
snmp = SNMP4EM::SNMPv2.new(:host => "192.168.1.1")
|
125
|
+
|
126
|
+
request = snmp.getbulk([OID_SYSTEM])
|
127
|
+
|
128
|
+
request.callback do |response|
|
129
|
+
if (response[OID_SYSTEM].is_a? Array)
|
130
|
+
response[OID_SYSTEM].each do |vb|
|
131
|
+
puts "#{vb[0]} = #{vb[1]}"
|
132
|
+
end
|
133
|
+
else
|
134
|
+
puts "Got error: #{response[OID_SYSTEM]}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
request.errback do |error|
|
139
|
+
puts "GET got error #{error}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
== Change Log
|
144
|
+
|
145
|
+
Version 0.1.0:
|
146
|
+
|
147
|
+
* Initial deployment, ability to run get/getnext/set/walk requests in parallel
|
148
|
+
|
149
|
+
Version 0.2.0:
|
150
|
+
|
151
|
+
* Added support for SNMPv2, including GET-BULK operations
|
152
|
+
|
153
|
+
== Developer Contact Information
|
154
|
+
|
155
|
+
Norman Elton
|
156
|
+
normelton@gmail.com
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SNMP #:nodoc:
|
2
|
+
class Null #:nodoc:
|
3
|
+
class << self
|
4
|
+
def rubify
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class OctetString #:nodoc:
|
11
|
+
alias :rubify :to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
class Integer #:nodoc:
|
15
|
+
alias :rubify :to_i
|
16
|
+
end
|
17
|
+
|
18
|
+
class ObjectId #:nodoc:
|
19
|
+
alias :rubify :to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
class IpAddress #:nodoc:
|
23
|
+
alias :rubify :to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
class ResponseError
|
27
|
+
attr_reader :error_status
|
28
|
+
alias :rubify :error_status #:nodoc:
|
29
|
+
|
30
|
+
def initialize(error_status) #:nodoc:
|
31
|
+
@error_status = error_status
|
32
|
+
end
|
33
|
+
|
34
|
+
# String representation of this error
|
35
|
+
def to_s
|
36
|
+
@error_status.to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SNMP4EM
|
2
|
+
module Handler #:nodoc:
|
3
|
+
def receive_data(data)
|
4
|
+
begin
|
5
|
+
message = SNMP::Message.decode(data)
|
6
|
+
rescue Exception => err
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
response = message.pdu
|
11
|
+
request_id = response.request_id
|
12
|
+
|
13
|
+
if (request = SnmpConnection.pending_requests.select{|r| r.snmp_id == request_id}.first)
|
14
|
+
request.handle_response(response)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module SNMP4EM
|
2
|
+
|
3
|
+
# Returned from SNMP4EM::SNMPv1.get(). This implements EM::Deferrable, so you can hang a callback()
|
4
|
+
# or errback() to retrieve the results.
|
5
|
+
|
6
|
+
class SnmpGetRequest < SnmpRequest
|
7
|
+
attr_reader :snmp_id
|
8
|
+
|
9
|
+
# For an SNMP-GET request, @pending_oids will be a ruby array of SNMP::ObjectNames that need to be fetched. As
|
10
|
+
# responses come back from the agent, this array will be pruned of any error-producing OIDs. Once no errors
|
11
|
+
# are returned, the @responses hash will be populated and returned.
|
12
|
+
|
13
|
+
def initialize(sender, oids, args = {}) #:nodoc:
|
14
|
+
@sender = sender
|
15
|
+
|
16
|
+
@timeout_timer = nil
|
17
|
+
@timeout_retries = @sender.retries
|
18
|
+
@error_retries = oids.size
|
19
|
+
|
20
|
+
@version = args[:version] || :SNMPv1
|
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
|
+
|
30
|
+
def handle_response(response) #:nodoc:
|
31
|
+
if (response.error_status == :noError)
|
32
|
+
# No errors, populate the @responses object so it can be returned
|
33
|
+
response.each_varbind do |vb|
|
34
|
+
request_oid = @pending_oids.shift
|
35
|
+
@responses[request_oid.to_s] = vb.value
|
36
|
+
end
|
37
|
+
|
38
|
+
else
|
39
|
+
# Got an error, remove that oid from @pending_oids so we can try again
|
40
|
+
error_oid = @pending_oids.delete_at(response.error_index - 1)
|
41
|
+
@responses[error_oid.to_s] = SNMP::ResponseError.new(response.error_status)
|
42
|
+
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
|
+
|
50
|
+
@responses.each_pair do |oid, value|
|
51
|
+
@responses[oid] = value.rubify if (!@return_raw && value.respond_to?(:rubify))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Send the @responses back to the requester, we're done!
|
55
|
+
succeed @responses
|
56
|
+
else
|
57
|
+
@error_retries -= 1
|
58
|
+
send
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def send
|
65
|
+
# Send the contents of @pending_oids
|
66
|
+
|
67
|
+
@snmp_id = generate_snmp_id
|
68
|
+
|
69
|
+
vb_list = SNMP::VarBindList.new(@pending_oids)
|
70
|
+
request = SNMP::GetRequest.new(@snmp_id, vb_list)
|
71
|
+
message = SNMP::Message.new(@version, @sender.community_ro, request)
|
72
|
+
|
73
|
+
super(message)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module SNMP4EM
|
2
|
+
|
3
|
+
# Returned from SNMP4EM::SNMPv1.get(). This implements EM::Deferrable, so you can hang a callback()
|
4
|
+
# or errback() to retrieve the results.
|
5
|
+
|
6
|
+
class SnmpGetBulkRequest < SnmpRequest
|
7
|
+
attr_reader :snmp_id
|
8
|
+
|
9
|
+
# For an SNMP-GETBULK request, @pending_oids will be a ruby array of SNMP::ObjectNames that need to be fetched. As
|
10
|
+
# responses come back from the agent, this array will be pruned of any error-producing OIDs. Once no errors
|
11
|
+
# are returned, the @responses hash will be populated and returned.
|
12
|
+
|
13
|
+
def initialize(sender, oids, args = {}) #:nodoc:
|
14
|
+
@sender = sender
|
15
|
+
|
16
|
+
@timeout_timer = nil
|
17
|
+
@timeout_retries = @sender.retries
|
18
|
+
@error_retries = oids.size
|
19
|
+
|
20
|
+
@version = args[:version] || :SNMPv2c
|
21
|
+
@return_raw = args[:return_raw] || false
|
22
|
+
|
23
|
+
@nonrepeaters = args[:nonrepeaters] || 0
|
24
|
+
@maxrepetitions = args[:maxrepetitions] || 10
|
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
|
+
|
33
|
+
def handle_response(response) #:nodoc:
|
34
|
+
if (response.error_status == :noError)
|
35
|
+
# No errors, populate the @responses object so it can be returned
|
36
|
+
|
37
|
+
@nonrepeaters.times do |i|
|
38
|
+
request_oid = @pending_oids.shift
|
39
|
+
response_vb = response.vb_list[i]
|
40
|
+
|
41
|
+
@responses[request_oid.to_s] = [[response_vb.name, response_vb.value]]
|
42
|
+
end
|
43
|
+
|
44
|
+
(@nonrepeaters ... response.vb_list.size).each do |i|
|
45
|
+
request_oid = @pending_oids[(i - @nonrepeaters) % @pending_oids.size]
|
46
|
+
response_vb = response.vb_list[i]
|
47
|
+
|
48
|
+
@responses[request_oid.to_s] ||= Array.new
|
49
|
+
@responses[request_oid.to_s] << [response_vb.name, response_vb.value]
|
50
|
+
end
|
51
|
+
|
52
|
+
@pending_oids.clear
|
53
|
+
|
54
|
+
else
|
55
|
+
# Got an error, remove that oid from @pending_oids so we can try again
|
56
|
+
error_oid = @pending_oids.delete_at(response.error_index - 1)
|
57
|
+
@responses[error_oid.to_s] = SNMP::ResponseError.new(response.error_status)
|
58
|
+
end
|
59
|
+
|
60
|
+
if (@pending_oids.empty? || @error_retries.zero?)
|
61
|
+
until @pending_oids.empty?
|
62
|
+
error_oid = @pending_oids.shift
|
63
|
+
@responses[error_oid.to_s] = SNMP::ResponseError.new(:genErr)
|
64
|
+
end
|
65
|
+
|
66
|
+
if (!@return_raw)
|
67
|
+
@responses.each_pair do |search_oid, values|
|
68
|
+
values.collect! do |oid_value|
|
69
|
+
oid_value[1] = oid_value[1].rubify if oid_value[1].respond_to?(:rubify)
|
70
|
+
oid_value
|
71
|
+
end
|
72
|
+
|
73
|
+
@responses[search_oid] = values
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Send the @responses back to the requester, we're done!
|
78
|
+
succeed @responses
|
79
|
+
else
|
80
|
+
@error_retries -= 1
|
81
|
+
send
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def send
|
88
|
+
# Send the contents of @pending_oids
|
89
|
+
|
90
|
+
@snmp_id = generate_snmp_id
|
91
|
+
|
92
|
+
vb_list = SNMP::VarBindList.new(@pending_oids)
|
93
|
+
request = SNMP::GetBulkRequest.new(@snmp_id, vb_list)
|
94
|
+
|
95
|
+
request.max_repetitions = @maxrepetitions
|
96
|
+
request.non_repeaters = @nonrepeaters
|
97
|
+
|
98
|
+
message = SNMP::Message.new(@version, @sender.community_ro, request)
|
99
|
+
|
100
|
+
super(message)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module SNMP4EM
|
2
|
+
|
3
|
+
# Returned from SNMP4EM::SNMPv1.getnext(). This implements EM::Deferrable, so you can hang a callback()
|
4
|
+
# or errback() to retrieve the results.
|
5
|
+
|
6
|
+
class SnmpGetNextRequest < SnmpRequest
|
7
|
+
attr_reader :snmp_id
|
8
|
+
|
9
|
+
# For an SNMP-GETNEXT request, @pending_oids will be a ruby array of SNMP::ObjectNames that need to be fetched. As
|
10
|
+
# responses come back from the agent, this array will be pruned of any error-producing OIDs. Once no errors
|
11
|
+
# are returned, the @responses hash will be populated and returned. The values of the hash will consist of a
|
12
|
+
# 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
|
+
|
30
|
+
def handle_response(response) #:nodoc:
|
31
|
+
if (response.error_status == :noError)
|
32
|
+
# No errors, populate the @responses object so it can be returned
|
33
|
+
response.each_varbind do |vb|
|
34
|
+
request_oid = @pending_oids.shift
|
35
|
+
@responses[request_oid.to_s] = [vb.name, vb.value]
|
36
|
+
end
|
37
|
+
|
38
|
+
else
|
39
|
+
# Got an error, remove that oid from @pending_oids so we can try again
|
40
|
+
error_oid = @pending_oids.delete_at(response.error_index - 1)
|
41
|
+
@responses[error_oid.to_s] = SNMP::ResponseError.new(response.error_status)
|
42
|
+
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
|
+
|
50
|
+
@responses.each_pair do |oid, value|
|
51
|
+
if value.is_a? Array
|
52
|
+
@responses[oid][1] = value[1].rubify if (!@return_raw && value[1].respond_to?(:rubify))
|
53
|
+
else
|
54
|
+
@responses[oid] = value.rubify if (!@return_raw && value.respond_to?(:rubify))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Send the @responses back to the requester, we're done!
|
59
|
+
succeed @responses
|
60
|
+
else
|
61
|
+
@error_retries -= 1
|
62
|
+
send
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def send #:nodoc:
|
69
|
+
# Send the contents of @pending_oids
|
70
|
+
|
71
|
+
@snmp_id = generate_snmp_id
|
72
|
+
|
73
|
+
vb_list = SNMP::VarBindList.new(@pending_oids)
|
74
|
+
request = SNMP::GetNextRequest.new(@snmp_id, vb_list)
|
75
|
+
message = SNMP::Message.new(:SNMPv1, @sender.community_ro, request)
|
76
|
+
|
77
|
+
super(message)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module SNMP4EM
|
2
|
+
|
3
|
+
# Returned from SNMP4EM::SNMPv1.set(). This implements EM::Deferrable, so you can hang a callback()
|
4
|
+
# or errback() to retrieve the results.
|
5
|
+
|
6
|
+
class SnmpSetRequest < SnmpRequest
|
7
|
+
attr_reader :snmp_id
|
8
|
+
|
9
|
+
# For an SNMP-SET request, @pending_varbinds will by an SNMP::VarBindList, initially populated from the
|
10
|
+
# provided oids hash. Variables can be passed as specific types from the SNMP library (i.e. SNMP::IpAddress)
|
11
|
+
# or as ruby native objects, in which case they will be cast into the appropriate SNMP object. As responses
|
12
|
+
# are returned, the @pending_varbinds object will be pruned of any error-producing varbinds. Once no errors
|
13
|
+
# are produced, the @responses object is populated and returned.
|
14
|
+
|
15
|
+
def initialize(sender, oids, args = {}) #:nodoc:
|
16
|
+
@sender = sender
|
17
|
+
|
18
|
+
@timeout_timer = nil
|
19
|
+
@timeout_retries = @sender.retries
|
20
|
+
@error_retries = oids.size
|
21
|
+
|
22
|
+
@return_raw = args[:return_raw] || false
|
23
|
+
|
24
|
+
@responses = Hash.new
|
25
|
+
@pending_varbinds = SNMP::VarBindList.new()
|
26
|
+
|
27
|
+
oids.each_pair do |oid,value|
|
28
|
+
if value.is_a? Integer
|
29
|
+
snmp_value = SNMP::Integer.new(value)
|
30
|
+
elsif value.is_a? String
|
31
|
+
snmp_value = SNMP::OctetString.new(value)
|
32
|
+
end
|
33
|
+
|
34
|
+
@pending_varbinds << SNMP::VarBind.new(oid,snmp_value)
|
35
|
+
end
|
36
|
+
|
37
|
+
init_callbacks
|
38
|
+
send
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_response(response) #:nodoc:
|
42
|
+
if (response.error_status == :noError)
|
43
|
+
# No errors, set any remaining varbinds to true
|
44
|
+
response.each_varbind do |vb|
|
45
|
+
response_vb = @pending_varbinds.shift
|
46
|
+
@responses[response_vb.name.to_s] = true
|
47
|
+
end
|
48
|
+
|
49
|
+
else
|
50
|
+
# Got an error, remove that varbind from @pending_varbinds so we can try again
|
51
|
+
error_vb = @pending_varbinds.delete_at(response.error_index - 1)
|
52
|
+
@responses[error_vb.name.to_s] = SNMP::ResponseError.new(response.error_status)
|
53
|
+
end
|
54
|
+
|
55
|
+
if (@pending_varbinds.empty? || @error_retries.zero?)
|
56
|
+
until @pending_varbinds.empty?
|
57
|
+
error_vb = @pending_varbinds.shift
|
58
|
+
@responses[error_vb.name.to_s] = SNMP::ResponseError.new(:genErr)
|
59
|
+
end
|
60
|
+
|
61
|
+
unless @return_raw
|
62
|
+
@responses.each_pair do |oid, value|
|
63
|
+
@responses[oid] = value.rubify if value.respond_to?(:rubify)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Send the @responses back to the requester, we're done!
|
68
|
+
succeed @responses
|
69
|
+
else
|
70
|
+
@error_retries -= 1
|
71
|
+
|
72
|
+
send
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def send
|
79
|
+
# Send the contents of @pending_varbinds
|
80
|
+
|
81
|
+
@snmp_id = generate_snmp_id
|
82
|
+
|
83
|
+
vb_list = SNMP::VarBindList.new(@pending_varbinds)
|
84
|
+
request = SNMP::SetRequest.new(@snmp_id, vb_list)
|
85
|
+
message = SNMP::Message.new(:SNMPv1, @sender.community_rw, request)
|
86
|
+
|
87
|
+
super(message)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module SNMP4EM
|
2
|
+
|
3
|
+
# Returned from SNMP4EM::SNMPv1.walk(). This implements EM::Deferrable, so you can hang a callback()
|
4
|
+
# or errback() to retrieve the results.
|
5
|
+
|
6
|
+
class SnmpWalkRequest < SnmpRequest
|
7
|
+
attr_reader :snmp_id
|
8
|
+
|
9
|
+
# For an SNMP-WALK request, @pending_oids will be a ruby array of SNMP::ObjectNames that need to be walked.
|
10
|
+
# Note that this library supports walking multiple OIDs in parallel. Once any error-producing OIDs are removed,
|
11
|
+
# a series of SNMP-GETNEXT requests are sent. Each response OID is checked to see if it begins with the walk OID.
|
12
|
+
# If so, the incoming OID/value pair is appended to the @response hash, and will be used in subsequent GETNEXT
|
13
|
+
# requests. Once an OID is returned that does not begin with the walk OID, that walk OID is removed from the
|
14
|
+
# @pending_oids array.
|
15
|
+
|
16
|
+
def initialize(sender, oids, args = {}) #:nodoc:
|
17
|
+
@sender = sender
|
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
|
+
|
33
|
+
def handle_response(response) #:nodoc:
|
34
|
+
oids_to_delete = []
|
35
|
+
|
36
|
+
if (response.error_status == :noError)
|
37
|
+
response.varbind_list.each_index do |i|
|
38
|
+
walk_oid = @pending_oids[i]
|
39
|
+
response_vb = response.varbind_list[i]
|
40
|
+
|
41
|
+
# Initialize the responses array if necessary
|
42
|
+
@responses[walk_oid.to_s] ||= Array.new
|
43
|
+
|
44
|
+
# If the incoming response-oid begins with the walk-oid, then append the pairing
|
45
|
+
# to the @response array. Otherwise, add it to the list of oids ready to delete
|
46
|
+
if (response_vb.name[0,walk_oid.length] == walk_oid)
|
47
|
+
@responses[walk_oid.to_s] << [response_vb.name, response_vb.value]
|
48
|
+
else
|
49
|
+
# If we were to delete thid oid from @pending_oids now, it would mess up the
|
50
|
+
# @pending_oids[i] call above.
|
51
|
+
oids_to_delete << walk_oid
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
@max_results -= 1 unless @max_results.nil?
|
56
|
+
|
57
|
+
else
|
58
|
+
error_oid = @pending_oids[response.error_index - 1]
|
59
|
+
oids_to_delete << error_oid
|
60
|
+
|
61
|
+
@responses[error_oid.to_s] = SNMP::ResponseError.new(response.error_status)
|
62
|
+
@error_retries -= 1
|
63
|
+
end
|
64
|
+
|
65
|
+
oids_to_delete.each{|oid| @pending_oids.delete oid}
|
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
|
+
|
72
|
+
# Send the @responses back to the requester, we're done!
|
73
|
+
succeed @responses
|
74
|
+
else
|
75
|
+
send
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def send
|
82
|
+
@snmp_id = generate_snmp_id
|
83
|
+
|
84
|
+
# This oids array will consist of all the oids that need to be getnext'd
|
85
|
+
oids = Array.new
|
86
|
+
|
87
|
+
@pending_oids.each do |oid|
|
88
|
+
# If there's already a response for this walk-oid, then use the last returned oid, otherwise
|
89
|
+
# start with the walk-oid.
|
90
|
+
if @responses.has_key?(oid.to_s)
|
91
|
+
oids << @responses[oid.to_s].last.first
|
92
|
+
else
|
93
|
+
oids << oid
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
vb_list = SNMP::VarBindList.new(oids)
|
98
|
+
request = SNMP::GetNextRequest.new(@snmp_id, vb_list)
|
99
|
+
message = SNMP::Message.new(:SNMPv1, @sender.community_ro, request)
|
100
|
+
|
101
|
+
super(message)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# The SNMP4EM library
|
2
|
+
|
3
|
+
module SNMP4EM
|
4
|
+
class SnmpConnection
|
5
|
+
@pending_requests = []
|
6
|
+
@socket = nil
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_reader :pending_requests
|
10
|
+
attr_reader :socket
|
11
|
+
|
12
|
+
def init_socket #:nodoc:
|
13
|
+
if @socket.nil?
|
14
|
+
@socket = EM::open_datagram_socket("0.0.0.0", 0, Handler)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :host, :port, :timeout, :retries
|
20
|
+
|
21
|
+
# Creates a new object to communicate with SNMPv1 agents. Optionally pass in the following parameters:
|
22
|
+
# * _host_ - IP/hostname of remote agent (default: 127.0.0.1)
|
23
|
+
# * _port_ - UDP port on remote agent (default: 161)
|
24
|
+
# * _community_ - Community string to use (default: public)
|
25
|
+
# * _community_ro_ - Read-only community string to use for get/getnext/walk operations (default: public)
|
26
|
+
# * _community_rw_ - Read-write community string to use for set operations (default: public)
|
27
|
+
# * _timeout_ - Number of seconds to wait before a request times out (default: 1)
|
28
|
+
# * _retries_ - Number of retries before failing (default: 3)
|
29
|
+
|
30
|
+
def initialize(args = {})
|
31
|
+
@host = args[:host] || "127.0.0.1"
|
32
|
+
@port = args[:port] || 161
|
33
|
+
@timeout = args[:timeout] || 1
|
34
|
+
@retries = args[:retries] || 3
|
35
|
+
|
36
|
+
self.class.init_socket
|
37
|
+
end
|
38
|
+
|
39
|
+
def send(message) #:nodoc:
|
40
|
+
self.class.socket.send_datagram message.encode, @host, @port
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module SNMP4EM
|
2
|
+
class SnmpRequest #:nodoc:
|
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
|
+
|
10
|
+
return snmp_id
|
11
|
+
end
|
12
|
+
|
13
|
+
def init_callbacks
|
14
|
+
self.callback do
|
15
|
+
SnmpConnection.pending_requests.delete_if {|r| r.snmp_id == @snmp_id}
|
16
|
+
@timeout_timer.cancel
|
17
|
+
end
|
18
|
+
|
19
|
+
self.errback do
|
20
|
+
SnmpConnection.pending_requests.delete_if {|r| r.snmp_id == @snmp_id}
|
21
|
+
@timeout_timer.cancel
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def send(msg)
|
26
|
+
@sender.send msg
|
27
|
+
|
28
|
+
@timeout_timer.cancel if @timeout_timer.is_a?(EM::Timer)
|
29
|
+
|
30
|
+
@timeout_timer = EM::Timer.new(@sender.timeout) do
|
31
|
+
if (@timeout_retries > 0)
|
32
|
+
send
|
33
|
+
@timeout_retries -= 1
|
34
|
+
else
|
35
|
+
fail("timeout")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# The SNMP4EM library
|
2
|
+
|
3
|
+
module SNMP4EM
|
4
|
+
class SNMPv1 < SnmpConnection
|
5
|
+
attr_reader :community_ro, :community_rw
|
6
|
+
|
7
|
+
# Creates a new object to communicate with SNMPv1 agents. Optionally pass in the following parameters:
|
8
|
+
# * _host_ - IP/hostname of remote agent (default: 127.0.0.1)
|
9
|
+
# * _port_ - UDP port on remote agent (default: 161)
|
10
|
+
# * _community_ - Community string to use (default: public)
|
11
|
+
# * _community_ro_ - Read-only community string to use for get/getnext/walk operations (default: public)
|
12
|
+
# * _community_rw_ - Read-write community string to use for set operations (default: public)
|
13
|
+
# * _timeout_ - Number of seconds to wait before a request times out (default: 1)
|
14
|
+
# * _retries_ - Number of retries before failing (default: 3)
|
15
|
+
|
16
|
+
def initialize(args = {})
|
17
|
+
super(args)
|
18
|
+
|
19
|
+
@community_ro = args[:community_ro] || args[:community] || "public"
|
20
|
+
@community_rw = args[:community_rw] || args[:community] || "public"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Sends an SNMP-GET request to the remote agent for all OIDs specified in the _oids_ array. Returns a SnmpGetRequest object,
|
24
|
+
# which implements EM::Deferrable. From there, implement a callback/errback to fetch the result. On success, the result will be
|
25
|
+
# a hash, mapping requested OID values to results.
|
26
|
+
#
|
27
|
+
# Optional arguments can be passed into _args_, including:
|
28
|
+
# * _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)
|
29
|
+
|
30
|
+
def get(oids, args = {})
|
31
|
+
request = SnmpGetRequest.new(self, oids, args.merge(:version => :SNMPv1))
|
32
|
+
SnmpConnection.pending_requests << request
|
33
|
+
return request
|
34
|
+
end
|
35
|
+
|
36
|
+
# Sends an SNMP-GETNEXT request to the remote agent for all OIDs specified in the _oids_ array. Returns a SnmpGetRequest object,
|
37
|
+
# which implements EM::Deferrable. From there, implement a callback/errback to fetch the result. On success, the result will be
|
38
|
+
# a hash, mapping requested OID values to two-element arrays consisting of [_next_oid_ , _next_value_]. Any values that produced an
|
39
|
+
# error will map to a symbol representing the error.
|
40
|
+
#
|
41
|
+
# Optional arguments can be passed into _args_, including:
|
42
|
+
# * _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)
|
43
|
+
|
44
|
+
def getnext(oids, args = {})
|
45
|
+
request = SnmpGetNextRequest.new(self, oids, args.merge(:version => :SNMPv1))
|
46
|
+
SnmpConnection.pending_requests << request
|
47
|
+
return request
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sends an SNMP-SET request to the remote agent for all OIDs specified in the _oids_ hash. The hash must map OID values to requested
|
51
|
+
# values. Values can either be specified as Ruby native strings/integers, or as SNMP-specific classes (SNMP::IpAddress, etc).
|
52
|
+
# Returns a SnmpSetRequest object, which implements EM::Deferrable. From there, implement a callback/errback to fetch the result.
|
53
|
+
# On success, the result will be a hash, mapping requested OID values to the returned value from the agent. Any values that were stored
|
54
|
+
# successfully will map to _true_, otherwise, the value will map to a symbol representing the error.
|
55
|
+
#
|
56
|
+
# Optional arguments can be passed into _args_, including:
|
57
|
+
# * _return_raw_ - Return error objects as SNMP::ResponseError instead of a symbol
|
58
|
+
|
59
|
+
def set(oids, args = {})
|
60
|
+
request = SnmpSetRequest.new(self, oids, args.merge(:version => :SNMPv1))
|
61
|
+
SnmpConnection.pending_requests << request
|
62
|
+
return request
|
63
|
+
end
|
64
|
+
|
65
|
+
# Sends a series of SNMP-GETNEXT requests to simulate an SNMP "walk" operation. Given an OID prefix, the library will keep requesting the
|
66
|
+
# next OID until that returned OID does not begin with the requested prefix. This gives the ability to retrieve entire portions of the
|
67
|
+
# SNMP tree in one "operation". Multiple OID prefixes can be passed into the _oids_ array, and will be fetched in parallel. The function returns
|
68
|
+
# a SnmpWalkRequest object, which implements EM::Deferrable. From there, implement a callback/errback to fetch the result. On success, the
|
69
|
+
# result will be a hash, mapping requested OID prefixes to the returned value. Successful walks will be mapped to an array of two-element arrays,
|
70
|
+
# each of which consists of [_oid_ , _value_]. Unsuccessful walks will be mapped to a symbol representing the error.
|
71
|
+
|
72
|
+
# Optional arguments can be passed into _args_, including:
|
73
|
+
# * _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)
|
74
|
+
# * _max_results_ - Maximum number of results to be returned for any single OID prefix (default: nil = unlimited)
|
75
|
+
|
76
|
+
def walk(oids, args = {})
|
77
|
+
request = SnmpWalkRequest.new(self, oids, args.merge(:version => :SNMPv1))
|
78
|
+
SnmpConnection.pending_requests << request
|
79
|
+
return request
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# The SNMP4EM library
|
2
|
+
|
3
|
+
module SNMP4EM
|
4
|
+
class SNMPv2 < SnmpConnection
|
5
|
+
attr_reader :community_ro, :community_rw
|
6
|
+
|
7
|
+
# Creates a new object to communicate with SNMPv1 agents. Optionally pass in the following parameters:
|
8
|
+
# * _host_ - IP/hostname of remote agent (default: 127.0.0.1)
|
9
|
+
# * _port_ - UDP port on remote agent (default: 161)
|
10
|
+
# * _community_ - Community string to use (default: public)
|
11
|
+
# * _community_ro_ - Read-only community string to use for get/getnext/walk operations (default: public)
|
12
|
+
# * _community_rw_ - Read-write community string to use for set operations (default: public)
|
13
|
+
# * _timeout_ - Number of seconds to wait before a request times out (default: 1)
|
14
|
+
# * _retries_ - Number of retries before failing (default: 3)
|
15
|
+
|
16
|
+
def initialize(args = {})
|
17
|
+
super(args)
|
18
|
+
|
19
|
+
@community_ro = args[:community_ro] || args[:community] || "public"
|
20
|
+
@community_rw = args[:community_rw] || args[:community] || "public"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Sends an SNMP-GET request to the remote agent for all OIDs specified in the _oids_ array. Returns a SnmpGetRequest object,
|
24
|
+
# which implements EM::Deferrable. From there, implement a callback/errback to fetch the result. On success, the result will be
|
25
|
+
# a hash, mapping requested OID values to results.
|
26
|
+
#
|
27
|
+
# Optional arguments can be passed into _args_, including:
|
28
|
+
# * _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)
|
29
|
+
|
30
|
+
def get(oids, args = {})
|
31
|
+
request = SnmpGetRequest.new(self, oids, args.merge(:version => :SNMPv2c))
|
32
|
+
SnmpConnection.pending_requests << request
|
33
|
+
return request
|
34
|
+
end
|
35
|
+
|
36
|
+
# Sends an SNMP-GETNEXT request to the remote agent for all OIDs specified in the _oids_ array. Returns a SnmpGetRequest object,
|
37
|
+
# which implements EM::Deferrable. From there, implement a callback/errback to fetch the result. On success, the result will be
|
38
|
+
# a hash, mapping requested OID values to two-element arrays consisting of [_next_oid_ , _next_value_]. Any values that produced an
|
39
|
+
# error will map to a symbol representing the error.
|
40
|
+
#
|
41
|
+
# Optional arguments can be passed into _args_, including:
|
42
|
+
# * _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)
|
43
|
+
|
44
|
+
def getnext(oids, args = {})
|
45
|
+
request = SnmpGetNextRequest.new(self, oids, args.merge(:version => :SNMPv2c))
|
46
|
+
SnmpConnection.pending_requests << request
|
47
|
+
return request
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sends an SNMP-SET request to the remote agent for all OIDs specified in the _oids_ hash. The hash must map OID values to requested
|
51
|
+
# values. Values can either be specified as Ruby native strings/integers, or as SNMP-specific classes (SNMP::IpAddress, etc).
|
52
|
+
# Returns a SnmpSetRequest object, which implements EM::Deferrable. From there, implement a callback/errback to fetch the result.
|
53
|
+
# On success, the result will be a hash, mapping requested OID values to the returned value from the agent. Any values that were stored
|
54
|
+
# successfully will map to _true_, otherwise, the value will map to a symbol representing the error.
|
55
|
+
#
|
56
|
+
# Optional arguments can be passed into _args_, including:
|
57
|
+
# * _return_raw_ - Return error objects as SNMP::ResponseError instead of a symbol
|
58
|
+
|
59
|
+
def set(oids, args = {})
|
60
|
+
request = SnmpSetRequest.new(self, oids, args.merge(:version => :SNMPv2c))
|
61
|
+
SnmpConnection.pending_requests << request
|
62
|
+
return request
|
63
|
+
end
|
64
|
+
|
65
|
+
# Sends a series of SNMP-GETNEXT requests to simulate an SNMP "walk" operation. Given an OID prefix, the library will keep requesting the
|
66
|
+
# next OID until that returned OID does not begin with the requested prefix. This gives the ability to retrieve entire portions of the
|
67
|
+
# SNMP tree in one "operation". Multiple OID prefixes can be passed into the _oids_ array, and will be fetched in parallel. The function returns
|
68
|
+
# a SnmpWalkRequest object, which implements EM::Deferrable. From there, implement a callback/errback to fetch the result. On success, the
|
69
|
+
# result will be a hash, mapping requested OID prefixes to the returned value. Successful walks will be mapped to an array of two-element arrays,
|
70
|
+
# each of which consists of [_oid_ , _value_]. Unsuccessful walks will be mapped to a symbol representing the error.
|
71
|
+
|
72
|
+
# Optional arguments can be passed into _args_, including:
|
73
|
+
# * _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)
|
74
|
+
# * _max_results_ - Maximum number of results to be returned for any single OID prefix (default: nil = unlimited)
|
75
|
+
|
76
|
+
def walk(oids, args = {})
|
77
|
+
request = SnmpWalkRequest.new(self, oids, args.merge(:version => :SNMPv2c))
|
78
|
+
SnmpConnection.pending_requests << request
|
79
|
+
return request
|
80
|
+
end
|
81
|
+
|
82
|
+
# Sends an SNMPv2 GET-BULK request to fetch multiple OID-value pairings simultaneously. This produces similar results to an SNMP-WALK using a single
|
83
|
+
# request/response transaction (SNMP-WALK is actually an inefficient series of GET-NEXTs). Multiple OIDs can be passed into the _oids_ array. Two
|
84
|
+
# additional parameters control how this list is processed. Setting the parameter _nonrepeaters_ to value _N_ indicates that the first _N_ OIDs will
|
85
|
+
# 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
|
86
|
+
# fetched is controlled by the parameter _maxrepetitions_. The function returns a SnmpGetBulkRequest object, which implements EM::Deferrable. From there,
|
87
|
+
# implement a callback/errback to fetch the result. On success, the result will be a hash, mapping requested OID prefixes to the returned value.
|
88
|
+
# 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
|
89
|
+
# symbol representing the error.
|
90
|
+
|
91
|
+
# For more information, see http://tools.ietf.org/html/rfc1905#section-4.2.3
|
92
|
+
|
93
|
+
# Optional arguments can be passed into _args_, including:
|
94
|
+
# * _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)
|
95
|
+
# * _nonrepeaters_ - Number of OIDs passed to which exactly one result will be returned
|
96
|
+
# * _maxrepetitions_ - Number of OID-value pairs to be returned for each OID
|
97
|
+
|
98
|
+
def getbulk(oids, args = {})
|
99
|
+
request = SnmpGetBulkRequest.new(self, oids, args.merge(:version => :SNMPv2c))
|
100
|
+
SnmpConnection.pending_requests << request
|
101
|
+
return request
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/snmp4em.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'snmp'
|
5
|
+
require 'snmp4em/common'
|
6
|
+
require 'snmp4em/handler'
|
7
|
+
require 'snmp4em/snmp_connection'
|
8
|
+
require 'snmp4em/snmp_v1'
|
9
|
+
require 'snmp4em/snmp_v2'
|
10
|
+
require 'snmp4em/snmp_request'
|
11
|
+
require 'snmp4em/requests/snmp_get_request'
|
12
|
+
require 'snmp4em/requests/snmp_getbulk_request'
|
13
|
+
require 'snmp4em/requests/snmp_getnext_request'
|
14
|
+
require 'snmp4em/requests/snmp_set_request'
|
15
|
+
require 'snmp4em/requests/snmp_walk_request'
|
data/snmp4em.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{snmp4em}
|
5
|
+
s.version = "0.2.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Norman Elton"]
|
9
|
+
s.date = %q{2010-05-16}
|
10
|
+
s.description = %q{A high-performance SNMP engine built on EventMachine and Ruby-SNMP, supporting SNMPv1 and SNMPv2 operations}
|
11
|
+
s.email = %q{normelton@gmail.com}
|
12
|
+
s.extra_rdoc_files = ["README"]
|
13
|
+
s.files = ["lib/snmp4em.rb", "lib/snmp4em/common.rb", "lib/snmp4em/handler.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_connection.rb", "lib/snmp4em/snmp_v1.rb", "lib/snmp4em/snmp_v2.rb", "snmp4em.gemspec", "Manifest"]
|
14
|
+
s.homepage = %q{http://github.com/normelton/snmp4em}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Snmp4em", "--main", "README"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{snmp4em}
|
18
|
+
s.rubygems_version = %q{1.3.6}
|
19
|
+
s.summary = %q{A high-performance SNMP engine built on EventMachine and Ruby-SNMP}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
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
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: snmp4em
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Norman Elton
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-05-16 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A high-performance SNMP engine built on EventMachine and Ruby-SNMP, supporting SNMPv1 and SNMPv2 operations
|
17
|
+
email: normelton@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- lib/snmp4em.rb
|
26
|
+
- lib/snmp4em/common.rb
|
27
|
+
- lib/snmp4em/handler.rb
|
28
|
+
- lib/snmp4em/requests/snmp_get_request.rb
|
29
|
+
- lib/snmp4em/requests/snmp_getbulk_request.rb
|
30
|
+
- lib/snmp4em/requests/snmp_getnext_request.rb
|
31
|
+
- lib/snmp4em/requests/snmp_set_request.rb
|
32
|
+
- lib/snmp4em/requests/snmp_walk_request.rb
|
33
|
+
- lib/snmp4em/snmp_request.rb
|
34
|
+
- lib/snmp4em/snmp_connection.rb
|
35
|
+
- lib/snmp4em/snmp_v1.rb
|
36
|
+
- lib/snmp4em/snmp_v2.rb
|
37
|
+
- snmp4em.gemspec
|
38
|
+
- Manifest
|
39
|
+
- README
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/normelton/snmp4em
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --line-numbers
|
47
|
+
- --inline-source
|
48
|
+
- --title
|
49
|
+
- Snmp4em
|
50
|
+
- --main
|
51
|
+
- README
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "1.2"
|
65
|
+
version:
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project: snmp4em
|
69
|
+
rubygems_version: 1.3.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: A high-performance SNMP engine built on EventMachine and Ruby-SNMP
|
73
|
+
test_files: []
|
74
|
+
|