# frozen_string_literal: true require "snmp" class Netdisco class SNMP class NetdiscoError < StandardError; end class NoResponse < NetdiscoError; end # 类对象初始化入口函数 def initialize(host, community = CFG.snmp.community, timeout = CFG.snmp.timeout, retries = CFG.snmp.retries) @host = host @snmp = ::SNMP::Manager.new(Host: @host, Community: community, Timeout: timeout, Retries: retries, MibModules: []) end # Closes the SNMP connection # @return [void] def close @snmp.close end # 查询某个 oid 监控值 # Gets one oid, return value # @param [String] oid to get # @return [SNMP::VarBind] def get(oid) mget([oid]).first end # 批量查询多个 oids 监控值 # Get multiple oids, return array of values # @param [Array(String)] oids to get # @return [SNMP::VarBindList] def mget(oids) snmp :get, oids end # 遍历 root_oid 监控值 # Bulkwalk everything below root oid # @param [String] root oid to start from # @return [Array(SNMP::VarBind)] def bulkwalk(root) # 初始化变量 last, oid, results = false, root.dup, [] # 将点分10进制字串转换为数组对象 # root = root.split(".").map { |chr| chr.to_i } # 遍历 root_oid until last vbs = snmp(:get_bulk, 0, CFG.snmp.bulkrows, oid).varbind_list vbs.each do |vb| oid = vb.name.to_str # 解析到的 oid 不匹配 root 跳出循环 (last = true; break) unless oid.match?(/^#{Regexp.quote(root)}/) # (last = true; break) unless oid[0..root.size - 1] == root results << vb end end results end # 将遍历的 root 监控值转换为 VBHash 样式 # bulkwalks oid and returns hash with oid as key # @param [String] oid root oid to walk # @yield [VBHash] hash containing oids found # @return [Hash] resulting hash def hashwalk(oid, &block) hash = VBHash.new bulkwalk(oid).each do |vb| # value, key = block.call(vb) # key ||= vb.oid hash[vb.oid] = vb end hash end private def snmp(method, *args) @snmp.send method, *args rescue ::SNMP::RequestTimeout, Errno::EACCES => e msg = "host '#{@host}' raised '#{e.class}' with message '#{e.message}' for method '#{method}' with args '#{args}'" Log.warn msg raise NoResponse, msg end # Hash with some helper methods to easier work with VarBinds class VBHash < Hash alias :org_bracket :[] undef :[] # 精确查询 # @param [Array(Strin, Array)] oid root oid under which you want all oids below it # @return [VBHash] oids which start with param oid def by_oid(*oid) oid = arg_to_oid(*oid) hash = select do |key, value| key[0..oid.size - 1] == oid end new_hash = VBHash.new new_hash.merge hash end # 模糊匹配 # @param [Array(String, Array)] args partial match 3.4.6 would match to 1.2.3.4.6.7.8 # @return [SNMP::VarBind, nil] matching element def by_partial(*args) oid = arg_to_oid(*args) # got = nil keys.each do |key| return self[key] if key.each_cons(oid.size).find { |e| e == oid } # if key.each_cons(oid.size).find { |e| e == oid } # got = self[key] # break # end end nil end # @param [Array[String, Array)] key which you want, multiple arguments compiled into single key # @return [SNMP::VarBind] matching element def [](*args) org_bracket arg_to_oid(*args) end private def arg_to_oid(*args) # FIXME && TODO key = [] args.each do |arg| if Array === arg key += arg.map { |e| e.to_i } elsif Fixnum === arg key << arg else key += arg.split(".").map { |e| e.to_i } end end key end end end end module SNMP class VarBind # @return [String] VarBind value as IP address def as_ip SNMP::IpAddress.new(value).to_s end # @param [String] root oid which is removed from self.oid # @return [Array] oid remaining after specified root oid def oid_id(root) root = root.split(".").map { |e| e.to_i } oid[root.size..-1] end end end