snmp-open 0.5.0 → 0.7.0

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
- SHA1:
3
- metadata.gz: 67cb5790febed285507e8f2872aa8dbb3f025a02
4
- data.tar.gz: d1504724d8f8572a03624bca255d10757636d40f
2
+ SHA256:
3
+ metadata.gz: b13230f5561531372236208bfe42c5a0d44ef032d8075316fd02bf78ec7e78b3
4
+ data.tar.gz: 2fc93d9967c5fc37918b7f371147e14f9942d356699a02e4ce46b06763bfceb0
5
5
  SHA512:
6
- metadata.gz: fff2fcd5e4c3a42d921112c4d0f36e96914b037aee168c73b2981796375597e82e7564352030cd0860043c40f24e61a7e44cd8fe3ae7b7f481b7c60e4d973631
7
- data.tar.gz: 240aebb9fd9938b76a1d0bc37e56c77d70eb8cd5958a73f952b1766df793c8baabf43a437b0a0207c0c391ea5648018c7948c9ad92572f6b2cabb5555fb67492
6
+ metadata.gz: b3678f4b2e04b9f5a3a45edd3273d8ecfecb8a7a2bc4d92568b9644c6192e8e5fbeb8b902f0bf53d5c42b184f1402359a6daf8ea9f9923c1331b22b914fc0a54
7
+ data.tar.gz: 19a0f2e47cb585f3a1aaab331c3a97bbec05d3e57ce8ec76e17f5c1dc48f96a5b68cbb0b9d8b7b648490cbfbeed0dd1f2810381574286bd5135bddc9eac2d5bc
@@ -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
data/.rubocop.yml ADDED
@@ -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
@@ -30,8 +30,7 @@ module SNMP
30
30
  else
31
31
  Open3.capture3(cli(cmd, oid, options))
32
32
  end
33
- raise CommandTimeoutError, err.chomp if err =~ /^timeout/i
34
- raise CommandError, err.chomp unless err.empty?
33
+ raise_capture_errors(err)
35
34
  out
36
35
  end
37
36
 
@@ -42,6 +41,7 @@ module SNMP
42
41
  [
43
42
  command,
44
43
  *options.map { |k, v| "#{k}#{v}" },
44
+ *oid_options(id),
45
45
  *@host_options.map { |k, v| "#{k}#{v}" },
46
46
  *@command_options.fetch(command, {}).map { |k, v| "#{k}#{v}" },
47
47
  *id
@@ -50,6 +50,19 @@ module SNMP
50
50
 
51
51
  private
52
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
+
53
66
  def merge_options(options = {})
54
67
  options.each_pair.with_object({}) do |(key, value), opts|
55
68
  if Options::MAP.key?(key)
@@ -63,6 +76,15 @@ module SNMP
63
76
  end
64
77
  end
65
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
+
66
88
  def normalize_command(command)
67
89
  case command
68
90
  when Symbol then "snmp#{command}"
@@ -99,6 +121,11 @@ module SNMP
99
121
  end # class CommandReader
100
122
 
101
123
  class CommandError < RuntimeError; end
124
+
102
125
  class CommandTimeoutError < CommandError; end
126
+
127
+ class UnknownMIBError < CommandError; end
128
+
129
+ class UnknownOIDError < CommandError; end
103
130
  end # class Open
104
131
  end # module SNMP
@@ -32,12 +32,12 @@ module SNMP
32
32
  mkdir(@directory, cmd.to_s) if @make_directories
33
33
  outfile = File.join(@directory, cmd.to_s, oid)
34
34
  File.read(outfile)
35
- rescue Errno::ENOENT => err
35
+ rescue Errno::ENOENT => e
36
36
  if @warnings
37
37
  warning = @warnings.call(@command_generator, cmd, oid, outfile)
38
38
  warn warning
39
39
  end
40
- raise err
40
+ raise e
41
41
  end
42
42
 
43
43
  def mkdir(base, cmd)
@@ -12,8 +12,10 @@ module SNMP
12
12
  'snmpbulkwalk' => '-Cc',
13
13
  'snmpwalk' => '-Cc'
14
14
  },
15
+ no_mib_name: '-Os',
15
16
  no_units: '-OU',
16
17
  non_symbolic: '-Oe',
18
+ non_symbolic_table_indexes: '-Ob',
17
19
  numeric: '-On',
18
20
  priv_password: '-X', # not recommended, see snmp.conf(5)
19
21
  priv_protocol: '-x',
@@ -24,12 +26,12 @@ module SNMP
24
26
  host: nil
25
27
  }.freeze
26
28
 
27
- # On some systems, SNMP command outputs will include symbolic OID names,
28
- # symbolic values, and/or value units. The parser doesn't support these,
29
- # so disable them.
29
+ # On some systems, SNMP command outputs will include symbolic values,
30
+ # table indexes, and/or value units. The parser doesn't support these, so
31
+ # disable them.
30
32
  REQUIRED_BY_PARSER = {
33
+ '-Ob' => nil,
31
34
  '-Oe' => nil,
32
- '-On' => nil,
33
35
  '-OU' => nil
34
36
  }.freeze
35
37
 
@@ -23,9 +23,11 @@ module SNMP
23
23
  class Bits < ValueParser
24
24
  def parse(tokens)
25
25
  return @parse if @parse
26
+
26
27
  bytes = []
27
28
  loop do
28
29
  break unless tokens.peek =~ /\A[0-9A-Za-z]{1,2}\z/
30
+
29
31
  bytes << tokens.next.to_i(16)
30
32
  end
31
33
  @parse = [@type, bytes]
@@ -50,9 +52,11 @@ module SNMP
50
52
  class HexString < ValueParser
51
53
  def parse(tokens)
52
54
  return @parse if @parse
55
+
53
56
  bytes = []
54
57
  loop do
55
58
  break unless tokens.peek =~ /\A[0-9A-Za-z]{2}\z/
59
+
56
60
  bytes << tokens.next
57
61
  end
58
62
  string = bytes.map { |b| b.to_i(16).chr }.join
@@ -72,6 +76,7 @@ module SNMP
72
76
  class Timeticks < ValueParser
73
77
  def parse(tokens)
74
78
  return @parse if @parse
79
+
75
80
  ticks = tokens.next.tr('()', '').to_i
76
81
 
77
82
  # consume tokens through one like 23:59:59.99
@@ -106,16 +111,16 @@ module SNMP
106
111
 
107
112
  KNOWN_TOKENS = {
108
113
  NOSUCHINSTANCE_STR => NoSuchInstance,
109
- NOSUCHOBJECT_STR => NoSuchObject,
114
+ NOSUCHOBJECT_STR => NoSuchObject,
110
115
  NOMOREVARIABLES_STR => Stop
111
116
  }.freeze
112
117
 
113
118
  KNOWN_TYPES = {
114
119
  nil => Default,
115
120
  'BITS' => Bits,
116
- 'INTEGER' => ValueParser::Integer,
117
- 'Gauge32' => ValueParser::Integer,
118
- 'Gauge64' => ValueParser::Integer,
121
+ 'INTEGER' => ValueParser::Integer,
122
+ 'Gauge32' => ValueParser::Integer,
123
+ 'Gauge64' => ValueParser::Integer,
119
124
  'Counter32' => ValueParser::Integer,
120
125
  'Counter64' => ValueParser::Integer,
121
126
  'Hex-STRING' => HexString,
@@ -14,6 +14,37 @@ module SNMP
14
14
  # convert SNMP command output into arrays
15
15
  class Parser
16
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
17
48
 
18
49
  def initialize(oids)
19
50
  @oids = oids
@@ -21,12 +52,8 @@ module SNMP
21
52
 
22
53
  def parse(texts)
23
54
  columns = texts.map do |text|
24
- tokenized =
25
- text
26
- .gsub(/^([0-9\.]+) = (Opaque|STRING): ((?!")[^\n]*)\n/,
27
- %(\\1 = \\2: "\\3"\n))
28
- .gsub(Static::ANY_MESSAGE, Static::QUOTED_MESSAGES)
29
- .shellsplit
55
+ clean = clean_input_text(text)
56
+ tokenized = clean.shellsplit
30
57
  parse_tokens(tokenized)
31
58
  end
32
59
 
@@ -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,14 +104,16 @@ 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
@@ -1,5 +1,5 @@
1
1
  module SNMP
2
2
  class Open
3
- VERSION = '0.5.0'.freeze
3
+ VERSION = '0.7.0'.freeze
4
4
  end
5
5
  end
data/lib/snmp/open.rb CHANGED
@@ -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
data/snmp-open.gemspec CHANGED
@@ -1,4 +1,4 @@
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
 
@@ -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.5.0
4
+ version: 0.7.0
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: 2018-02-14 00:00:00.000000000 Z
11
+ date: 2022-03-15 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
@@ -98,24 +99,24 @@ files:
98
99
  homepage: https://github.com/bjmllr/snmp-open
99
100
  licenses: []
100
101
  metadata: {}
101
- post_install_message:
102
+ post_install_message:
102
103
  rdoc_options: []
103
104
  require_paths:
104
105
  - lib
105
106
  required_ruby_version: !ruby/object:Gem::Requirement
106
107
  requirements:
107
- - - ">="
108
+ - - "~>"
108
109
  - !ruby/object:Gem::Version
109
- version: '0'
110
+ version: '2.4'
110
111
  required_rubygems_version: !ruby/object:Gem::Requirement
111
112
  requirements:
112
113
  - - ">="
113
114
  - !ruby/object:Gem::Version
114
115
  version: '0'
115
116
  requirements: []
116
- rubyforge_project:
117
- rubygems_version: 2.5.2.2
118
- signing_key:
117
+ rubyforge_project:
118
+ rubygems_version: 2.7.6.2
119
+ signing_key:
119
120
  specification_version: 4
120
121
  summary: Wrapper for command-line SNMP utilities
121
122
  test_files: []
data/.travis.yml DELETED
@@ -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