snmp-open 0.3.0 → 0.6.1

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
- SHA1:
3
- metadata.gz: '09dd63241e17dc715dc949d0b727f61e777cfade'
4
- data.tar.gz: a3bf4afbcb4debc166bbc04b0c67292d41a63a12
2
+ SHA256:
3
+ metadata.gz: 2778b6bac09136b98ff5bfcdf5313f470d8468d556353f4e5466479624291383
4
+ data.tar.gz: b2f2a13ad5ad75e79116e33e63f2462e768b5850887180e9b94e1ff369c17bac
5
5
  SHA512:
6
- metadata.gz: bdf0ce08cdc82f961165108a9ea267011cf65c84c34b9ff944d91650ea9ea13bdc413f83346115041b1e6797509a3bda4a823e34de8b02c912587d071b3856f4
7
- data.tar.gz: 402b3e552a7c41ffe6f33b48f8c62e42ab79a1775540068304579f3babcaf0309b7d17b8cb4a7b4c195ea0d35ba52d103259e37ec02c54ea6c4c04ea97d6eb8f
6
+ metadata.gz: f61f7cbd63437b97d260e8bee251cfe45ca02a706564de5ae293859c5ab8feb80c253fdd67ba0fe93fd78b1df49370adca9a12cecac6b545456efdeccf8f4553
7
+ data.tar.gz: 816aba2a56ded47b4dadbe0fee21e339bfa423bd76bc6a4e1a2e5979dfc2048fa62124c23447e4d7144d6da06f153b48b04ff3374b5647fd05d0d94a9e8d8ba7
@@ -0,0 +1,24 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ubuntu-latest, macos-latest]
15
+ ruby: [2.4, 2.5, 2.6, 2.7, jruby, truffleruby]
16
+ runs-on: ${{ matrix.os }}
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ bundler-cache: true
23
+ - name: Run tests
24
+ run: bundle exec rake
@@ -0,0 +1,62 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+
4
+ Style/CommentedKeyword:
5
+ Enabled: false
6
+
7
+ Lint/MissingSuper:
8
+ Exclude:
9
+ - 'lib/snmp/open/parser/value_parser.rb'
10
+
11
+ Metrics/ClassLength:
12
+ Exclude:
13
+ - 'lib/snmp/open/parser.rb'
14
+
15
+ Style/AccessModifierDeclarations: {Enabled: false}
16
+ Style/IfUnlessModifier: {Enabled: false}
17
+ Style/FrozenStringLiteralComment: {Enabled: false}
18
+
19
+ Layout/SpaceBeforeBrackets: # (new in 1.7)
20
+ Enabled: true
21
+ Lint/AmbiguousAssignment: # (new in 1.7)
22
+ Enabled: true
23
+ Lint/DeprecatedConstants: # (new in 1.8)
24
+ Enabled: true
25
+ Lint/DuplicateBranch: # (new in 1.3)
26
+ Enabled: true
27
+ Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1)
28
+ Enabled: true
29
+ Lint/EmptyBlock: # (new in 1.1)
30
+ Enabled: true
31
+ Lint/EmptyClass: # (new in 1.3)
32
+ Enabled: true
33
+ Lint/LambdaWithoutLiteralBlock: # (new in 1.8)
34
+ Enabled: true
35
+ Lint/NoReturnInBeginEndBlocks: # (new in 1.2)
36
+ Enabled: true
37
+ Lint/RedundantDirGlobSort: # (new in 1.8)
38
+ Enabled: true
39
+ Lint/ToEnumArguments: # (new in 1.1)
40
+ Enabled: true
41
+ Lint/UnexpectedBlockArity: # (new in 1.5)
42
+ Enabled: true
43
+ Lint/UnmodifiedReduceAccumulator: # (new in 1.1)
44
+ Enabled: true
45
+ Style/ArgumentsForwarding: # (new in 1.1)
46
+ Enabled: true
47
+ Style/CollectionCompact: # (new in 1.2)
48
+ Enabled: true
49
+ Style/DocumentDynamicEvalDefinition: # (new in 1.1)
50
+ Enabled: true
51
+ Style/EndlessMethod: # (new in 1.8)
52
+ Enabled: true
53
+ Style/HashExcept: # (new in 1.7)
54
+ Enabled: true
55
+ Style/NegatedIfElseCondition: # (new in 1.2)
56
+ Enabled: true
57
+ Style/NilLambda: # (new in 1.3)
58
+ Enabled: true
59
+ Style/RedundantArgument: # (new in 1.4)
60
+ Enabled: true
61
+ Style/SwapValues: # (new in 1.1)
62
+ Enabled: true
data/Gemfile CHANGED
@@ -5,4 +5,5 @@ group :guard do
5
5
  gem 'guard'
6
6
  gem 'guard-rspec'
7
7
  gem 'guard-rubocop'
8
+ gem 'rubocop', '~>1.0'
8
9
  end
@@ -27,16 +27,18 @@ module SNMP
27
27
  end
28
28
 
29
29
  # Perform an SNMP get using the "snmpget" command and parse the output
30
- def get(oids)
30
+ def get(oids, &block)
31
31
  return enum_for(:get, oids) unless block_given?
32
+
32
33
  texts = oids.map { |oid| reader.capture(:get, oid) }
33
- Parser.new(oids).parse(texts).fetch(0, []).each { |arg| yield(arg) }
34
+ Parser.new(oids).parse(texts).fetch(0, []).each(&block)
34
35
  end
35
36
 
36
37
  # Perform an SNMP walk using the "snmpwalk" or "snmpbulkwalk" commands and
37
38
  # parse the output
38
39
  def walk(oids, **kwargs)
39
40
  return enum_for(:walk, oids, **kwargs) unless block_given?
41
+
40
42
  bulk = kwargs.fetch(:bulk, true)
41
43
  options = walk_options(bulk, **kwargs)
42
44
  cmd = bulk ? :bulkwalk : :walk
@@ -1,39 +1,13 @@
1
1
  require 'open3'
2
+ require 'snmp/open/options'
2
3
 
3
4
  module SNMP
4
5
  class Open
5
6
  # Open3-based data source that executes an snmp* command and captures the
6
7
  # output
7
8
  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
- no_check_increasing: {
16
- 'snmpbulkwalk' => '-Cc',
17
- 'snmpwalk' => '-Cc'
18
- },
19
- numeric: '-On', # needed by parser, should always be enabled
20
- priv_password: '-X', # not recommended, see snmp.conf(5)
21
- priv_protocol: '-x',
22
- sec_level: '-l',
23
- sec_user: '-u',
24
- retries: '-r',
25
- timeout: '-t',
26
- host: nil
27
- }.freeze
28
-
29
- OPTION_VALUES = {
30
- no_check_increasing: {
31
- true => ''
32
- }.freeze
33
- }.freeze
34
-
35
9
  # +options+ accepts options dealing with making connections to the host,
36
- # including all of the options listed in the +OPTIONS+ constant hash.
10
+ # including all of the options listed in the +Options::MAP+ constant hash.
37
11
  # Other options can be given as strings (or any object with a suitable
38
12
  # +to_s+ method), e.g., these are equivalent:
39
13
  #
@@ -44,7 +18,9 @@ module SNMP
44
18
  @env = options.delete(:env)
45
19
  host = options.delete(:host) ||
46
20
  (raise ArgumentError, 'Host expected but not given')
47
- opts = merge_options(options).merge('-On' => nil, host => nil)
21
+ opts = Options::REQUIRED_BY_PARSER
22
+ .merge(merge_options(options))
23
+ .merge(host => nil)
48
24
  @command_options, @host_options = partition_options(opts)
49
25
  end
50
26
 
@@ -54,8 +30,7 @@ module SNMP
54
30
  else
55
31
  Open3.capture3(cli(cmd, oid, options))
56
32
  end
57
- raise CommandTimeoutError, err.chomp if err =~ /^timeout/i
58
- raise CommandError, err.chomp unless err.empty?
33
+ raise_capture_errors(err)
59
34
  out
60
35
  end
61
36
 
@@ -66,6 +41,7 @@ module SNMP
66
41
  [
67
42
  command,
68
43
  *options.map { |k, v| "#{k}#{v}" },
44
+ *oid_options(id),
69
45
  *@host_options.map { |k, v| "#{k}#{v}" },
70
46
  *@command_options.fetch(command, {}).map { |k, v| "#{k}#{v}" },
71
47
  *id
@@ -74,11 +50,24 @@ module SNMP
74
50
 
75
51
  private
76
52
 
53
+ def raise_capture_errors(err)
54
+ case err
55
+ when /^Cannot find module \(([^)]+)\)/
56
+ raise UnknownMIBError, "Unknown MIB: #{Regexp.last_match(1)}"
57
+ when /^(\S+): Unknown Object Identifier$/
58
+ raise UnknownOIDError, "Unknown OID: #{Regexp.last_match(1)}"
59
+ when /^timeout/i
60
+ raise CommandTimeoutError, err.chomp
61
+ when /./
62
+ raise CommandError, err.chomp
63
+ end
64
+ end
65
+
77
66
  def merge_options(options = {})
78
67
  options.each_pair.with_object({}) do |(key, value), opts|
79
- if OPTIONS.key?(key)
80
- opts[OPTIONS[key]] =
81
- (OPTION_VALUES.fetch(key, {}).fetch(value, value) || next)
68
+ if Options::MAP.key?(key)
69
+ opts[Options::MAP[key]] =
70
+ (Options::VALUES.fetch(key, {}).fetch(value, value) || next)
82
71
  elsif key.is_a?(String)
83
72
  opts[key] = value
84
73
  else
@@ -87,6 +76,15 @@ module SNMP
87
76
  end
88
77
  end
89
78
 
79
+ # if the request OID is all-numeric, force numeric OID in the output
80
+ def oid_options(id)
81
+ if id =~ /[^0-9.]/
82
+ []
83
+ else
84
+ ['-On']
85
+ end
86
+ end
87
+
90
88
  def normalize_command(command)
91
89
  case command
92
90
  when Symbol then "snmp#{command}"
@@ -123,6 +121,11 @@ module SNMP
123
121
  end # class CommandReader
124
122
 
125
123
  class CommandError < RuntimeError; end
124
+
126
125
  class CommandTimeoutError < CommandError; end
126
+
127
+ class UnknownMIBError < CommandError; end
128
+
129
+ class UnknownOIDError < CommandError; end
127
130
  end # class Open
128
131
  end # module SNMP
@@ -13,19 +13,36 @@ module SNMP
13
13
  # be used to generate a needed file, if the file is unavailable. Controlled
14
14
  # by the `warnings` option.
15
15
  class FileReader
16
+ DEFAULT_WARNING_FORMATTER = lambda { |gen, cmd, oid, outfile|
17
+ "#{gen.cli(cmd, oid)} > #{outfile}"
18
+ }
19
+
16
20
  def initialize(directory, options = {})
17
21
  @directory = directory
18
22
  @warnings = options.delete(:warnings)
19
- @command_generator =
20
- SNMP::Open::CommandReader.new(options.merge(host: '$OPTIONS'))
23
+ @make_directories = options.delete(:make_directories)
24
+ if @warnings && !@warnings.respond_to?(:call)
25
+ @warnings = DEFAULT_WARNING_FORMATTER
26
+ end
27
+ options[:host] ||= '$OPTIONS'
28
+ @command_generator = SNMP::Open::CommandReader.new(options)
21
29
  end
22
30
 
23
31
  def capture(cmd, oid, _options = {})
24
- outfile = File.join(cmd.to_s, oid)
25
- File.read(File.join(@directory, outfile))
26
- rescue Errno::ENOENT => err
27
- warn "#{@command_generator.cli(cmd, oid)} > #{outfile}" if @warnings
28
- raise err
32
+ mkdir(@directory, cmd.to_s) if @make_directories
33
+ outfile = File.join(@directory, cmd.to_s, oid)
34
+ File.read(outfile)
35
+ rescue Errno::ENOENT => e
36
+ if @warnings
37
+ warning = @warnings.call(@command_generator, cmd, oid, outfile)
38
+ warn warning
39
+ end
40
+ raise e
41
+ end
42
+
43
+ def mkdir(base, cmd)
44
+ Dir.mkdir(base) unless File.exist?(base)
45
+ Dir.mkdir(File.join(base, cmd)) unless File.exist?(File.join(base, cmd))
29
46
  end
30
47
  end # class FileReader
31
48
  end # class Open
@@ -0,0 +1,41 @@
1
+ module SNMP
2
+ class Open
3
+ class Options
4
+ # see snmpcmd(1) for explanation of options
5
+ MAP = {
6
+ version: '-v',
7
+ auth_password: '-A',
8
+ auth_protocol: '-a',
9
+ community: '-c',
10
+ context: '-n',
11
+ no_check_increasing: {
12
+ 'snmpbulkwalk' => '-Cc',
13
+ 'snmpwalk' => '-Cc'
14
+ },
15
+ no_units: '-OU',
16
+ non_symbolic: '-Oe',
17
+ numeric: '-On',
18
+ priv_password: '-X', # not recommended, see snmp.conf(5)
19
+ priv_protocol: '-x',
20
+ sec_level: '-l',
21
+ sec_user: '-u',
22
+ retries: '-r',
23
+ timeout: '-t',
24
+ host: nil
25
+ }.freeze
26
+
27
+ # On some systems, SNMP command outputs will include symbolic values
28
+ # and/or value units. The parser doesn't support these, so disable them.
29
+ REQUIRED_BY_PARSER = {
30
+ '-Oe' => nil,
31
+ '-OU' => nil
32
+ }.freeze
33
+
34
+ VALUES = {
35
+ no_check_increasing: {
36
+ true => ''
37
+ }.freeze
38
+ }.freeze
39
+ end # class Options
40
+ end # class Open
41
+ end # module SNMP
@@ -1,5 +1,7 @@
1
1
  require 'set'
2
2
  require 'shellwords'
3
+ require 'snmp/open/parser/constants'
4
+ require 'snmp/open/parser/value_parser'
3
5
 
4
6
  module SNMP
5
7
  class Open
@@ -11,10 +13,38 @@ module SNMP
11
13
 
12
14
  # convert SNMP command output into arrays
13
15
  class Parser
14
- NOSUCHOBJECT_STR =
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
+ include SNMP::Open::Parser::Constants
17
+ OID_RE = Regexp.union(/\S+-MIB::\S+/, /[0-9.]+/)
18
+
19
+ EMPTY_STRING_RE =
20
+ /^(#{OID_RE}) # capture group 1: OID
21
+ \s+=\s+
22
+ (Opaque|STRING) # capture group 2: Type
23
+ :\s*\n # value is always empty string
24
+ /x.freeze
25
+
26
+ STRING_RE =
27
+ /^(#{OID_RE}) # capture group 1: OID
28
+ \s+=\s+
29
+ (Opaque|STRING):\s+ # capture group 2: Type
30
+
31
+ ( # capture group 3: Value
32
+
33
+ (?!") # this pattern is for finding strings in need of
34
+ # quoting, so reject any strings that are already
35
+ # quoted
36
+
37
+ [^\n]* # first line of value
38
+
39
+ (\n # newline before each additional line of value
40
+ (?!
41
+ #{OID_RE} # additional lines of value are identified by not
42
+ \s+=\s+ # starting with "<OID> ="
43
+ )
44
+ [^\n]+ # additional lines of value
45
+ )*
46
+ )\n
47
+ /x.freeze
18
48
 
19
49
  def initialize(oids)
20
50
  @oids = oids
@@ -22,11 +52,8 @@ module SNMP
22
52
 
23
53
  def parse(texts)
24
54
  columns = texts.map do |text|
25
- tokenized =
26
- text
27
- .gsub(NOSUCHOBJECT_STR, %("#{NOSUCHOBJECT_STR}"))
28
- .gsub(NOSUCHINSTANCE_STR, %("#{NOSUCHINSTANCE_STR}"))
29
- .shellsplit
55
+ clean = clean_input_text(text)
56
+ tokenized = clean.shellsplit
30
57
  parse_tokens(tokenized)
31
58
  end
32
59
 
@@ -35,7 +62,7 @@ module SNMP
35
62
 
36
63
  private
37
64
 
38
- def table(columns)
65
+ def align(columns)
39
66
  indexes = columns.first.map { |value| index_using_first_oid(value) }
40
67
  hash = columns.flat_map { |row| row.map { |v| [v.oid, v] } }.to_h
41
68
 
@@ -47,6 +74,14 @@ module SNMP
47
74
  end
48
75
  end
49
76
 
77
+ def clean_input_text(text)
78
+ text
79
+ .gsub(/\r\n|\n\r|\r/, "\n")
80
+ .gsub(EMPTY_STRING_RE, %(\\1 = \\2: ""\n))
81
+ .gsub(STRING_RE, %(\\1 = \\2: "\\3"\n))
82
+ .gsub(Static::ANY_MESSAGE, Static::QUOTED_MESSAGES)
83
+ end
84
+
50
85
  def index_using_first_oid(value)
51
86
  base = @oids.first
52
87
 
@@ -69,34 +104,31 @@ module SNMP
69
104
 
70
105
  objects
71
106
  rescue StopIteration
72
- return objects
107
+ objects
73
108
  end
74
109
 
75
110
  def parse_next_object(tokens)
76
111
  oid = tokens.next.sub(/\A\./, '')
77
- raise "Parse error at #{oid}" unless oid =~ /\A[0-9.]+\z/
112
+ raise "Parse error at #{oid}" unless oid =~ OID_RE
113
+
78
114
  equals = tokens.next
79
115
  raise "Parse error after #{oid}" unless equals == '='
116
+
80
117
  type, value = parse_type(tokens)
81
118
  Value.new(oid, type, value)
82
119
  end
83
120
 
84
121
  def parse_type(tokens)
85
- next_token = tokens.next
86
- type = next_token.match(/\A([A-Z]+):\z/) { |md| md[1] }
87
- type, value = parse_value(tokens, next_token, type)
88
- [type, Conversions.convert_value(type, value)]
122
+ token = tokens.next
123
+ type = token.match(/\A([-A-Za-z]+[0-9]*):\z/) { |md| md[1] }
124
+ ValueParser.find(type, token).parse(tokens)
89
125
  end
90
126
 
91
- def parse_value(tokens, token, type)
92
- if token == NOSUCHOBJECT_STR
93
- ['No Such Object', nil]
94
- elsif token == NOSUCHINSTANCE_STR
95
- ['No Such Instance', nil]
96
- elsif !type
97
- ['STRING', token]
127
+ def table(columns)
128
+ if columns.size == 1 && columns.all? { |column| column.size == 1 }
129
+ columns
98
130
  else
99
- [type, tokens.next]
131
+ align(columns)
100
132
  end
101
133
  end
102
134
 
@@ -116,25 +148,24 @@ module SNMP
116
148
  @oids.zip(columns).map do |oid, column|
117
149
  indexes.map do |index|
118
150
  id = (oid == index ? index : "#{oid}.#{index}")
119
- column.find { |o| o.oid == id } || Conversions.absent_value(id)
151
+ column.find { |o| o.oid == id } || Value.new(id, 'absent', nil)
120
152
  end
121
153
  end
122
154
  end
123
155
 
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
133
- end
156
+ # static messages from net-snmp commands
157
+ module Static
158
+ include SNMP::Open::Parser::Constants
134
159
 
135
- module_function def absent_value(id)
136
- Value.new(id, 'absent', nil)
137
- end
160
+ MESSAGES = [
161
+ NOSUCHOBJECT_STR,
162
+ NOSUCHINSTANCE_STR,
163
+ NOMOREVARIABLES_STR
164
+ ].freeze
165
+
166
+ ANY_MESSAGE = Regexp.union(*MESSAGES)
167
+
168
+ QUOTED_MESSAGES = MESSAGES.map { |v| [v, %("#{v}")] }.to_h.freeze
138
169
  end
139
170
  end # class Parser
140
171
  end # class Open
@@ -0,0 +1,15 @@
1
+ module SNMP
2
+ class Open
3
+ class Parser
4
+ module Constants
5
+ NOSUCHOBJECT_STR =
6
+ 'No Such Object available on this agent at this OID'.freeze
7
+ NOSUCHINSTANCE_STR =
8
+ 'No Such Instance currently exists at this OID'.freeze
9
+ NOMOREVARIABLES_STR =
10
+ 'No more variables left in this MIB View '\
11
+ '(It is past the end of the MIB tree)'.freeze
12
+ end # module Constants
13
+ end # class Parser
14
+ end # class Open
15
+ end # module SNMP
@@ -0,0 +1,132 @@
1
+ module SNMP
2
+ class Open
3
+ class Parser
4
+ # base class for value parsers
5
+ class ValueParser
6
+ include SNMP::Open::Parser::Constants
7
+
8
+ def self.find(type, token)
9
+ cls = KNOWN_TOKENS[token] || KNOWN_TYPES[type] || Other
10
+ cls.new(type, token)
11
+ end
12
+
13
+ def initialize(type, token)
14
+ @type = type
15
+ @token = token
16
+ end
17
+
18
+ def parse(*)
19
+ @parse
20
+ end
21
+
22
+ # parses BITS
23
+ class Bits < ValueParser
24
+ def parse(tokens)
25
+ return @parse if @parse
26
+
27
+ bytes = []
28
+ loop do
29
+ break unless tokens.peek =~ /\A[0-9A-Za-z]{1,2}\z/
30
+
31
+ bytes << tokens.next.to_i(16)
32
+ end
33
+ @parse = [@type, bytes]
34
+ end
35
+ end # class Bits < ValueParser
36
+
37
+ # parses objects with no explicit type
38
+ class Default < ValueParser
39
+ def initialize(_type, token)
40
+ @parse = ['STRING', token]
41
+ end
42
+ end # class Default
43
+
44
+ # parses integer-like objects
45
+ class Integer < ValueParser
46
+ def parse(tokens)
47
+ @parse ||= [@type, Integer(tokens.next)]
48
+ end
49
+ end
50
+
51
+ # parses objects identified like '= Hex-STRING:'
52
+ class HexString < ValueParser
53
+ def parse(tokens)
54
+ return @parse if @parse
55
+
56
+ bytes = []
57
+ loop do
58
+ break unless tokens.peek =~ /\A[0-9A-Za-z]{2}\z/
59
+
60
+ bytes << tokens.next
61
+ end
62
+ string = bytes.map { |b| b.to_i(16).chr }.join
63
+ @parse = [@type, string]
64
+ end
65
+ end # class HexString
66
+
67
+ # handles messages indicating the end of the response
68
+ class Stop < ValueParser
69
+ def parse(*)
70
+ raise StopIteration, @token
71
+ end
72
+ end
73
+
74
+ # parses objects identified like '= Timeticks:'
75
+ # note that 1 second = 100 ticks
76
+ class Timeticks < ValueParser
77
+ def parse(tokens)
78
+ return @parse if @parse
79
+
80
+ ticks = tokens.next.tr('()', '').to_i
81
+
82
+ # consume tokens through one like 23:59:59.99
83
+ loop do
84
+ break if tokens.next =~ /\A\d\d:\d\d:\d\d.\d\d\z/
85
+ end
86
+
87
+ @parse = [@type, ticks]
88
+ end
89
+ end # class Timeticks
90
+
91
+ # handles objects not handled by any other parser
92
+ class Other < ValueParser
93
+ def parse(tokens)
94
+ @parse ||= [@type, tokens.next]
95
+ end
96
+ end # class Other
97
+
98
+ # handles NoSuchInstance
99
+ class NoSuchInstance < ValueParser
100
+ def initialize(*)
101
+ @parse = ['No Such Instance', nil]
102
+ end
103
+ end # class NoSuchInstance < ValueParser
104
+
105
+ # handles NoSuchObject
106
+ class NoSuchObject < ValueParser
107
+ def initialize(*)
108
+ @parse = ['No Such Object', nil]
109
+ end
110
+ end # class NoSuchObject < ValueParser
111
+
112
+ KNOWN_TOKENS = {
113
+ NOSUCHINSTANCE_STR => NoSuchInstance,
114
+ NOSUCHOBJECT_STR => NoSuchObject,
115
+ NOMOREVARIABLES_STR => Stop
116
+ }.freeze
117
+
118
+ KNOWN_TYPES = {
119
+ nil => Default,
120
+ 'BITS' => Bits,
121
+ 'INTEGER' => ValueParser::Integer,
122
+ 'Gauge32' => ValueParser::Integer,
123
+ 'Gauge64' => ValueParser::Integer,
124
+ 'Counter32' => ValueParser::Integer,
125
+ 'Counter64' => ValueParser::Integer,
126
+ 'Hex-STRING' => HexString,
127
+ 'Timeticks' => Timeticks
128
+ }.freeze
129
+ end # class ValueParser
130
+ end # class Parser
131
+ end # class Open
132
+ end # module SNMP
@@ -1,5 +1,5 @@
1
- module Snmp
2
- module Open
3
- VERSION = '0.3.0'.freeze
1
+ module SNMP
2
+ class Open
3
+ VERSION = '0.6.1'.freeze
4
4
  end
5
5
  end
@@ -1,10 +1,10 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require 'snmp/open/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'snmp-open'
7
- spec.version = Snmp::Open::VERSION
7
+ spec.version = SNMP::Open::VERSION
8
8
  spec.authors = ['Ben Miller']
9
9
  spec.email = ['bmiller@rackspace.com']
10
10
 
@@ -18,8 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency 'bundler', '~> 1.11'
22
- spec.add_development_dependency 'rake', '~> 10.0'
21
+ spec.required_ruby_version = '~> 2.4'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 2.2'
24
+ spec.add_development_dependency 'rake', '~> 13.0'
23
25
  spec.add_development_dependency 'rspec', '~> 3.0'
24
26
  spec.add_development_dependency 'snmp'
25
27
  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.3.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Miller
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-05 00:00:00.000000000 Z
11
+ date: 2021-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.11'
19
+ version: '2.2'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.11'
26
+ version: '2.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,16 +66,17 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- description:
69
+ description:
70
70
  email:
71
71
  - bmiller@rackspace.com
72
72
  executables: []
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
+ - ".github/workflows/ruby.yml"
76
77
  - ".gitignore"
77
78
  - ".rspec"
78
- - ".travis.yml"
79
+ - ".rubocop.yml"
79
80
  - CODE_OF_CONDUCT.md
80
81
  - Gemfile
81
82
  - Guardfile
@@ -89,30 +90,32 @@ files:
89
90
  - lib/snmp/open.rb
90
91
  - lib/snmp/open/command_reader.rb
91
92
  - lib/snmp/open/file_reader.rb
93
+ - lib/snmp/open/options.rb
92
94
  - lib/snmp/open/parser.rb
95
+ - lib/snmp/open/parser/constants.rb
96
+ - lib/snmp/open/parser/value_parser.rb
93
97
  - lib/snmp/open/version.rb
94
98
  - snmp-open.gemspec
95
99
  homepage: https://github.com/bjmllr/snmp-open
96
100
  licenses: []
97
101
  metadata: {}
98
- post_install_message:
102
+ post_install_message:
99
103
  rdoc_options: []
100
104
  require_paths:
101
105
  - lib
102
106
  required_ruby_version: !ruby/object:Gem::Requirement
103
107
  requirements:
104
- - - ">="
108
+ - - "~>"
105
109
  - !ruby/object:Gem::Version
106
- version: '0'
110
+ version: '2.4'
107
111
  required_rubygems_version: !ruby/object:Gem::Requirement
108
112
  requirements:
109
113
  - - ">="
110
114
  - !ruby/object:Gem::Version
111
115
  version: '0'
112
116
  requirements: []
113
- rubyforge_project:
114
- rubygems_version: 2.6.11
115
- signing_key:
117
+ rubygems_version: 3.1.2
118
+ signing_key:
116
119
  specification_version: 4
117
120
  summary: Wrapper for command-line SNMP utilities
118
121
  test_files: []
@@ -1,7 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.4.1
5
- - 2.3.4
6
- - 2.2.7
7
- before_install: gem install bundler -v 1.13.6