snmp_table_viewer 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9db3534a0e0d11c1747bd4f2edbc2d98990fd1ed
4
- data.tar.gz: f0302013da02ee45a7712a22524029ed73bdf039
3
+ metadata.gz: b570ea16acd375c817335b0d61ac9479aa9ae944
4
+ data.tar.gz: 94133afd6edafe5d3a94292d3c15379e2b032c7d
5
5
  SHA512:
6
- metadata.gz: 5ba88ae246f5ef4c89703d4760fefb11f20185466e9225b4b18dfcf8d371e43d0d5cf5a690e461e90cbcbc34a433c2fdacd5b834a3b2219b6dcaaf9184eef829
7
- data.tar.gz: 077a5ec639f89fd10ddb13a7958f8164487229d4a6f3a622732b2e10f41ac6b2d494bc4e241a6a0379663802270aff29e5ece6d36940eb497d026b3be8e8c486
6
+ metadata.gz: d427c9f895295b1f22c0c604fd48b275ea93644a615169fdeead38ca0540a5041e5690a0888ebd1de2e913d22836559022e7641f287c0983976bc8a84ecf0bd3
7
+ data.tar.gz: 08fe2bd62489cad0a409b70c1ff45cb416aadf2b38b6b0813f4c707ff7835f0f63362eb627c82c38452f7c946e5b64204462647724f3529eeedccf8141bcc1d2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## Version 0.0.5
2
+
3
+ * Rename snmp-table-viewer script to table-from-snmp
4
+ * Add script table-from-stdin
5
+
1
6
  ## Version 0.0.4
2
7
 
3
8
  * Rename gem to snmp_table_viewer
data/README.md CHANGED
@@ -40,10 +40,11 @@ gem 'snmp_table_viewer', '~> 0.0'
40
40
  ```
41
41
 
42
42
 
43
- ## Executable
43
+ ## Executables
44
44
 
45
+ ### Create table from doing an SNMP walk
45
46
  ```
46
- Usage: snmp-table-viewer [options]
47
+ Usage: table-from-snmp [options]
47
48
  -h, -?, --help Prints this help.
48
49
  --headings HEADINGS Headings to use in the table (e.g. "A, Bc, D").
49
50
  --headings-for TYPE Use headings for this table type (ifTable).
@@ -75,6 +76,19 @@ SNMP version 3 options:
75
76
  Table formatter options:
76
77
  --[no-]transpose-table Transpose the output table (swap rows and columns).
77
78
  ```
79
+ ### Create table from piped in data
80
+ ```
81
+ Usage: table-from-stdin [options]
82
+ -h, -?, --help Prints this help.
83
+ --headings HEADINGS Headings to use in the table (e.g. "A, Bc, D").
84
+ --headings-for TYPE Use headings for this table type (ifTable).
85
+ --format FORMAT How to format the output (table|csv|json|raw) (default table).
86
+ --converter CONVERTER A converter to run on the data before formatting (iftable).
87
+
88
+ Table formatter options:
89
+ --[no-]transpose-table Transpose the output table (swap rows and columns).
90
+ ```
91
+
78
92
 
79
93
  ## Documentation & Versioning
80
94
 
@@ -29,25 +29,10 @@ def parse_command_line
29
29
  headings: [],
30
30
  formatter: SNMPTableViewer::Formatter::Table,
31
31
  }
32
- headings_for = {
33
- 'ifTable' => ['Index', 'Descr', 'Type', 'Mtu', 'Speed', 'PhysAddress', 'AdminStatus', 'OperStatus', 'LastChange', 'InOctets', 'InUcastPkts', 'InNUcastkts', 'InDiscards', 'InErrors', 'InUnknownPrortos', 'OutOctets', 'OutUcastPkts', 'OutNUcastPkts', 'OutDiscards', 'OutErrors', 'OutQLen', 'Specific'],
34
- }
35
- formatters = {
36
- 'table' => SNMPTableViewer::Formatter::Table,
37
- 'csv' => SNMPTableViewer::Formatter::CSV,
38
- 'json' => SNMPTableViewer::Formatter::JSON,
39
- 'raw' => SNMPTableViewer::Formatter::Raw,
40
- }
41
- converters = {
42
- 'iftable' => SNMPTableViewer::Converter::IfTable,
43
- }
44
- base_oids = {
45
- 'iftable' => '1.3.6.1.2.1.2.2',
46
- }
47
32
  snmp_version = 'v3'
48
33
 
49
34
  parser = OptionParser.new do |opts|
50
- opts.banner = "Usage: snmp-table-viewer [options]"
35
+ opts.banner = "Usage: table-from-snmp [options]"
51
36
 
52
37
  opts.on('-h', '--help', '-?', 'Prints this help.') do
53
38
  puts opts
@@ -58,16 +43,16 @@ def parse_command_line
58
43
  options[:headings] += v.map(&:strip)
59
44
  end
60
45
 
61
- opts.on('--headings-for TYPE', String, "Use headings for this table type (#{headings_for.keys.join('|')}).") do |v|
62
- options[:headings] += headings_for[v] || []
46
+ opts.on('--headings-for TYPE', String, "Use headings for this table type (#{SNMPTableViewer::HEADINGS_FOR.keys.join('|')}).") do |v|
47
+ options[:headings] += SNMPTableViewer::HEADINGS_FOR[v] || []
63
48
  end
64
49
 
65
- opts.on('--format FORMAT', String, "How to format the output (#{formatters.keys.join('|')}) (default table).") do |v|
66
- options[:formatter] = formatters[v.downcase]
50
+ opts.on('--format FORMAT', String, "How to format the output (#{SNMPTableViewer::FORMATTERS.keys.join('|')}) (default table).") do |v|
51
+ options[:formatter] = SNMPTableViewer::FORMATTERS[v.downcase]
67
52
  end
68
53
 
69
- opts.on('--converter CONVERTER', String, "A converter to run on the data before formatting (#{converters.keys.join('|')}).") do |v|
70
- options[:converter] = converters[v.downcase]
54
+ opts.on('--converter CONVERTER', String, "A converter to run on the data before formatting (#{SNMPTableViewer::CONVERTERS.keys.join('|')}).") do |v|
55
+ options[:converter] = SNMPTableViewer::CONVERTERS[v.downcase]
71
56
  end
72
57
 
73
58
 
@@ -87,7 +72,7 @@ def parse_command_line
87
72
  end
88
73
 
89
74
  opts.on('--base-oid OID', 'The oid at the start of the table. Can by dotted numbers or ifTable') do |v|
90
- options[:base_oid] = base_oids[v.downcase] || v
75
+ options[:base_oid] = SNMPTableViewer::BASE_OIDS[v.downcase] || v
91
76
  end
92
77
 
93
78
 
@@ -139,7 +124,7 @@ options = parse_command_line
139
124
  snmp_options = options[:snmp][:common].clone
140
125
  snmp_options.merge!(options[:snmp][snmp_options[:version]])
141
126
 
142
- data = SNMPTableViewer::Fetcher.fetch(base_oid: options[:base_oid], **snmp_options)
127
+ data = SNMPTableViewer::Fetcher.from_snmp(base_oid: options[:base_oid], **snmp_options)
143
128
 
144
129
  converter = options[:converter]
145
130
  data = converter.convert(data) unless converter.nil?
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require_relative File.join('..', 'lib', 'snmp_table_viewer')
5
+
6
+ def parse_command_line
7
+ options = {
8
+ SNMPTableViewer::Formatter::Table => {
9
+ transpose: false,
10
+ },
11
+ headings: [],
12
+ formatter: SNMPTableViewer::Formatter::Table,
13
+ }
14
+
15
+ parser = OptionParser.new do |opts|
16
+ opts.banner = "Usage: table-from-stdin [options]"
17
+
18
+ opts.on('-h', '--help', '-?', 'Prints this help.') do
19
+ puts opts
20
+ exit
21
+ end
22
+
23
+ opts.on('--headings HEADINGS', Array, 'Headings to use in the table (e.g. "A, Bc, D").') do |v|
24
+ options[:headings] += v.map(&:strip)
25
+ end
26
+
27
+ opts.on('--headings-for TYPE', String, "Use headings for this table type (#{SNMPTableViewer::HEADINGS_FOR.keys.join('|')}).") do |v|
28
+ options[:headings] += SNMPTableViewer::HEADINGS_FOR[v] || []
29
+ end
30
+
31
+ opts.on('--format FORMAT', String, "How to format the output (#{SNMPTableViewer::FORMATTERS.keys.join('|')}) (default table).") do |v|
32
+ options[:formatter] = SNMPTableViewer::FORMATTERS[v.downcase]
33
+ end
34
+
35
+ opts.on('--converter CONVERTER', String, "A converter to run on the data before formatting (#{SNMPTableViewer::CONVERTERS.keys.join('|')}).") do |v|
36
+ options[:converter] = SNMPTableViewer::CONVERTERS[v.downcase]
37
+ end
38
+
39
+
40
+ opts.separator "\nTable formatter options:"
41
+ opts.on('--[no-]transpose-table', 'Transpose the output table (swap rows and columns).') do |v|
42
+ options[SNMPTableViewer::Formatter::Table][:transpose] = v
43
+ end
44
+
45
+ end # create parser
46
+
47
+ parser.parse!(ARGV)
48
+ options
49
+ end
50
+
51
+
52
+ options = parse_command_line
53
+ data = STDIN.readlines.map(&:strip)
54
+ data = SNMPTableViewer::Fetcher.from_array(data)
55
+
56
+ converter = options[:converter]
57
+ data = converter.convert(data) unless converter.nil?
58
+
59
+ formatter = options[:formatter]
60
+ formatter_options = options[formatter] || {}
61
+ formatter = formatter.new(data: data, headings: options[:headings])
62
+ puts formatter.output(**formatter_options)
@@ -6,19 +6,63 @@ module SNMPTableViewer
6
6
  # Fetch the data using SNMP.
7
7
  # @param base_oid [String] The OID to start the SNMP walk from
8
8
  # @param **snmp_options [Hash] The options to pass to NETSNMP::Client.new
9
- # @return [Array<Array<#to_s>>] A two dimensional array containing objects in each cell (at 'address' data[row][col])
9
+ # @return [Array<Array<#to_s>>] A two dimensional array containing objects in each cell (at 'address' data\[row\]\[col\])
10
10
  def self.from_snmp(base_oid:, **snmp_options)
11
11
  data = Array.new
12
12
  NETSNMP::Client.new(snmp_options) do |manager|
13
13
  manager.walk(oid: base_oid).each do |oid, value|
14
14
  col, row = oid.split('.')[-2..-1].map{ |i| i.to_i - 1}
15
- data[row] ||= []
15
+ data[row] ||= Array.new
16
16
  data[row][col] = value
17
17
  end
18
18
  end
19
19
  data
20
20
  end
21
21
 
22
+ # Build the data from an Array<String>.
23
+ # Each String of the format returned by the snmpwalk command ("<oid> = <type>: <value>").
24
+ # @param data [Array<String>] The Strings to get the data from
25
+ # @return [Array<Array<#to_s>>] A two dimensional array containing objects in each cell (at 'address' data\[row\]\[col\])
26
+ def self.from_array(data_in)
27
+ data_out = Array.new
28
+ regexp_general = Regexp.compile(/\A(?:iso)?[\.0-9]+\.([0-9]+)\.([0-9]+)\s+=\s+([A-Za-z0-9 \-]+):\s+(.+)\Z/)
29
+ regexp_nodata = Regexp.compile(/\A(?:iso)?[\.0-9]+\.([0-9]+)\.([0-9]+)\s+=\s+""\Z/)
30
+ data_in.each.with_index do |line, index|
31
+ # Try to get a match on the various valid frmats of line
32
+ match = line.match(regexp_general)
33
+ match ||= line.match(regexp_nodata)
34
+ if match.nil?
35
+ STDERR.puts "Could not parse data on line #{index+1}: #{line}"
36
+ next
37
+ end
38
+
39
+ col, row, type, value = match.captures
40
+ # Convert value
41
+ case type && type.downcase
42
+ when nil
43
+ when 'string'
44
+ value = value[1..-2] # Strip enclosing quotes
45
+ when 'oid', 'hex-string'
46
+ when 'integer', 'integer32', 'uinteger32', 'gauge32', 'counter32', 'counter64'
47
+ value = value.to_i
48
+ when 'ipaddress'
49
+ value = IPAddr.new(value)
50
+ when 'timeticks'
51
+ match = value.match(/\A\((\d+)\)/)
52
+ value = NETSNMP::Timetick.new(match.nil? ? 0 : match[1].to_i)
53
+ else
54
+ STDERR.puts "Unknown SNMP type (#{type}) on line #{index+1}: #{line}"
55
+ end
56
+
57
+ # Save value
58
+ row = row.to_i - 1
59
+ col = col.to_i - 1
60
+ data_out[row] ||= Array.new
61
+ data_out[row][col] = value
62
+ end # each line of data_in
63
+ data_out
64
+ end
65
+
22
66
  end # class Fetcher
23
67
 
24
68
  end # module SNMPTableViewer
@@ -11,4 +11,24 @@ require_relative '../version'
11
11
  Dir["#{File.dirname(__FILE__)}/**/*.rb"].select{ |f| f != __FILE__}.sort.each { |f| load(f) }
12
12
 
13
13
  module SNMPTableViewer
14
+
15
+ HEADINGS_FOR = {
16
+ 'ifTable' => ['Index', 'Descr', 'Type', 'Mtu', 'Speed', 'PhysAddress', 'AdminStatus', 'OperStatus', 'LastChange', 'InOctets', 'InUcastPkts', 'InNUcastkts', 'InDiscards', 'InErrors', 'InUnknownPrortos', 'OutOctets', 'OutUcastPkts', 'OutNUcastPkts', 'OutDiscards', 'OutErrors', 'OutQLen', 'Specific'],
17
+ }.freeze
18
+
19
+ FORMATTERS = {
20
+ 'table' => SNMPTableViewer::Formatter::Table,
21
+ 'csv' => SNMPTableViewer::Formatter::CSV,
22
+ 'json' => SNMPTableViewer::Formatter::JSON,
23
+ 'raw' => SNMPTableViewer::Formatter::Raw,
24
+ }.freeze
25
+
26
+ CONVERTERS = {
27
+ 'iftable' => SNMPTableViewer::Converter::IfTable,
28
+ }.freeze
29
+
30
+ BASE_OIDS = {
31
+ 'iftable' => '1.3.6.1.2.1.2.2',
32
+ }.freeze
33
+
14
34
  end # module SNMPTableViewer
@@ -1,21 +1,22 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
2
+ $:.push File.expand_path(File.join('..', 'lib'), __FILE__)
3
3
  require File.join(File.dirname(__FILE__), 'version')
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "snmp_table_viewer"
6
+ s.name = 'snmp_table_viewer'
7
7
  s.license = 'BSD 3 clause'
8
8
  s.version = SNMPTableViewer::VERSION
9
9
  s.authors = ['Robert Gauld']
10
10
  s.email = ['robert@robertgauld.co.uk']
11
- s.homepage = 'https://github.com/robertgauld/snmp-table-viewer'
11
+ s.homepage = 'https://github.com/robertgauld/snmp_table_viewer'
12
12
  s.summary = %q{Easily view SNMP tables.}
13
13
  s.description = %q{Easily view SNMP tables in a variety of different formats including as a table in the terminal, json or csv.}
14
14
 
15
15
  s.files = `git ls-files`.split("\n")
16
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
- s.require_paths = ["lib"]
18
+ s.require_paths = ['lib']
19
+ s.bindir = 'bin'
19
20
 
20
21
  s.add_runtime_dependency 'netsnmp', '~> 0.1.3'
21
22
  s.add_runtime_dependency 'terminal-table', '~> 1.8.0'
@@ -1,6 +1,6 @@
1
1
  describe SNMPTableViewer::Fetcher do
2
2
 
3
- it 'Fetches' do
3
+ it '#from_snmp' do
4
4
  snmp_options = {opt_a: :a}
5
5
  manager = double("manager")
6
6
  expect(manager).to receive(:walk).with(oid: '1.2.3.4.5').once.and_return([
@@ -20,4 +20,46 @@ describe SNMPTableViewer::Fetcher do
20
20
  ]
21
21
  end
22
22
 
23
+ describe '#from_array' do
24
+ it 'Given array of strings "<oid> = <type>: <value>"' do
25
+ data = [
26
+ 'iso.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1',
27
+ 'iso.3.6.1.2.1.2.2.1.2.1 = STRING: "lo"',
28
+ 'iso.3.6.1.2.1.2.2.1.3.1 = Gauge32: 2',
29
+ 'iso.3.6.1.2.1.2.2.1.4.1 = Hex-STRING: 01 23 45 67 89 AB',
30
+ 'iso.3.6.1.2.1.2.2.1.5.1 = Timeticks: (10) 0:00:10.00',
31
+ 'iso.3.6.1.2.1.2.2.1.6.1 = Counter32: 3',
32
+ 'iso.3.6.1.2.1.2.2.1.7.1 = OID: ccitt.0',
33
+ 'iso.3.6.1.2.1.2.2.1.8.1 = IpAddress: 1.2.3.4',
34
+ 'iso.3.6.1.2.1.2.2.1.10.1 = ""',
35
+ ]
36
+ expect(described_class.from_array(data)).to eq [[
37
+ 1,
38
+ 'lo',
39
+ 2,
40
+ '01 23 45 67 89 AB',
41
+ NETSNMP::Timetick.new(10),
42
+ 3,
43
+ 'ccitt.0',
44
+ IPAddr.new('1.2.3.4'),
45
+ nil,
46
+ nil
47
+ ]]
48
+ end
49
+
50
+ it 'Errors but survives on a bad line' do
51
+ data = ['This is a bad line', 'This is another bad line']
52
+ expect(STDERR).to receive(:puts).with('Could not parse data on line 1: This is a bad line').once
53
+ expect(STDERR).to receive(:puts).with('Could not parse data on line 2: This is another bad line').once
54
+ expect(described_class.from_array(data)).to eq []
55
+ end
56
+
57
+ it 'Errors but survives on a bad type' do
58
+ data = ['1.2.3.4.0.1.1 = INTEGER: 1', '1.2.3.4.0.2.1 = invalid-type: 1']
59
+ expect(STDERR).to receive(:puts).with('Unknown SNMP type (invalid-type) on line 2: 1.2.3.4.0.2.1 = invalid-type: 1').once
60
+ expect(described_class.from_array(data)).to eq [[1, '1']]
61
+ end
62
+
63
+ end # describe #from_array
64
+
23
65
  end
data/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module SNMPTableViewer
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snmp_table_viewer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Gauld
@@ -139,7 +139,8 @@ description: Easily view SNMP tables in a variety of different formats including
139
139
  email:
140
140
  - robert@robertgauld.co.uk
141
141
  executables:
142
- - snmp-table-viewer
142
+ - table-from-snmp
143
+ - table-from-stdin
143
144
  extensions: []
144
145
  extra_rdoc_files: []
145
146
  files:
@@ -153,7 +154,8 @@ files:
153
154
  - LICENSE.rdoc
154
155
  - README.md
155
156
  - Rakefile
156
- - bin/snmp-table-viewer
157
+ - bin/table-from-snmp
158
+ - bin/table-from-stdin
157
159
  - lib/snmp_table_viewer.rb
158
160
  - lib/snmp_table_viewer/converter.rb
159
161
  - lib/snmp_table_viewer/converter/if_table.rb
@@ -175,7 +177,7 @@ files:
175
177
  - spec/snmp_table_viewer_spec.rb
176
178
  - spec/spec_helper.rb
177
179
  - version.rb
178
- homepage: https://github.com/robertgauld/snmp-table-viewer
180
+ homepage: https://github.com/robertgauld/snmp_table_viewer
179
181
  licenses:
180
182
  - BSD 3 clause
181
183
  metadata: {}