snmp_table_viewer 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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: {}