robertgauld/snmp_table_viewer

View on GitHub
lib/snmp_table_viewer/fetcher.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module SNMPTableViewer

  # Class to fetch the information from an SNMP host.
  class Fetcher

    # Fetch the data using SNMP.
    # @param base_oid [String] The OID to start the SNMP walk from
    # @param **snmp_options [Hash] The options to pass to NETSNMP::Client.new
    # @return [Array<Array<#to_s>>] A two dimensional array containing objects in each cell (at 'address' data\[row\]\[col\])
    def self.from_snmp(base_oid:, **snmp_options)
      data = Array.new
      NETSNMP::Client.new(snmp_options) do |manager|
        manager.walk(oid: base_oid).each do |oid, value|
          col, row = oid.split('.')[-2..-1].map{ |i| i.to_i - 1}
          data[row] ||= Array.new
          data[row][col] = value
        end
      end
      data
    end

    # Build the data from an Array<String>.
    #   Each String of the format returned by the snmpwalk command ("<oid> = <type>: <value>").
    # @param data [Array<String>] The Strings to get the data from
    # @return [Array<Array<#to_s>>] A two dimensional array containing objects in each cell (at 'address' data\[row\]\[col\])
    def self.from_array(data_in)
      data_out = Array.new
      regexp_general = Regexp.compile(/\A(?:iso)?[\.0-9]+\.([0-9]+)\.([0-9]+)\s+=\s+([A-Za-z0-9 \-]+):\s+(.+)\Z/)
      regexp_nodata = Regexp.compile(/\A(?:iso)?[\.0-9]+\.([0-9]+)\.([0-9]+)\s+=\s+""\Z/)
      data_in.each.with_index do |line, index|
        # Try to get a match on the various valid frmats of line
        match = line.match(regexp_general)
        match ||= line.match(regexp_nodata)
        if match.nil?
          STDERR.puts "Could not parse data on line #{index+1}: #{line}"
          next
        end

        col, row, type, value = match.captures
        # Convert value
        case type && type.downcase
          when nil
          when 'string'
            value = value[1..-2] # Strip enclosing quotes
          when 'oid', 'hex-string'
          when 'integer', 'integer32', 'uinteger32', 'gauge32', 'counter32', 'counter64'
            value = value.to_i
          when 'ipaddress'
            value = IPAddr.new(value)
          when 'timeticks'
            match = value.match(/\A\((\d+)\)/)
            value = NETSNMP::Timetick.new(match.nil? ? 0 : match[1].to_i)
          else
            STDERR.puts "Unknown SNMP type (#{type}) on line #{index+1}: #{line}"
        end
        
        # Save value
        row = row.to_i - 1
        col = col.to_i - 1
        data_out[row] ||= Array.new        
        data_out[row][col] = value
      end # each line of data_in
      data_out
    end

  end # class Fetcher

end # module SNMPTableViewer