snmp-open 0.5.0 → 0.7.0

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: 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