netsnmp 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.travis.yml +4 -4
- data/Gemfile +5 -1
- data/README.md +124 -63
- data/lib/netsnmp.rb +66 -10
- data/lib/netsnmp/client.rb +93 -75
- data/lib/netsnmp/encryption/aes.rb +84 -0
- data/lib/netsnmp/encryption/des.rb +80 -0
- data/lib/netsnmp/encryption/none.rb +17 -0
- data/lib/netsnmp/errors.rb +1 -3
- data/lib/netsnmp/message.rb +81 -0
- data/lib/netsnmp/oid.rb +18 -137
- data/lib/netsnmp/pdu.rb +106 -64
- data/lib/netsnmp/scoped_pdu.rb +23 -0
- data/lib/netsnmp/security_parameters.rb +198 -0
- data/lib/netsnmp/session.rb +84 -275
- data/lib/netsnmp/v3_session.rb +81 -0
- data/lib/netsnmp/varbind.rb +65 -156
- data/lib/netsnmp/version.rb +2 -1
- data/netsnmp.gemspec +2 -8
- data/spec/client_spec.rb +147 -99
- data/spec/handlers/celluloid_spec.rb +33 -20
- data/spec/oid_spec.rb +11 -5
- data/spec/pdu_spec.rb +22 -22
- data/spec/security_parameters_spec.rb +40 -0
- data/spec/session_spec.rb +0 -23
- data/spec/support/celluloid.rb +24 -0
- data/spec/support/request_examples.rb +36 -0
- data/spec/support/start_docker.sh +15 -1
- data/spec/v3_session_spec.rb +21 -0
- data/spec/varbind_spec.rb +2 -51
- metadata +30 -76
- data/lib/netsnmp/core.rb +0 -12
- data/lib/netsnmp/core/client.rb +0 -15
- data/lib/netsnmp/core/constants.rb +0 -153
- data/lib/netsnmp/core/inline.rb +0 -20
- data/lib/netsnmp/core/libc.rb +0 -48
- data/lib/netsnmp/core/libsnmp.rb +0 -44
- data/lib/netsnmp/core/structures.rb +0 -167
- data/lib/netsnmp/core/utilities.rb +0 -13
- data/lib/netsnmp/handlers/celluloid.rb +0 -27
- data/lib/netsnmp/handlers/em.rb +0 -56
- data/spec/core/libc_spec.rb +0 -2
- data/spec/core/libsnmp_spec.rb +0 -32
- data/spec/core/structures_spec.rb +0 -54
- data/spec/handlers/em_client_spec.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35229e0d1dd73c4a43a778b6d0e724bbca5ecc12
|
4
|
+
data.tar.gz: f16c14549b5df1408842b8da935b61180751c997
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45139e881aa85c3350408c9ed59ded3c1ef1c2a418b29fab7953af0a50e056ef235d63280a4958ad537f4b5545e2b5ab0d79c2521b04e0f41ab6a9653f35c47e
|
7
|
+
data.tar.gz: 7621a13aece7a4abcd5b7ec11652a8a39d25ab07ef6206263e8ad378e13aa1d4c397c58fce27e366ab32a845b11e7f7fd043ac2f9a594cf47258fcfc29c94262
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.travis.yml
CHANGED
@@ -25,12 +25,12 @@ script:
|
|
25
25
|
|
26
26
|
language: ruby
|
27
27
|
rvm:
|
28
|
-
- 2.0
|
29
28
|
- 2.1
|
30
29
|
- 2.2
|
31
|
-
- 2.3
|
30
|
+
- 2.3
|
31
|
+
- 2.4
|
32
32
|
- ruby-head
|
33
|
-
- jruby-9.1.
|
33
|
+
- jruby-9.1.6.0
|
34
34
|
- jruby-head
|
35
35
|
- rbx-2
|
36
36
|
matrix:
|
@@ -38,5 +38,5 @@ matrix:
|
|
38
38
|
- rvm: ruby-head
|
39
39
|
- rvm: jruby-head
|
40
40
|
# to figure out later
|
41
|
-
- rvm: jruby-9.1.
|
41
|
+
- rvm: jruby-9.1.6.0
|
42
42
|
- rvm: rbx-2
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -5,9 +5,7 @@
|
|
5
5
|
[![Code Climate](https://codeclimate.com/github/swisscom/ruby-netsnmp/badges/gpa.svg)](https://codeclimate.com/github/swisscom/ruby-netsnmp)
|
6
6
|
[![Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/github/swisscom/ruby-netsnmp/master)
|
7
7
|
|
8
|
-
The netsnmp gem provides a ruby
|
9
|
-
|
10
|
-
This gem started as a cleanup from [net-snmp](https://github.com/mixtli/net-snmp) and its follow-up [net-snmp2](https://github.com/jbreeden/net-snmp2), both of which have been mostly inactive for the last year(s).
|
8
|
+
The `netsnmp` gem provides a ruby native implementation of the SNMP protocol (v1/2c abd v3).
|
11
9
|
|
12
10
|
## Installation
|
13
11
|
|
@@ -29,33 +27,38 @@ Or install it yourself as:
|
|
29
27
|
$ gem install netsnmp
|
30
28
|
```
|
31
29
|
|
32
|
-
##
|
30
|
+
## Features
|
33
31
|
|
34
|
-
|
32
|
+
This gem provides:
|
35
33
|
|
36
|
-
*
|
37
|
-
*
|
38
|
-
*
|
39
|
-
*
|
40
|
-
* Lack of support for NIO4r/Celluloid-IO (the other event loop, besides EM, that counts in the ruby world).
|
41
|
-
* The default sync request calls block the whole VM, making multi-threading a non-factor, forcing you to resort to multiprocess for concurrency.
|
34
|
+
* Implementation in ruby of the SNMP Protocol for v3, v2c and v1 (most notable the rfc3414 and 3826).
|
35
|
+
* Client/Manager API with simple interface for get, genext, set and walk.
|
36
|
+
* No dependencies.
|
37
|
+
* Support for concurrency and evented I/O.
|
42
38
|
|
39
|
+
## Why?
|
43
40
|
|
44
|
-
|
41
|
+
If you look for snmp gems in ruby toolbox, you'll find a bunch.
|
42
|
+
You may ask, why not just use one of them?
|
45
43
|
|
46
|
-
|
44
|
+
Most of them only implement v1 and v2, so if your requirement is to use v3, you're left with only 2 choices: [net-snmp](https://github.com/mixtli/net-snmp) (unmantained since 2013) and its follow-up [net-snmp2](https://github.com/jbreeden/net-snmp2), which started as a fork to fix some bugs left unattended. Both libraries wrap the C netsnmp library using FFI, which leaves them vulnerable to the following bugs (experienced in both libraries):
|
47
45
|
|
48
|
-
|
46
|
+
* Dependency of specific versions of netsnmp C package.
|
47
|
+
* Memory Leaks.
|
48
|
+
* Doesn't work reliable in ruby > 2.0.0-p576, crashing the VM.
|
49
|
+
* Network I/O done by the library, thereby blocking the GVL, thereby making all snmp calls block the whole ruby VM.
|
50
|
+
* This means, multi-threading is impossible.
|
51
|
+
* This means, evented I/O is impossible.
|
49
52
|
|
50
|
-
|
53
|
+
All of these issues are resolved here.
|
51
54
|
|
52
55
|
## Features
|
53
56
|
|
54
|
-
* Client Interface, which supports SNMP
|
55
|
-
* Supports get,
|
56
|
-
*
|
57
|
-
* Ruby >= 2.
|
58
|
-
*
|
57
|
+
* Client Interface, which supports SNMP v3, v2c, and v1
|
58
|
+
* Supports get, getnext, set and walk calls.
|
59
|
+
* Proxy IO object support (for eventmachine/celluloid-io)
|
60
|
+
* Ruby >= 2.1 support
|
61
|
+
* Pure Ruby (no FFI)
|
59
62
|
|
60
63
|
## Examples
|
61
64
|
|
@@ -64,13 +67,14 @@ You can use the docker container provided under spec/support to test against the
|
|
64
67
|
```ruby
|
65
68
|
require 'netsnmp'
|
66
69
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
70
|
+
# example you can test against the docker simulator provided. port attribute might be different.
|
71
|
+
manager = NETSNMP::Client.new(host: "localhost", port: 33445, username: "simulator",
|
72
|
+
auth_password: "auctoritas", auth_protocol: :md5,
|
73
|
+
priv_password: "privatus", priv_protocol: :des,
|
74
|
+
context: "a172334d7d97871b72241397f713fa12")
|
71
75
|
|
72
76
|
# SNMP get
|
73
|
-
manager.get("sysName.0") #=> 'tt'
|
77
|
+
manager.get(oid: "sysName.0") #=> 'tt'
|
74
78
|
|
75
79
|
# SNMP walk
|
76
80
|
manager.walk("sysORDescr") do |oid_code, value|
|
@@ -78,19 +82,13 @@ manager.walk("sysORDescr") do |oid_code, value|
|
|
78
82
|
puts "for #{oid_code}: #{value}"
|
79
83
|
end
|
80
84
|
|
81
|
-
# SNMP get_bulk
|
82
|
-
manager.get_bulk("sysOrDescr") do |oid_code, value|
|
83
|
-
# do something with them
|
84
|
-
puts "for #{oid_code}: #{value}"
|
85
|
-
end
|
86
|
-
|
87
85
|
manager.close
|
88
86
|
|
89
87
|
# SNMP set
|
90
|
-
manager2 = NETSNMP::Client.new("localhost", port: 33445, username: "simulator",
|
91
|
-
|
92
|
-
|
93
|
-
|
88
|
+
manager2 = NETSNMP::Client.new(host: "localhost", port: 33445, username: "simulator",
|
89
|
+
auth_password: "auctoritas", auth_protocol: :md5,
|
90
|
+
priv_password: "privatus", priv_protocol: :des,
|
91
|
+
context: "0886e1397d572377c17c15036a1e6c66")
|
94
92
|
|
95
93
|
# setting to 43, becos yes
|
96
94
|
manager2.set("sysUpTimeInstance", 43)
|
@@ -98,54 +96,113 @@ manager2.set("sysUpTimeInstance", 43)
|
|
98
96
|
manager2.close
|
99
97
|
```
|
100
98
|
|
101
|
-
|
99
|
+
SNMP v2/v1 examples will be similar (beware of the differences in the initialization attributes).
|
102
100
|
|
103
|
-
This library uses RSpec. The client specs are "integration" tests, in that we communicate with an snmp agent simulator.
|
104
101
|
|
105
|
-
|
102
|
+
## Concurrency
|
106
103
|
|
107
|
-
|
108
|
-
> spec/support/start_docker.sh
|
109
|
-
```
|
104
|
+
In ruby, you are usually adviced not to share IO objects across threads. The same principle applies here to `NETSNMP::Client`: provided you use it within a thread of execution, it should behave safely. So, something like this would be possible:
|
110
105
|
|
111
|
-
|
106
|
+
```ruby
|
107
|
+
general_options = { auth_protocol: ....
|
108
|
+
routers.map do |r|
|
109
|
+
Thread.start do
|
110
|
+
NETSNMP::Client.new(general_options.merge(host: r)) do |cl|
|
111
|
+
cli.get(oid: "1.6.3.......
|
112
112
|
|
113
|
-
|
114
|
-
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end.each(&:join)
|
115
116
|
```
|
116
117
|
|
117
|
-
|
118
|
+
Evented IO is also supported, in that you can pass a `:proxy` object as an already opened channel of communication to the client. Very important: you have to take care of the lifecycle, as the client will not connect and will not close the object, it will assume no control over it.
|
119
|
+
|
120
|
+
When passing a proxy object, you can omit the `:host` parameter.
|
121
|
+
|
122
|
+
The proxy object will have to be a duck-type implementing `#send`, which is a method receiving the sending PDU payload, and return the payload of the receiving PDU.
|
123
|
+
|
124
|
+
Here is a small pseudo-code example:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
# beware, we are inside a warp-speed loop!!!
|
128
|
+
general_options = { auth_protocol: ....
|
129
|
+
proxy = SpecialUDPImplementation.new(host: router)
|
130
|
+
NETSNMP::Client.new(general_options.merge(proxy: proxy)) do |cl|
|
131
|
+
# this get call will eventually #send to the proxy...
|
132
|
+
cli.get(oid: "1.6.3.......
|
118
133
|
|
134
|
+
end
|
135
|
+
# client isn't usable anymore, but now we must close to proxy
|
136
|
+
proxy.close
|
119
137
|
```
|
120
|
-
|
138
|
+
|
139
|
+
For more information about this subject, the specs test this feature against celluloid-io. An eventmachine could be added, if someone would be kind enough to provide an implementation.
|
140
|
+
|
141
|
+
## Performance
|
142
|
+
|
143
|
+
|
144
|
+
### XOR
|
145
|
+
|
146
|
+
This library has some workarounds to some missing features in the ruby language, namely the inexistence of a byte array structure. The closest we have is a byte stream presented as a String with ASCII encoding. A method was added to the String class called `#xor` for some operations needed internally. To prevent needless monkey-patches, Refinements have been employed.
|
147
|
+
|
148
|
+
If `#xor` becomes at some point the bottleneck of your usage, this gem has also support for [xorcist](https://github.com/fny/xorcist/). You just have to add it to your Gemfile (or install it in the system):
|
149
|
+
|
121
150
|
```
|
151
|
+
# Gemfile
|
152
|
+
|
153
|
+
gem 'netsnmp'
|
154
|
+
|
155
|
+
# or, in the command line
|
156
|
+
|
157
|
+
$ gem install netsnmp
|
158
|
+
```
|
159
|
+
|
160
|
+
and `netsnmp` will automatically pick it up.
|
122
161
|
|
123
|
-
##
|
162
|
+
## Auth/Priv Key
|
124
163
|
|
125
|
-
|
164
|
+
If you'll use this gem often with SNMP v3 and auth/priv security level enabled, you'll have that funny feeling that everything could be a bit faster. Well, this is basically because the true performance bottleneck of this gem is the generation of the auth and pass keys used for authorization and encryption. Although this is a one-time thing for each client, its lag will be noticeable if you're running on > 100 hosts.
|
126
165
|
|
127
|
-
|
166
|
+
There is a recommended work-around, but this is only usable **if you are using the same user/authpass/privpass on all the hosts!!!**. Use this with care, then:
|
128
167
|
|
168
|
+
```ruby
|
169
|
+
$shared_security_parameters = NETSNMP::SecurityParameters.new(security_level: :authpriv, username: "mustermann",
|
170
|
+
auth_protocol: :md5, priv_protocol: :aes, ....
|
171
|
+
# this will eager-load the auth/priv_key
|
172
|
+
...
|
173
|
+
|
174
|
+
# over 9000 routers are running on this event loop!!! this is just one!
|
175
|
+
NETSNMP::Client.new(share_options.merge(proxy: router_proxy, security_parameters: $shared_security_parameters.dup).new do |cl|
|
176
|
+
cli.get(oid: .....
|
177
|
+
end
|
129
178
|
```
|
130
|
-
# on OSX
|
131
|
-
> brew install net-snmp
|
132
179
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
180
|
+
## OpenSSL
|
181
|
+
|
182
|
+
All encoding/decoding/encryption/decryption/digests are done using `openssl`, which is (still) a part of the standard library. If at some point `openssl` is removed and not specifically distributed, you'll have to install it yourself. Hopefully this will never happen.
|
183
|
+
|
184
|
+
|
185
|
+
## Tests
|
186
|
+
|
187
|
+
This library uses RSpec. The client specs are "integration" tests, in that we communicate with an snmp agent simulator.
|
188
|
+
|
189
|
+
To start the simulator locally, you'll need docker 1.9 or higher (Why 1.9? ```--build-arg``` parameter support was needed for our builds in the CI. You could use a lower version by providing the proxy environment variables in the Dockerfile directly, provided you don't merge these changes to master, thereby exposing your proxy).
|
190
|
+
|
191
|
+
```
|
192
|
+
> spec/support/start_docker.sh
|
139
193
|
```
|
140
194
|
|
141
|
-
|
195
|
+
this builds and starts the docker image in deamonized mode. You can afterwards run your specs:
|
142
196
|
|
143
197
|
```
|
144
|
-
>
|
145
|
-
> sudo download-mibs
|
198
|
+
> bundle exec rspec
|
146
199
|
```
|
147
200
|
|
148
|
-
|
201
|
+
To stop the image, you can just:
|
202
|
+
|
203
|
+
```
|
204
|
+
> spec/supoprt/stop_docker.sh
|
205
|
+
```
|
149
206
|
|
150
207
|
## Contributing
|
151
208
|
|
@@ -156,7 +213,11 @@ TODO: on Windows(?)
|
|
156
213
|
|
157
214
|
## TODO
|
158
215
|
|
159
|
-
There are
|
216
|
+
There are some features which this gem doesn't support. It was built to provide a client (or manager, in SNMP language) implementation only, and the requirements were fulfilled. However, these notable misses will stand-out:
|
217
|
+
|
218
|
+
* No MIB support (you can only work with OIDs)
|
219
|
+
* No server (Agent, in SNMP-ish) implementation.
|
220
|
+
* No getbulk support.
|
160
221
|
|
161
|
-
|
222
|
+
So if you like the gem, but would rather have these features implemented, please help by sending us a PR and we'll gladly review it.
|
162
223
|
|
data/lib/netsnmp.rb
CHANGED
@@ -1,16 +1,72 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "netsnmp/version"
|
3
|
+
require "openssl"
|
4
|
+
require "io/wait"
|
5
|
+
require "securerandom"
|
6
|
+
|
2
7
|
|
3
8
|
# core structures
|
4
|
-
|
9
|
+
|
10
|
+
begin
|
11
|
+
require "xorcist"
|
12
|
+
require "xorcist/refinements"
|
13
|
+
NETSNMP::StringExtensions = Xorcist::Refinements
|
14
|
+
rescue LoadError
|
15
|
+
# "no xorcist"
|
16
|
+
module NETSNMP
|
17
|
+
module StringExtensions
|
18
|
+
refine String do
|
19
|
+
# Bitwise XOR operator for the String class
|
20
|
+
def xor( other )
|
21
|
+
b1 = self.unpack("C*")
|
22
|
+
return b1 if !other
|
23
|
+
|
24
|
+
b2 = other.unpack("C*")
|
25
|
+
longest = [b1.length,b2.length].max
|
26
|
+
b1 = [0]*(longest-b1.length) + b1
|
27
|
+
b2 = [0]*(longest-b2.length) + b2
|
28
|
+
b1.zip(b2).map{ |a,b| a^b }.pack("C*")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
5
35
|
|
6
36
|
module NETSNMP
|
7
|
-
|
8
|
-
|
37
|
+
def self.set_debug(io)
|
38
|
+
@debug_output = io
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.debug(&blk)
|
42
|
+
@debug_output << blk.call + "\n" if @debug_output
|
43
|
+
end
|
44
|
+
|
45
|
+
unless defined?(Hexdump) # support the hexdump gem
|
46
|
+
module Hexdump
|
47
|
+
def self.dump(data, width: 8)
|
48
|
+
pairs = data.unpack("H*").first.scan(/.{4}/)
|
49
|
+
pairs.each_slice(width).map do |row|
|
50
|
+
row.join(" ")
|
51
|
+
end.join("\n")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
9
55
|
end
|
10
56
|
|
11
|
-
|
12
|
-
require
|
13
|
-
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
57
|
+
|
58
|
+
require "netsnmp/errors"
|
59
|
+
|
60
|
+
require "netsnmp/oid"
|
61
|
+
require "netsnmp/varbind"
|
62
|
+
require "netsnmp/pdu"
|
63
|
+
require "netsnmp/session"
|
64
|
+
|
65
|
+
require "netsnmp/scoped_pdu"
|
66
|
+
require "netsnmp/v3_session"
|
67
|
+
require "netsnmp/security_parameters"
|
68
|
+
require "netsnmp/message"
|
69
|
+
require "netsnmp/encryption/des"
|
70
|
+
require "netsnmp/encryption/aes"
|
71
|
+
|
72
|
+
require "netsnmp/client"
|
data/lib/netsnmp/client.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module NETSNMP
|
2
3
|
# Main Entity, provides the user-facing API to communicate with SNMP Agents
|
3
4
|
#
|
@@ -7,83 +8,90 @@ module NETSNMP
|
|
7
8
|
#
|
8
9
|
#
|
9
10
|
class Client
|
10
|
-
|
11
|
-
|
12
|
-
# @param [Hash] options the
|
11
|
+
RETRIES = 5
|
12
|
+
|
13
|
+
# @param [Hash] options the options to needed to enable the SNMP client.
|
14
|
+
# @option options [String, Integer, nil] :version the version of the protocol (defaults to 3).
|
15
|
+
# also accepts common known declarations like :v3, "v2c", etc
|
16
|
+
# @option options [Integer] :retries number of retries for each failed PDU (after which it raise timeout error. Defaults to {RETRIES} retries)
|
17
|
+
# @yield [client] the instantiated client, after which it closes it for use.
|
18
|
+
# @example Yielding a clinet
|
19
|
+
# NETSNMP::Client.new(host: "241.232.22.12") do |client|
|
20
|
+
# puts client.get(oid: "1.3.6.1.2.1.1.5.0")
|
21
|
+
# end
|
13
22
|
#
|
14
|
-
|
15
|
-
|
16
|
-
|
23
|
+
def initialize(**options)
|
24
|
+
version = options[:version]
|
25
|
+
version = case version
|
26
|
+
when Integer then version # assume the use know what he's doing
|
27
|
+
when /v?1/ then 0
|
28
|
+
when /v?2c?/ then 1
|
29
|
+
when /v?3/, nil then 3
|
30
|
+
end
|
31
|
+
|
32
|
+
@retries = options.fetch(:retries, RETRIES)
|
33
|
+
@session ||= version == 3 ? V3Session.new(options) : Session.new(options)
|
34
|
+
if block_given?
|
35
|
+
begin
|
36
|
+
yield self
|
37
|
+
ensure
|
38
|
+
close
|
39
|
+
end
|
40
|
+
end
|
17
41
|
end
|
18
42
|
|
19
|
-
#
|
43
|
+
# Closes the inner section
|
20
44
|
def close
|
21
45
|
@session.close
|
22
46
|
end
|
23
47
|
|
24
48
|
# Performs an SNMP GET Request
|
25
|
-
#
|
26
|
-
# @param [OID, String] oid_code the oid to get
|
27
|
-
# @param [Hash] options the varbind options (see Varbind)
|
28
|
-
# @option options [true, false] :response_pdu if true, the method returns a PDU
|
29
49
|
#
|
30
|
-
# @
|
50
|
+
# @see {NETSNMP::Varbind#new}
|
31
51
|
#
|
32
|
-
def get(
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
response_pdu = @session.send(request_pdu)
|
38
|
-
case options[:response_type]
|
39
|
-
when :pdu then response_pdu
|
40
|
-
else response_pdu.value
|
41
|
-
end
|
52
|
+
def get(oid_opts)
|
53
|
+
request = @session.build_pdu(:get, oid_opts)
|
54
|
+
response = handle_retries { @session.send(request) }
|
55
|
+
yield response if block_given?
|
56
|
+
response.varbinds.first.value
|
42
57
|
end
|
43
58
|
|
44
59
|
# Performs an SNMP GETNEXT Request
|
45
60
|
#
|
46
|
-
# @
|
47
|
-
# @param [Hash] options the varbind options (see Varbind)
|
48
|
-
# @option options [true, false] :response_pdu if true, the method returns a PDU
|
49
|
-
#
|
50
|
-
# @return [String] the value for the next oid
|
51
|
-
#
|
52
|
-
# @note this method is used as a sub-routine for the walk
|
61
|
+
# @see {NETSNMP::Varbind#new}
|
53
62
|
#
|
54
|
-
def get_next(
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
case options[:response_type]
|
61
|
-
when :pdu then response_pdu
|
62
|
-
else response_pdu.value
|
63
|
-
end
|
63
|
+
def get_next(oid_opts)
|
64
|
+
request = @session.build_pdu(:getnext, oid_opts)
|
65
|
+
response = handle_retries { @session.send(request) }
|
66
|
+
yield response if block_given?
|
67
|
+
varbind = response.varbinds.first
|
68
|
+
[varbind.oid, varbind.value]
|
64
69
|
end
|
65
70
|
|
66
71
|
# Perform a SNMP Walk (issues multiple subsequent GENEXT requests within the subtree rooted on an OID)
|
67
72
|
#
|
68
|
-
# @param [
|
69
|
-
# @param [Hash] options the varbind options
|
73
|
+
# @param [String] oid the root oid from the subtree
|
70
74
|
#
|
71
75
|
# @return [Enumerator] the enumerator-collection of the oid-value pairs
|
72
76
|
#
|
73
|
-
def walk(
|
74
|
-
|
75
|
-
walkoid = oid_code.is_a?(OID) ? oid_code : OID.new(oid_code)
|
77
|
+
def walk(oid: )
|
78
|
+
walkoid = oid
|
76
79
|
Enumerator.new do |y|
|
77
|
-
code = walkoid
|
80
|
+
code = walkoid
|
81
|
+
first_response_code = nil
|
78
82
|
catch(:walk) do
|
79
83
|
loop do
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
get_next(oid: code) do |response|
|
85
|
+
response.varbinds.each do |varbind|
|
86
|
+
code = varbind.oid
|
87
|
+
if !OID.parent?(walkoid, code) or
|
88
|
+
varbind.value.eql?(:endofmibview) or
|
89
|
+
code == first_response_code
|
90
|
+
throw(:walk)
|
91
|
+
else
|
92
|
+
y << [code, varbind.value]
|
93
|
+
end
|
94
|
+
first_response_code ||= code
|
87
95
|
end
|
88
96
|
end
|
89
97
|
end
|
@@ -93,39 +101,49 @@ module NETSNMP
|
|
93
101
|
|
94
102
|
# Perform a SNMP GETBULK Request (performs multiple GETNEXT)
|
95
103
|
#
|
96
|
-
# @param [
|
104
|
+
# @param [String] oid the first oid
|
97
105
|
# @param [Hash] options the varbind options
|
98
106
|
# @option options [Integer] :errstat sets the number of objects expected for the getnext instance
|
99
107
|
# @option options [Integer] :errindex number of objects repeating for all the repeating IODs.
|
100
108
|
#
|
101
109
|
# @return [Enumerator] the enumerator-collection of the oid-value pairs
|
102
110
|
#
|
103
|
-
def get_bulk(
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
115
|
-
end
|
111
|
+
#def get_bulk(oid)
|
112
|
+
# request = @session.build_pdu(:getbulk, *oids)
|
113
|
+
# request[:error_status] = options.delete(:non_repeaters) || 0
|
114
|
+
# request[:error_index] = options.delete(:max_repetitions) || 10
|
115
|
+
# response = @session.send(request)
|
116
|
+
# Enumerator.new do |y|
|
117
|
+
# response.varbinds.each do |varbind|
|
118
|
+
# y << [ varbind.oid, varbind.value ]
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
#end
|
116
122
|
|
117
123
|
# Perform a SNMP SET Request
|
118
124
|
#
|
119
|
-
# @
|
120
|
-
# @param [Hash] options the varbind options
|
121
|
-
# @option options [Object] :value value to update the oid with.
|
125
|
+
# @see {NETSNMP::Varbind#new}
|
122
126
|
#
|
123
|
-
def set(
|
124
|
-
|
125
|
-
|
126
|
-
yield
|
127
|
-
|
128
|
-
|
127
|
+
def set(oid_opts)
|
128
|
+
request = @session.build_pdu(:set, oid_opts)
|
129
|
+
response = handle_retries { @session.send(request) }
|
130
|
+
yield response if block_given?
|
131
|
+
response.varbinds.map(&:value)
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
# Handles timeout errors by reissuing the same pdu until it runs out or retries.
|
138
|
+
def handle_retries
|
139
|
+
retries = @retries
|
140
|
+
begin
|
141
|
+
yield
|
142
|
+
rescue Timeout::Error => e
|
143
|
+
raise e if retries == 0
|
144
|
+
retries -= 1
|
145
|
+
retry
|
146
|
+
end
|
129
147
|
end
|
130
148
|
end
|
131
149
|
end
|