snmp4em 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|