Class: Net::SNMP::Session
- Inherits:
-
Object
- Object
- Net::SNMP::Session
- Extended by:
- Forwardable
- Includes:
- Debug
- Defined in:
- lib/net/snmp/session.rb
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.
-
#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) ⇒ 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, &block) ⇒ Object
Issue an SNMP GET Request.
-
#get_bulk(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GETBULK Request See #send_pdu.
-
#get_next(oidlist, &block) ⇒ Object
Issue an SNMP GETNEXT Request See #send_pdu.
-
#initialize(options = {}) ⇒ Session
constructor
A new instance of Session.
- #method_missing(m, *args) ⇒ Object
- #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, &callback) ⇒ Object
Send a PDU
pduThe Net::SNMP::PDU object to send. -
#set(oidlist, &block) ⇒ Object
Issue an SNMP Set Request See #send_pdu.
-
#snmp_err ⇒ Object
The SNMP Session error code.
-
#table(table_name, &blk) ⇒ Object
table(‘ifEntry’).
-
#walk(oidlist) ⇒ 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 |
# File 'lib/net/snmp/session.rb', line 59 def initialize( = {}) @timeout = [:timeout] || 1 @retries = [:retries] || 5 @requests = {} @peername = [:peername] || 'localhost' @peername = "#{@peername}:#{[:port]}" if [:port] @community = [:community] || "public" [:community_len] = @community.length @version = [:version] || 1 [:version] ||= Constants::SNMP_VERSION_1 @version = [:version] || 1 #self.class.sessions << self @sess = Wrapper::SnmpSession.new(nil) Wrapper.snmp_sess_init(@sess.pointer) #options.each_pair {|k,v| ptr.send("#{k}=", v)} @sess.community = FFI::MemoryPointer.from_string(@community) @sess.community_len = @community.length @sess.peername = FFI::MemoryPointer.from_string(@peername) #@sess.remote_port = options[:port] || 162 @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 debug "setting timeout = #{@timeout} retries = #{@retries}" @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 # General callback just takes the pdu, calls the session callback if any, then the request specific callback. @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
229 230 231 232 233 234 235 |
# File 'lib/net/snmp/session.rb', line 229 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.
20 21 22 |
# File 'lib/net/snmp/session.rb', line 20 def lock @lock end |
.sessions ⇒ Object
Returns the value of attribute sessions.
20 21 22 |
# File 'lib/net/snmp/session.rb', line 20 def sessions @sessions end |
Instance Attribute Details
#callback ⇒ Object
Returns the value of attribute callback.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def callback @callback end |
#community ⇒ Object
Returns the value of attribute community.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def community @community end |
#peername ⇒ Object
Returns the value of attribute peername.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def peername @peername end |
#requests ⇒ Object
Returns the value of attribute requests.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def requests @requests end |
#struct ⇒ Object
Returns the value of attribute struct.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def struct @struct end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
13 14 15 |
# File 'lib/net/snmp/session.rb', line 13 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
Options:
-
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: 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 self.class.lock.synchronize { Wrapper.snmp_sess_close(@struct) self.class.sessions.delete(self.sessid) } else Wrapper.snmp_sess_close(@struct) self.class.sessions.delete(self.sessid) end end |
#columns(columns) ⇒ 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'}}
351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/net/snmp/session.rb', line 351 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
237 238 239 240 |
# File 'lib/net/snmp/session.rb', line 237 def default_max_repeaters # We could do something based on transport here. 25 seems safe 25 end |
#errno ⇒ Object
459 460 461 462 |
# File 'lib/net/snmp/session.rb', line 459 def errno get_error @errno end |
#error(msg, options = {}) ⇒ Object
Raise a NET::SNMP::Error with the session attached
243 244 245 246 247 248 |
# File 'lib/net/snmp/session.rb', line 243 def error(msg, = {}) #Wrapper.snmp_sess_perror(msg, @sess.pointer) err = Error.new({:session => self}.merge()) err.print raise err, msg end |
#error_message ⇒ Object
The SNMP Session error message
471 472 473 474 |
# File 'lib/net/snmp/session.rb', line 471 def get_error @snmp_msg end |
#get(oidlist, &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 See #send_pdu
207 208 209 210 211 212 213 214 215 216 |
# File 'lib/net/snmp/session.rb', line 207 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, &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
476 477 478 |
# File 'lib/net/snmp/session.rb', line 476 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.
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/net/snmp/session.rb', line 258 def select(timeout = nil) fdset = FFI::MemoryPointer.new(:pointer, Net::SNMP::Inline.fd_setsize / 8) 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) #debug "Calling select #{Time.now}" num_ready = FFI::LibC.select(num_fds.read_int, fdset, nil, nil, tv) #debug "Done select #{Time.now}" 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, &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
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 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 |
# File 'lib/net/snmp/session.rb', line 408 def send_pdu(pdu, &callback) if block_given? @requests[pdu.reqid] = callback debug "calling async_send" if Wrapper.snmp_sess_async_send(@struct, pdu.pointer, sess_callback, nil) == 0 error("snmp_get async failed") end #pdu.free nil else if defined?(EM) && EM.reactor_running? && defined?(Fiber) f = Fiber.current send_pdu pdu do | op, response_pdu | #pdu.free 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 response_ptr = FFI::MemoryPointer.new(:pointer) if [Constants::SNMP_MSG_TRAP, Constants::SNMP_MSG_TRAP2].include?(pdu.command) status = Wrapper.snmp_sess_send(@struct, pdu.pointer) if status == 0 error("snmp_sess_send") end 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 end if [Constants::SNMP_MSG_TRAP, Constants::SNMP_MSG_TRAP2].include?(pdu.command) 1 else PDU.new(response_ptr.read_pointer) end end end end |
#set(oidlist, &block) ⇒ Object
Issue an SNMP Set Request See #send_pdu
221 222 223 224 225 226 227 |
# File 'lib/net/snmp/session.rb', line 221 def set(oidlist, &block) pdu = PDU.new(Constants::SNMP_MSG_SET) oidlist.each do |oid| pdu.add_varbind(:oid => oid[0], :type => oid[1], :value => oid[2]) end send_pdu(pdu, &block) end |
#snmp_err ⇒ Object
The SNMP Session error code
465 466 467 468 |
# File 'lib/net/snmp/session.rb', line 465 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
368 369 370 371 372 373 374 375 |
# File 'lib/net/snmp/session.rb', line 368 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) ⇒ 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.
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/net/snmp/session.rb', line 297 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 "===============================================================" debug "base_list = #{base_list}" prev_base = base_list.dup oidlist = [] #print_errors #pdu.print_errors 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 "caught error" 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 |