Class: Net::SNMP::Session
- Inherits:
-
Object
- Object
- Net::SNMP::Session
- Extended by:
- Forwardable
- Includes:
- Debug
- Defined in:
- lib/net/snmp/session.rb
Overview
Provides an API for managing SNMP agents
Direct Known Subclasses
Class Attribute Summary collapse
-
.lock ⇒ Object
Returns the value of attribute lock.
-
.sessions ⇒ Object
Returns the value of attribute sessions.
Instance Attribute Summary collapse
-
#callback ⇒ Object
Returns the value of attribute callback.
-
#community ⇒ Object
Returns the value of attribute community.
-
#peername ⇒ Object
Returns the value of attribute peername.
-
#port ⇒ Object
Returns the value of attribute port.
-
#requests ⇒ Object
Returns the value of attribute requests.
-
#struct ⇒ Object
Returns the value of attribute struct.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
Class Method Summary collapse
-
.open(options = {}) ⇒ Object
Open a new session.
Instance Method Summary collapse
-
#close ⇒ Object
Close the snmp session and free associated resources.
-
#columns(columns, options = {}) ⇒ Object
Given a list of columns (e.g [‘ifIndex’, ‘ifDescr’], will return a hash with the indexes as keys and hashes as values. puts sess.get_columns([‘ifIndex’, ‘ifDescr’]).inspect => {‘ifIndex’ => ‘1’, ‘ifDescr’ => ‘lo0’, ‘2’ => => ‘2’, ‘ifDescr’ => ‘en0’}.
- #default_max_repeaters ⇒ Object
- #errno ⇒ Object
-
#error(msg, options = {}) ⇒ Object
Raise a NET::SNMP::Error with the session attached.
-
#error_message ⇒ Object
The SNMP Session error message.
-
#get(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GET Request.
-
#get_bulk(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GETBULK Request Supports typical options, plus - ‘:non_repeaters` The number of non-repeated oids in the request - `:max_repititions` The maximum repititions to return for all repeaters Note that the non-repeating varbinds must be added first.
-
#get_next(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GETNEXT Request See #send_pdu.
-
#initialize(options = {}) ⇒ Session
constructor
A new instance of Session.
-
#method_missing(m, *args) ⇒ Object
Proxy getters to the C struct representing the session.
- #print_errors ⇒ Object
-
#select(timeout = nil) ⇒ Object
(also: #poll)
Check the session for SNMP responses from asynchronous SNMP requests This method will check for new responses and call the associated response callbacks.
-
#send_pdu(pdu, options = {}, &callback) ⇒ Object
Send a PDU
pdu
The Net::SNMP::PDU object to send. - #send_pdu_blocking(pdu) ⇒ Object
-
#set(vb_list, options = {}, &block) ⇒ Object
Issue an SNMP Set Request.
-
#snmp_err ⇒ Object
The SNMP Session error code.
-
#table(table_name, &blk) ⇒ Object
table(‘ifEntry’).
-
#walk(oidlist, options = {}) ⇒ Object
Issue repeated getnext requests on each oid passed in until the result is no longer a child.
Methods included from Debug
Constructor Details
#initialize(options = {}) ⇒ Session
Returns a new instance of Session.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/net/snmp/session.rb', line 59 def initialize( = {}) = {:peername => } if .kind_of?(String) @timeout = [:timeout] || 1 @retries = [:retries] || 5 @requests = {} @peername = [:peername] || 'localhost' # If the port is supplied in the peername, don't # worry about the port option (avoids appending two port numbers) unless @peername[':'] [:port] ||= 161 @port = [:port] @peername = "#{@peername}:#{[:port]}" end @community = [:community] || "public" [:community_len] = @community.length [:version] ||= Constants::SNMP_VERSION_2c @version = [:version] @sess = Wrapper::SnmpSession.new(nil) Wrapper.snmp_sess_init(@sess.pointer) @sess.community = FFI::MemoryPointer.from_string(@community) @sess.community_len = @community.length @sess.peername = FFI::MemoryPointer.from_string(@peername) @sess.version = case @version.to_s when '1' Constants::SNMP_VERSION_1 when '2', '2c' Constants::SNMP_VERSION_2c when '3' Constants::SNMP_VERSION_3 else Constants::SNMP_VERSION_1 end @sess.timeout = @timeout * 1000000 @sess.retries = @retries if @sess.version == Constants::SNMP_VERSION_3 @sess.securityLevel = [:security_level] || Constants::SNMP_SEC_LEVEL_NOAUTH @sess.securityAuthProto = case [:auth_protocol] when :sha1 OID.new("1.3.6.1.6.3.10.1.1.3").pointer when :md5 OID.new("1.3.6.1.6.3.10.1.1.2").pointer when nil OID.new("1.3.6.1.6.3.10.1.1.1").pointer end @sess.securityPrivProto = case [:priv_protocol] when :aes OID.new("1.3.6.1.6.3.10.1.2.4").pointer when :des OID.new("1.3.6.1.6.3.10.1.2.2").pointer when nil OID.new("1.3.6.1.6.3.10.1.2.1").pointer end @sess.securityAuthProtoLen = 10 @sess.securityAuthKeyLen = Constants::USM_AUTH_KU_LEN @sess.securityPrivProtoLen = 10 @sess.securityPrivKeyLen = Constants::USM_PRIV_KU_LEN if [:context] @sess.contextName = FFI::MemoryPointer.from_string([:context]) @sess.contextNameLen = [:context].length end # Do not generate_Ku, unless we're Auth or AuthPriv unless @sess.securityLevel == Constants::SNMP_SEC_LEVEL_NOAUTH [:auth_password] ||= [:password] # backward compatability if [:username].nil? or [:auth_password].nil? raise Net::SNMP::Error.new "SecurityLevel requires username and password" end if [:username] @sess.securityName = FFI::MemoryPointer.from_string([:username]) @sess.securityNameLen = [:username].length end auth_len_ptr = FFI::MemoryPointer.new(:size_t) auth_len_ptr.write_int(Constants::USM_AUTH_KU_LEN) auth_key_result = Wrapper.generate_Ku(@sess.securityAuthProto, @sess.securityAuthProtoLen, [:auth_password], [:auth_password].length, @sess.securityAuthKey, auth_len_ptr) @sess.securityAuthKeyLen = auth_len_ptr.read_int if @sess.securityLevel == Constants::SNMP_SEC_LEVEL_AUTHPRIV priv_len_ptr = FFI::MemoryPointer.new(:size_t) priv_len_ptr.write_int(Constants::USM_PRIV_KU_LEN) # NOTE I know this is handing off the AuthProto, but generates a proper # key for encryption, and using PrivProto does not. priv_key_result = Wrapper.generate_Ku(@sess.securityAuthProto, @sess.securityAuthProtoLen, [:priv_password], [:priv_password].length, @sess.securityPrivKey, priv_len_ptr) @sess.securityPrivKeyLen = priv_len_ptr.read_int end unless auth_key_result == Constants::SNMPERR_SUCCESS and priv_key_result == Constants::SNMPERR_SUCCESS Wrapper.snmp_perror("netsnmp") end end end @struct = Wrapper.snmp_sess_open(@sess.pointer) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(m, *args) ⇒ Object
Proxy getters to the C struct representing the session
253 254 255 256 257 258 259 |
# File 'lib/net/snmp/session.rb', line 253 def method_missing(m, *args) if @struct.respond_to?(m) @struct.send(m, *args) else super end end |
Class Attribute Details
.lock ⇒ Object
Returns the value of attribute lock.
17 18 19 |
# File 'lib/net/snmp/session.rb', line 17 def lock @lock end |
.sessions ⇒ Object
Returns the value of attribute sessions.
17 18 19 |
# File 'lib/net/snmp/session.rb', line 17 def sessions @sessions end |
Instance Attribute Details
#callback ⇒ Object
Returns the value of attribute callback.
10 11 12 |
# File 'lib/net/snmp/session.rb', line 10 def callback @callback end |
#community ⇒ Object
Returns the value of attribute community.
10 11 12 |
# File 'lib/net/snmp/session.rb', line 10 def community @community end |
#peername ⇒ Object
Returns the value of attribute peername.
10 11 12 |
# File 'lib/net/snmp/session.rb', line 10 def peername @peername end |
#port ⇒ Object
Returns the value of attribute port.
10 11 12 |
# File 'lib/net/snmp/session.rb', line 10 def port @port end |
#requests ⇒ Object
Returns the value of attribute requests.
10 11 12 |
# File 'lib/net/snmp/session.rb', line 10 def requests @requests end |
#struct ⇒ Object
Returns the value of attribute struct.
10 11 12 |
# File 'lib/net/snmp/session.rb', line 10 def struct @struct end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
11 12 13 |
# File 'lib/net/snmp/session.rb', line 11 def version @version end |
Class Method Details
.open(options = {}) ⇒ Object
Open a new session. Accepts a block which yields the session.
Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :community => 'public') do |sess|
pdu = sess.get(["sysDescr.0"])
pdu.print
end
Arguments
-
options: A Hash or String object + As a Hash, supports the following keys
- peername: hostname - community: snmp community string. Default is public - version: snmp version. Possible values include 1, '2c', and 3. Default is 1. - timeout: snmp timeout in seconds - retries: snmp retries. default = 5 - security_level: SNMPv3 only. default = Net::SNMP::Constants::SNMP_SEC_LEVEL_NOAUTH - auth_protocol: SNMPv3 only. default is nil (usmNoAuthProtocol). Possible values include :md5, :sha1, and nil - priv_protocol: SNMPv3 only. default is nil (usmNoPrivProtocol). Possible values include :des, :aes, and nil - context: SNMPv3 only. - username: SNMPv3 only. - auth_password: SNMPv3 only. - priv_password: SNMPv3 only.
Returns a new Net::SNMP::Session
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/net/snmp/session.rb', line 43 def open( = {}) session = new() if Net::SNMP::thread_safe Net::SNMP::Session.lock.synchronize { Net::SNMP::Session.sessions[session.sessid] = session } else Net::SNMP::Session.sessions[session.sessid] = session end if block_given? yield session end session end |
Instance Method Details
#close ⇒ Object
Close the snmp session and free associated resources.
171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/net/snmp/session.rb', line 171 def close if Net::SNMP.thread_safe Session.lock.synchronize { Wrapper.snmp_sess_close(@struct) Session.sessions.delete(self.sessid) } else Wrapper.snmp_sess_close(@struct) Session.sessions.delete(self.sessid) end end |
#columns(columns, options = {}) ⇒ Object
Given a list of columns (e.g [‘ifIndex’, ‘ifDescr’], will return a hash with the indexes as keys and hashes as values.
puts sess.get_columns(['ifIndex', 'ifDescr']).inspect
{'1' => {'ifIndex' => '1', 'ifDescr' => 'lo0'}, '2' => {'ifIndex' => '2', 'ifDescr' => 'en0'}}
374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
# File 'lib/net/snmp/session.rb', line 374 def columns(columns, = {}) columns = columns.map {|c| c.kind_of?(OID) ? c : OID.new(c)} walk_hash = walk(columns, ) results = {} walk_hash.each do |k, v| oid = OID.new(k) results[oid.index] ||= {} results[oid.index][oid.node.label] = v end if block_given? yield results end results end |
#default_max_repeaters ⇒ Object
261 262 263 264 |
# File 'lib/net/snmp/session.rb', line 261 def default_max_repeaters # We could do something based on transport here. 25 seems safe 25 end |
#errno ⇒ Object
526 527 528 529 |
# File 'lib/net/snmp/session.rb', line 526 def errno get_error @errno end |
#error(msg, options = {}) ⇒ Object
Raise a NET::SNMP::Error with the session attached
267 268 269 270 271 |
# File 'lib/net/snmp/session.rb', line 267 def error(msg, = {}) #Wrapper.snmp_sess_perror(msg, @sess.pointer) err = Error.new({:session => self}.merge()) raise err, msg end |
#error_message ⇒ Object
The SNMP Session error message
538 539 540 541 |
# File 'lib/net/snmp/session.rb', line 538 def get_error @snmp_msg end |
#get(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GET Request. See #send_pdu
185 186 187 188 189 190 191 192 |
# File 'lib/net/snmp/session.rb', line 185 def get(oidlist, = {}, &block) pdu = PDU.new(Constants::SNMP_MSG_GET) oidlist = [oidlist] unless oidlist.kind_of?(Array) oidlist.each do |oid| pdu.add_varbind(:oid => oid) end send_pdu(pdu, , &block) end |
#get_bulk(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GETBULK Request Supports typical options, plus
- `:non_repeaters` The number of non-repeated oids in the request
- `:max_repititions` The maximum repititions to return for all repeaters
Note that the non-repeating varbinds must be added first. See #send_pdu
211 212 213 214 215 216 217 218 219 220 |
# File 'lib/net/snmp/session.rb', line 211 def get_bulk(oidlist, = {}, &block) pdu = PDU.new(Constants::SNMP_MSG_GETBULK) oidlist = [oidlist] unless oidlist.kind_of?(Array) oidlist.each do |oid| pdu.add_varbind(:oid => oid) end pdu.non_repeaters = [:non_repeaters] || 0 pdu.max_repetitions = [:max_repetitions] || 10 send_pdu(pdu, , &block) end |
#get_next(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GETNEXT Request See #send_pdu
196 197 198 199 200 201 202 203 |
# File 'lib/net/snmp/session.rb', line 196 def get_next(oidlist, = {}, &block) pdu = PDU.new(Constants::SNMP_MSG_GETNEXT) oidlist = [oidlist] unless oidlist.kind_of?(Array) oidlist.each do |oid| pdu.add_varbind(:oid => oid) end send_pdu(pdu, , &block) end |
#print_errors ⇒ Object
543 544 545 |
# File 'lib/net/snmp/session.rb', line 543 def print_errors puts "errno: #{errno}, snmp_err: #{@snmp_err}, message: #{@snmp_msg}" end |
#select(timeout = nil) ⇒ Object Also known as: poll
Check the session for SNMP responses from asynchronous SNMP requests This method will check for new responses and call the associated response callbacks. timeout
A timeout of nil indicates a poll and will return immediately. A value of false will block until data is available. Otherwise, pass the number of seconds to block. Returns the number of file descriptors handled.
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/net/snmp/session.rb', line 281 def select(timeout = nil) unless @fdset # 8K should be plenty of space @fdset = FFI::MemoryPointer.new(1024 * 8) end @fdset.clear num_fds = FFI::MemoryPointer.new(:int) tv_sec = timeout ? timeout.round : 0 tv_usec = timeout ? (timeout - timeout.round) * 1000000 : 0 tval = Wrapper::TimeVal.new(:tv_sec => tv_sec, :tv_usec => tv_usec) block = FFI::MemoryPointer.new(:int) if timeout.nil? block.write_int(0) else block.write_int(1) end Wrapper.snmp_sess_select_info(@struct, num_fds, @fdset, tval.pointer, block ) tv = (timeout == false ? nil : tval) num_ready = FFI::LibC.select(num_fds.read_int, @fdset, nil, nil, tv) if num_ready > 0 Wrapper.snmp_sess_read(@struct, @fdset) elsif num_ready == 0 Wrapper.snmp_sess_timeout(@struct) elsif num_ready == -1 # error. check snmp_error? error("select") else error("wtf is wrong with select?") end num_ready end |
#send_pdu(pdu, options = {}, &callback) ⇒ Object
Send a PDU pdu
The Net::SNMP::PDU object to send. Usually created by Session.get, Session.getnext, etc. callback
An optional callback. It should take two parameters, status and response_pdu. If no callback
is given, the call will block until the response is available and will return the response pdu. If an error occurs, a Net::SNMP::Error will be thrown. If callback
is passed, the PDU will be sent and send_pdu
will return immediately. You must then call Session.select to invoke the callback. This is usually done in some sort of event loop. See Net::SNMP::Dispatcher.
If you’re running inside eventmachine and have fibers (ruby 1.9, jruby, etc), sychronous calls will actually run asynchronously behind the scenes. Just run Net::SNMP::Dispatcher.fiber_loop in your reactor.
pdu = Net::SNMP::PDU.new(Constants::SNMP_MSG_GET)
pdu.add_varbind(:oid => 'sysDescr.0')
session.send_pdu(pdu) do |status, pdu|
if status == :success
pdu.print
elsif status == :timeout
puts "Timed Out"
else
puts "A problem occurred"
end
end
session.select(false) #block until data is ready. Callback will be called.
begin
result = session.send_pdu(pdu)
puts result.inspect
rescue Net::SNMP::Error => e
puts e.
end
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/net/snmp/session.rb', line 431 def send_pdu(pdu, = {}, &callback) if [:blocking] return send_pdu_blocking(pdu) end debug "Sending: " do pdu.print end if block_given? debug "Setting callback for reqid #{pdu.reqid}" @requests[pdu.reqid] = callback debug "Calling snmp_sess_async_send" if Wrapper.snmp_sess_async_send(@struct, pdu.pointer, sess_callback, nil) == 0 error("snmp_get async failed") end nil else if defined?(EM) && EM.reactor_running? && defined?(Fiber) f = Fiber.current send_pdu pdu do | op, response_pdu | f.resume([op, response_pdu]) end op, result = Fiber.yield case op when :timeout raise TimeoutError.new, "timeout" when :send_failed error "send failed" when :success result when :connect, :disconnect nil #does this ever happen? else error "unknown operation #{op}" end else send_pdu_blocking(pdu) end end # if block_given? # debug "Setting callback for reqid #{pdu.reqid}" # @requests[pdu.reqid] = callback # debug "Calling snmp_sess_async_send" # if Wrapper.snmp_sess_async_send(@struct, pdu.pointer, sess_callback, nil) == 0 # error("snmp_get async failed") # end # nil # elsif defined?(EM) && EM.reactor_running? && defined?(Fiber) # f = Fiber.current # send_pdu pdu do | op, response_pdu | # f.resume([op, response_pdu]) # end # op, result = Fiber.yield # case op # when :timeout # raise TimeoutError.new, "timeout" # when :send_failed # error "send failed" # when :success # result # when :connect, :disconnect # nil #does this ever happen? # else # error "unknown operation #{op}" # end # else # send_pdu_blocking(pdu) # end end |
#send_pdu_blocking(pdu) ⇒ Object
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
# File 'lib/net/snmp/session.rb', line 503 def send_pdu_blocking(pdu) response_ptr = FFI::MemoryPointer.new(:pointer) if [Constants::SNMP_MSG_TRAP, Constants::SNMP_MSG_TRAP2, Constants::SNMP_MSG_RESPONSE].include?(pdu.command) # Since we don't expect a response, the native net-snmp lib is going to free this # pdu for us. Polite, though this may be, it causes intermittent segfaults when freeing # memory malloc'ed by ruby. So, clone the pdu into a new memory buffer, # and pass that along. The clone is then freed by the native lib. The sent # pdu must be freed by the caller. clone = Wrapper.snmp_clone_pdu(pdu.struct) status = Wrapper.snmp_sess_send(@struct, clone) if status == 0 error("snmp_sess_send") end :success else status = Wrapper.snmp_sess_synch_response(@struct, pdu.pointer, response_ptr) unless status == Constants::STAT_SUCCESS error("snmp_sess_synch_response", :status => status) end PDU.new(response_ptr.read_pointer) end end |
#set(vb_list, options = {}, &block) ⇒ Object
Issue an SNMP Set Request.
-
vb_list: An single varbind, or an array of varbinds, each of which may be + An Array of length 3 ‘[oid, type, value]` + An Array of length 2 `[oid, value]` + Or a Hash `oid, type: type, value: value`
* Hash syntax is the same as supported by PDU.add_varbind * If type is not supplied, it is infered by the value
See #send_pdu
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/net/snmp/session.rb', line 230 def set(vb_list, = {}, &block) pdu = PDU.new(Constants::SNMP_MSG_SET) # Normalize input to an array if a single varbind is supplied if vb_list.kind_of?(Hash) || (vb_list.kind_of?(Enumerable) && !vb_list.first.kind_of?(Enumerable)) vb_list = [vb_list] end vb_list.each do |vb| if vb.kind_of?(Hash) pdu.add_varbind(vb) elsif vb.kind_of?(Enumerable) && vb.length == 3 pdu.add_varbind(:oid => vb[0], :type => vb[1], :value => vb[2]) elsif vb.kind_of?(Enumerable) && vb.length == 2 pdu.add_varbind(:oid => vb[0], :value => vb[1]) else raise "Invalid varbind: #{vb}" end end send_pdu(pdu, , &block) end |
#snmp_err ⇒ Object
The SNMP Session error code
532 533 534 535 |
# File 'lib/net/snmp/session.rb', line 532 def snmp_err get_error @snmp_err end |
#table(table_name, &blk) ⇒ Object
table(‘ifEntry’). You must pass the direct parent entry. Calls columns with all columns in table_name
391 392 393 394 395 396 397 398 |
# File 'lib/net/snmp/session.rb', line 391 def table(table_name, &blk) column_names = MIB::Node.get_node(table_name).children.collect {|c| c.oid } results = columns(column_names) if block_given? yield results end results end |
#walk(oidlist, options = {}) ⇒ Object
Issue repeated getnext requests on each oid passed in until the result is no longer a child. Returns a hash with the numeric oid strings as keys. XXX work in progress. only works synchronously (except with EM + fibers). Need to do better error checking and use getbulk when avaiable.
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
# File 'lib/net/snmp/session.rb', line 323 def walk(oidlist, = {}) oidlist = [oidlist] unless oidlist.kind_of?(Array) oidlist = oidlist.map {|o| o.kind_of?(OID) ? o : OID.new(o)} all_results = {} base_list = oidlist while(!oidlist.empty? && pdu = get_next(oidlist, )) debug "================ Walk: Get Next =====================" debug "base_list: \n#{base_list.map { |o| " - #{o.to_s}" }.join("\n")}" prev_base = base_list.dup oidlist = [] pdu.varbinds.each_with_index do |vb, i| if prev_base[i].parent_of?(vb.oid) && vb.object_type != Constants::SNMP_ENDOFMIBVIEW # Still in subtree. Store results and add next oid to list debug "adding #{vb.oid} to oidlist" all_results[vb.oid.to_s] = vb.value oidlist << vb.oid else # End of subtree. Don't add to list or results debug "End of subtree" base_list.delete_at(i) debug "not adding #{vb.oid}" end # If get a pdu error, we can only tell the first failing varbind, # So we remove it and resend all the rest if pdu.error? && pdu.errindex == i + 1 oidlist.pop # remove the bad oid debug "Error on: #{pdu.varbinds[pdu.errindex - 1].oid}" if pdu.varbinds.size > i+1 # recram rest of oids on list ((i+1)..pdu.varbinds.size).each do |j| debug "j = #{j}" debug "adding #{j} = #{prev_list[j]}" oidlist << prev_list[j] end # delete failing oid from base_list base_list.delete_at(i) end break end end end if block_given? yield all_results end all_results end |