snmp-open 0.1.3 → 0.1.4

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: 42cc48b7cd27987ef9bf4a9ab604a7c819ff2dae
4
- data.tar.gz: c3a38d4e43063ed42a0ce786628e3af6a915504b
3
+ metadata.gz: 9ae08ac661e97b5c47899d166a7bdcd6b71e0c55
4
+ data.tar.gz: b10aae94bb31fc05b38ec3d3ab9ce1d450c3b104
5
5
  SHA512:
6
- metadata.gz: 423425fb07efe8265c9384d1f60ebe18ec12ea5a08f9e58551b6837e817fb84fb9604a63690398d23e21d2b537a23b2c00d958d3b2b00c0e3eb5aca5f23faaa8
7
- data.tar.gz: 4af15c0e555126e1015936069aeac4c8aaf9ec3e8b067089f3e9092205609478a30bc566232d1c2c0f3c519b0283dcd4e8b881e4d199101c36ab7e1ccbcae3a7
6
+ metadata.gz: 998d8abcd4e3e7b5967affb6441f590201c7a0c15b24ebe7f56911fa17a103086a2c6392586baa4fb9fe26083985e9de8cbc174eb2524a4303602a11757301be
7
+ data.tar.gz: ecf925444abd22e218b7235985aa5d98357f9e6e34b759ac760d3bbc5c1e83c89c46c261132663ee479124932c5b8d07e3313c88edd812cccf18aed1a179ce31
data/bin/console CHANGED
@@ -6,5 +6,5 @@ require 'snmp/open'
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
- require "pry"
9
+ require 'pry'
10
10
  Pry.start
data/bin/get ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/ruby
2
+ require 'json'
3
+ $LOAD_PATH << File.join(__dir__, '..', 'lib')
4
+ require 'snmp/open'
5
+
6
+ host = ARGV.fetch(0)
7
+ oids = ARGV[1..-1]
8
+ jj SNMP::Open.new(host: host).get(oids).to_a
data/bin/walk ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/ruby
2
+ require 'json'
3
+ $LOAD_PATH << File.join(__dir__, '..', 'lib')
4
+ require 'snmp/open'
5
+
6
+ host = ARGV.fetch(0)
7
+ oids = ARGV[1..-1]
8
+ jj SNMP::Open.new(host: host).walk(oids).to_a
data/lib/snmp/open.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'open3'
2
1
  require 'snmp/open/parser'
2
+ require 'snmp/open/command_reader'
3
3
 
4
4
  # Simple Network Management Protocol
5
5
  module SNMP
@@ -19,92 +19,39 @@ module SNMP
19
19
 
20
20
  # Open3-based wrapper for SNMP CLI commands
21
21
  class Open
22
- attr_reader :options
22
+ attr_reader :reader
23
23
 
24
- # see snmpcmd(1) for explanation of options
25
- OPTIONS = {
26
- version: '-v',
27
- auth_password: '-A',
28
- auth_protocol: '-a',
29
- community: '-c',
30
- context: '-n',
31
- numeric: '-On', # needed by parser, should always be enabled
32
- priv_password: '-X', # not recommended, see snmp.conf(5)
33
- priv_protocol: '-x',
34
- sec_level: '-l',
35
- sec_user: '-u',
36
- retries: '-r',
37
- timeout: '-t',
38
- host: nil
39
- }.freeze
40
-
41
- # +options+ accepts options dealing with making connections to the host,
42
- # including all of the options listed in the +OPTIONS+ constant hash. Other
43
- # options can be given as strings (or any object with a suitable +to_s+
44
- # method), e.g., these are equivalent:
45
- #
46
- # SNMP::Open.new(host: hostname, timeout: 3, '-m' => miblist)
47
- # SNMP::Open.new(hostname => nil, '-t' => '3', '-m' => miblist)
48
- #
24
+ # see CommandReader for a description of options
49
25
  def initialize(options = {})
50
- host = options.delete(:host) ||
51
- (raise ArgumentError, 'Host expected but not given')
52
- @host_options = merge_options(options)
53
- .merge('-On' => nil, host => nil)
54
- return if @host_options.key?(nil)
55
- end
56
-
57
- # Generate a CLI command string
58
- def cli(command, id = nil, options = {})
59
- command = case command
60
- when Symbol then "snmp#{command}"
61
- else command.to_s
62
- end
63
-
64
- [
65
- command,
66
- *options.map { |k, v| "#{k}#{v}" },
67
- *@host_options.map { |k, v| "#{k}#{v}" },
68
- *id
69
- ].join(' ')
26
+ @reader = options[:reader] || CommandReader.new(options)
70
27
  end
71
28
 
72
29
  # Perform an SNMP get using the "snmpget" command and parse the output
73
30
  def get(oids)
74
31
  return enum_for(:get, oids) unless block_given?
75
- texts = oids.map { |oid| capture_command(:get, oid) }
76
- Parser.new(oids).parse(texts).each { |arg, *| yield(arg) }
32
+ texts = oids.map { |oid| reader.capture(:get, oid) }
33
+ Parser.new(oids).parse(texts).first.each { |arg| yield(arg) }
77
34
  end
78
35
 
79
36
  # Perform an SNMP walk using the "snmpwalk" or "snmpbulkwalk" commands and
80
37
  # parse the output
81
38
  def walk(oids, **kwargs)
82
- kwargs = { bulk: true, non_repeaters: 0, max_repetitions: 10 }
83
- .merge(kwargs)
84
39
  return enum_for(:walk, oids, **kwargs) unless block_given?
40
+ bulk = kwargs.fetch(:bulk, true)
41
+ options = walk_options(bulk, **kwargs)
85
42
  cmd = bulk ? :bulkwalk : :walk
86
- options = bulk ? { '-Cn' => non_repeaters, '-Cr' => max_repetitions } : {}
87
- texts = oids.map { |oid| capture_command(cmd, oid, options) }
43
+ texts = oids.map { |oid| reader.capture(cmd, oid, options) }
88
44
  Parser.new(oids).parse(texts).each { |*args| yield(*args) }
89
45
  end
90
46
 
91
- private
92
-
93
- def capture_command(cmd, oid, options = {})
94
- out, err = Open3.capture3(cli(cmd, oid, options))
95
- raise err unless err.empty?
96
- out
97
- end
98
-
99
- def merge_options(options = {})
100
- options.each_pair.with_object({}) do |(key, value), opts|
101
- if OPTIONS.key?(key)
102
- opts[OPTIONS[key]] = value
103
- elsif key.is_a?(String)
104
- opts[key] = value
105
- else
106
- raise "Unknown option #{key}"
107
- end
47
+ def walk_options(bulk, **kwargs)
48
+ if bulk
49
+ {
50
+ '-Cn' => kwargs.fetch(:non_repeaters, 0),
51
+ '-Cr' => kwargs.fetch(:max_repetitions, 10)
52
+ }
53
+ else
54
+ {}
108
55
  end
109
56
  end
110
57
  end # class Open
@@ -0,0 +1,75 @@
1
+ require 'open3'
2
+
3
+ module SNMP
4
+ class Open
5
+ # Open3-based data source that executes an snmp* command and captures the
6
+ # output
7
+ class CommandReader
8
+ # see snmpcmd(1) for explanation of options
9
+ OPTIONS = {
10
+ version: '-v',
11
+ auth_password: '-A',
12
+ auth_protocol: '-a',
13
+ community: '-c',
14
+ context: '-n',
15
+ numeric: '-On', # needed by parser, should always be enabled
16
+ priv_password: '-X', # not recommended, see snmp.conf(5)
17
+ priv_protocol: '-x',
18
+ sec_level: '-l',
19
+ sec_user: '-u',
20
+ retries: '-r',
21
+ timeout: '-t',
22
+ host: nil
23
+ }.freeze
24
+
25
+ # +options+ accepts options dealing with making connections to the host,
26
+ # including all of the options listed in the +OPTIONS+ constant hash.
27
+ # Other options can be given as strings (or any object with a suitable
28
+ # +to_s+ method), e.g., these are equivalent:
29
+ #
30
+ # SNMP::Open.new(host: hostname, timeout: 3, '-m' => miblist)
31
+ # SNMP::Open.new(hostname => nil, '-t' => '3', '-m' => miblist)
32
+ #
33
+ def initialize(options)
34
+ host = options.delete(:host) ||
35
+ (raise ArgumentError, 'Host expected but not given')
36
+ @host_options = merge_options(options).merge('-On' => nil, host => nil)
37
+ end
38
+
39
+ def capture(cmd, oid, options = {})
40
+ out, err = Open3.capture3(cli(cmd, oid, options))
41
+ raise err unless err.empty?
42
+ out
43
+ end
44
+
45
+ # Generate a CLI command string
46
+ def cli(command, id = nil, options = {})
47
+ command = case command
48
+ when Symbol then "snmp#{command}"
49
+ else command.to_s
50
+ end
51
+
52
+ [
53
+ command,
54
+ *options.map { |k, v| "#{k}#{v}" },
55
+ *@host_options.map { |k, v| "#{k}#{v}" },
56
+ *id
57
+ ].join(' ')
58
+ end
59
+
60
+ private
61
+
62
+ def merge_options(options = {})
63
+ options.each_pair.with_object({}) do |(key, value), opts|
64
+ if OPTIONS.key?(key)
65
+ opts[OPTIONS[key]] = value
66
+ elsif key.is_a?(String)
67
+ opts[key] = value
68
+ else
69
+ raise "Unknown option #{key}"
70
+ end
71
+ end
72
+ end
73
+ end # class CommandReader
74
+ end # class Open
75
+ end # module SNMP
@@ -1,8 +1,8 @@
1
- require 'snmp/open/parser'
1
+ require 'snmp/open/command_reader'
2
2
 
3
3
  module SNMP
4
4
  class Open
5
- # Test double for SNMP::Open that reads from the filesystem instead of
5
+ # Test data source for SNMP::Open that reads from the filesystem instead of
6
6
  # running SNMP commands. Expects a 'walk' directory to be present if #walk
7
7
  # will be used, and a 'get' directory if #get will be used. Within each
8
8
  # directory, files named according to the numeric OIDs to be used are
@@ -12,37 +12,19 @@ module SNMP
12
12
  # Produces warnings describing an snmpbulkwalk or snmpget command that could
13
13
  # be used to generate a needed file, if the file is unavailable. Controlled
14
14
  # by the `warnings` option.
15
-
16
15
  class FileReader
17
16
  def initialize(directory, options = {})
18
17
  @directory = directory
19
18
  @warnings = options.delete(:warnings)
20
- @command_generator = SNMP::Open.new(options.merge(host: '$OPTIONS'))
21
- end
22
-
23
- def get(oids)
24
- return enum_for(:get, oids) unless block_given?
25
- texts = oids.map { |o| File.read(File.join(@directory, 'get', o)) }
26
- Parser.new(oids).parse(texts).each { |arg, *| yield(arg) }
27
- rescue Errno::ENOENT => err
28
- if @warnings
29
- oids.each do |oid|
30
- warn "#{@command_generator.cli(:get, oid)} > get/#{oid}"
31
- end
32
- end
33
- raise err
19
+ @command_generator =
20
+ SNMP::Open::CommandReader.new(options.merge(host: '$OPTIONS'))
34
21
  end
35
22
 
36
- def walk(oids, *rest)
37
- return enum_for(:walk, oids, *rest) unless block_given?
38
- texts = oids.map { |o| File.read(File.join(@directory, 'walk', o)) }
39
- Parser.new(oids).parse(texts).each { |*args| yield(*args) }
23
+ def capture(cmd, oid, _options = {})
24
+ outfile = File.join(cmd.to_s, oid)
25
+ File.read(File.join(@directory, outfile))
40
26
  rescue Errno::ENOENT => err
41
- if @warnings
42
- oids.each do |oid|
43
- warn "#{@command_generator.cli(:bulkwalk, oid)} > walk/#{oid}"
44
- end
45
- end
27
+ warn "#{@command_generator.cli(cmd, oid)} > #{outfile}" if @warnings
46
28
  raise err
47
29
  end
48
30
  end # class FileReader
@@ -13,6 +13,8 @@ module SNMP
13
13
  class Parser
14
14
  NOSUCHOBJECT_STR =
15
15
  'No Such Object available on this agent at this OID'.freeze
16
+ NOSUCHINSTANCE_STR =
17
+ 'No Such Instance currently exists at this OID'.freeze
16
18
 
17
19
  def initialize(oids)
18
20
  @oids = oids
@@ -21,7 +23,10 @@ module SNMP
21
23
  def parse(texts)
22
24
  columns = texts.map do |text|
23
25
  tokenized =
24
- text.gsub(NOSUCHOBJECT_STR, %("#{NOSUCHOBJECT_STR}")).shellsplit
26
+ text
27
+ .gsub(NOSUCHOBJECT_STR, %("#{NOSUCHOBJECT_STR}"))
28
+ .gsub(NOSUCHINSTANCE_STR, %("#{NOSUCHINSTANCE_STR}"))
29
+ .shellsplit
25
30
  parse_tokens(tokenized)
26
31
  end
27
32
 
@@ -80,12 +85,14 @@ module SNMP
80
85
  next_token = tokens.next
81
86
  type = next_token.match(/\A([A-Z]+):\z/) { |md| md[1] }
82
87
  type, value = parse_value(tokens, next_token, type)
83
- [type, convert_value(type, value)]
88
+ [type, Conversions.convert_value(type, value)]
84
89
  end
85
90
 
86
91
  def parse_value(tokens, token, type)
87
92
  if token == NOSUCHOBJECT_STR
88
93
  ['No Such Object', nil]
94
+ elsif token == NOSUCHINSTANCE_STR
95
+ ['No Such Instance', nil]
89
96
  elsif !type
90
97
  ['STRING', token]
91
98
  else
@@ -109,22 +116,25 @@ module SNMP
109
116
  @oids.zip(columns).map do |oid, column|
110
117
  indexes.map do |index|
111
118
  id = (oid == index ? index : "#{oid}.#{index}")
112
- column.find { |o| o.oid == id } || absent_value(id)
119
+ column.find { |o| o.oid == id } || Conversions.absent_value(id)
113
120
  end
114
121
  end
115
122
  end
116
123
 
117
- def convert_value(type, value)
118
- case type
119
- when 'INTEGER'
120
- value.to_i
121
- else
122
- value
124
+ # functions to generate value objects
125
+ module Conversions
126
+ module_function def convert_value(type, value)
127
+ case type
128
+ when 'INTEGER'
129
+ value.to_i
130
+ else
131
+ value
132
+ end
123
133
  end
124
- end
125
134
 
126
- def absent_value(id)
127
- Value.new(id, 'absent', nil)
135
+ module_function def absent_value(id)
136
+ Value.new(id, 'absent', nil)
137
+ end
128
138
  end
129
139
  end # class Parser
130
140
  end # class Open
@@ -1,5 +1,5 @@
1
1
  module Snmp
2
2
  module Open
3
- VERSION = '0.1.3'.freeze
3
+ VERSION = '0.1.4'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snmp-open
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Miller
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-03-17 00:00:00.000000000 Z
11
+ date: 2017-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -83,8 +83,11 @@ files:
83
83
  - README.md
84
84
  - Rakefile
85
85
  - bin/console
86
+ - bin/get
86
87
  - bin/setup
88
+ - bin/walk
87
89
  - lib/snmp/open.rb
90
+ - lib/snmp/open/command_reader.rb
88
91
  - lib/snmp/open/file_reader.rb
89
92
  - lib/snmp/open/parser.rb
90
93
  - lib/snmp/open/version.rb