snmp-open 0.3.1 → 0.4.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 +4 -4
- data/lib/snmp/open/command_reader.rb +8 -32
- data/lib/snmp/open/options.rb +43 -0
- data/lib/snmp/open/parser.rb +22 -36
- data/lib/snmp/open/parser/constants.rb +15 -0
- data/lib/snmp/open/parser/value_parser.rb +127 -0
- data/lib/snmp/open/version.rb +2 -2
- data/snmp-open.gemspec +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed0ba9db497fbb007a69e702a2ed6321cfde3583
|
4
|
+
data.tar.gz: 9cbd977f12ae09f800fc0b27aa29fbad04bd0cd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74fb9d39823597e02d95f2029e14391d16851e29f0b20006ab595550e56207dc2f20a1bb3404aa118d25cf9e0a8016542c60be327bf43e45683bad890571aa7a
|
7
|
+
data.tar.gz: 6b29974a7a28fa197acb75647674f036f7ef5fad733de2f0ae7a5c780005717e17d8cb87fb4855f398768665ccf987432906d6ed6131f69546798725ac98f6f0
|
@@ -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 +
|
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 =
|
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
|
|
@@ -76,9 +52,9 @@ module SNMP
|
|
76
52
|
|
77
53
|
def merge_options(options = {})
|
78
54
|
options.each_pair.with_object({}) do |(key, value), opts|
|
79
|
-
if
|
80
|
-
opts[
|
81
|
-
(
|
55
|
+
if Options::MAP.key?(key)
|
56
|
+
opts[Options::MAP[key]] =
|
57
|
+
(Options::VALUES.fetch(key, {}).fetch(value, value) || next)
|
82
58
|
elsif key.is_a?(String)
|
83
59
|
opts[key] = value
|
84
60
|
else
|
@@ -0,0 +1,43 @@
|
|
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 OID names,
|
28
|
+
# symbolic values, and/or value units. The parser doesn't support these,
|
29
|
+
# so disable them.
|
30
|
+
REQUIRED_BY_PARSER = {
|
31
|
+
'-Oe' => nil,
|
32
|
+
'-On' => nil,
|
33
|
+
'-OU' => nil
|
34
|
+
}.freeze
|
35
|
+
|
36
|
+
VALUES = {
|
37
|
+
no_check_increasing: {
|
38
|
+
true => ''
|
39
|
+
}.freeze
|
40
|
+
}.freeze
|
41
|
+
end # class Options
|
42
|
+
end # class Open
|
43
|
+
end # module SNMP
|
data/lib/snmp/open/parser.rb
CHANGED
@@ -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,7 @@ module SNMP
|
|
11
13
|
|
12
14
|
# convert SNMP command output into arrays
|
13
15
|
class Parser
|
14
|
-
|
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
|
18
17
|
|
19
18
|
def initialize(oids)
|
20
19
|
@oids = oids
|
@@ -24,8 +23,9 @@ module SNMP
|
|
24
23
|
columns = texts.map do |text|
|
25
24
|
tokenized =
|
26
25
|
text
|
27
|
-
.gsub(
|
28
|
-
|
26
|
+
.gsub(/^([0-9\.]+) = (Opaque|STRING): ((?!")[^\n]*)\n/,
|
27
|
+
%(\\1 = \\2: "\\3"\n))
|
28
|
+
.gsub(Static::ANY_MESSAGE, Static::QUOTED_MESSAGES)
|
29
29
|
.shellsplit
|
30
30
|
parse_tokens(tokenized)
|
31
31
|
end
|
@@ -82,22 +82,9 @@ module SNMP
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def parse_type(tokens)
|
85
|
-
|
86
|
-
type =
|
87
|
-
type,
|
88
|
-
[type, Conversions.convert_value(type, value)]
|
89
|
-
end
|
90
|
-
|
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]
|
98
|
-
else
|
99
|
-
[type, tokens.next]
|
100
|
-
end
|
85
|
+
token = tokens.next
|
86
|
+
type = token.match(/\A([-A-Za-z]+[0-9]*):\z/) { |md| md[1] }
|
87
|
+
ValueParser.find(type, token).parse(tokens)
|
101
88
|
end
|
102
89
|
|
103
90
|
def table(columns)
|
@@ -124,25 +111,24 @@ module SNMP
|
|
124
111
|
@oids.zip(columns).map do |oid, column|
|
125
112
|
indexes.map do |index|
|
126
113
|
id = (oid == index ? index : "#{oid}.#{index}")
|
127
|
-
column.find { |o| o.oid == id } ||
|
114
|
+
column.find { |o| o.oid == id } || Value.new(id, 'absent', nil)
|
128
115
|
end
|
129
116
|
end
|
130
117
|
end
|
131
118
|
|
132
|
-
#
|
133
|
-
module
|
134
|
-
|
135
|
-
case type
|
136
|
-
when 'INTEGER'
|
137
|
-
value.to_i
|
138
|
-
else
|
139
|
-
value
|
140
|
-
end
|
141
|
-
end
|
119
|
+
# static messages from net-snmp commands
|
120
|
+
module Static
|
121
|
+
include SNMP::Open::Parser::Constants
|
142
122
|
|
143
|
-
|
144
|
-
|
145
|
-
|
123
|
+
MESSAGES = [
|
124
|
+
NOSUCHOBJECT_STR,
|
125
|
+
NOSUCHINSTANCE_STR,
|
126
|
+
NOMOREVARIABLES_STR
|
127
|
+
].freeze
|
128
|
+
|
129
|
+
ANY_MESSAGE = Regexp.union(*MESSAGES)
|
130
|
+
|
131
|
+
QUOTED_MESSAGES = MESSAGES.map { |v| [v, %("#{v}")] }.to_h.freeze
|
146
132
|
end
|
147
133
|
end # class Parser
|
148
134
|
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,127 @@
|
|
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
|
+
bytes = []
|
27
|
+
loop do
|
28
|
+
break unless tokens.peek =~ /\A[0-9A-Za-z]{1,2}\z/
|
29
|
+
bytes << tokens.next.to_i(16)
|
30
|
+
end
|
31
|
+
@parse = [@type, bytes]
|
32
|
+
end
|
33
|
+
end # class Bits < ValueParser
|
34
|
+
|
35
|
+
# parses objects with no explicit type
|
36
|
+
class Default < ValueParser
|
37
|
+
def initialize(_type, token)
|
38
|
+
@parse = ['STRING', token]
|
39
|
+
end
|
40
|
+
end # class Default
|
41
|
+
|
42
|
+
# parses integer-like objects
|
43
|
+
class Integer < ValueParser
|
44
|
+
def parse(tokens)
|
45
|
+
@parse ||= [@type, Integer(tokens.next)]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# parses objects identified like '= Hex-STRING:'
|
50
|
+
class HexString < ValueParser
|
51
|
+
def parse(tokens)
|
52
|
+
return @parse if @parse
|
53
|
+
bytes = []
|
54
|
+
loop do
|
55
|
+
break unless tokens.peek =~ /\A[0-9A-Za-z]{2}\z/
|
56
|
+
bytes << tokens.next
|
57
|
+
end
|
58
|
+
string = bytes.map { |b| b.to_i(16).chr }.join
|
59
|
+
@parse = [@type, string]
|
60
|
+
end
|
61
|
+
end # class HexString
|
62
|
+
|
63
|
+
# handles messages indicating the end of the response
|
64
|
+
class Stop < ValueParser
|
65
|
+
def parse(*)
|
66
|
+
raise StopIteration, @token
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# parses objects identified like '= Timeticks:'
|
71
|
+
# note that 1 second = 100 ticks
|
72
|
+
class Timeticks < ValueParser
|
73
|
+
def parse(tokens)
|
74
|
+
return @parse if @parse
|
75
|
+
ticks = tokens.next.tr('()', '').to_i
|
76
|
+
|
77
|
+
# consume tokens through one like 23:59:59.99
|
78
|
+
loop do
|
79
|
+
break if tokens.next =~ /\A\d\d:\d\d:\d\d.\d\d\z/
|
80
|
+
end
|
81
|
+
|
82
|
+
@parse = [@type, ticks]
|
83
|
+
end
|
84
|
+
end # class Timeticks
|
85
|
+
|
86
|
+
# handles objects not handled by any other parser
|
87
|
+
class Other < ValueParser
|
88
|
+
def parse(tokens)
|
89
|
+
@parse ||= [@type, tokens.next]
|
90
|
+
end
|
91
|
+
end # class Other
|
92
|
+
|
93
|
+
# handles NoSuchInstance
|
94
|
+
class NoSuchInstance < ValueParser
|
95
|
+
def initialize(*)
|
96
|
+
@parse = ['No Such Instance', nil]
|
97
|
+
end
|
98
|
+
end # class NoSuchInstance < ValueParser
|
99
|
+
|
100
|
+
# handles NoSuchObject
|
101
|
+
class NoSuchObject < ValueParser
|
102
|
+
def initialize(*)
|
103
|
+
@parse = ['No Such Object', nil]
|
104
|
+
end
|
105
|
+
end # class NoSuchObject < ValueParser
|
106
|
+
|
107
|
+
KNOWN_TOKENS = {
|
108
|
+
NOSUCHINSTANCE_STR => NoSuchInstance,
|
109
|
+
NOSUCHOBJECT_STR => NoSuchObject,
|
110
|
+
NOMOREVARIABLES_STR => Stop
|
111
|
+
}.freeze
|
112
|
+
|
113
|
+
KNOWN_TYPES = {
|
114
|
+
nil => Default,
|
115
|
+
'BITS' => Bits,
|
116
|
+
'INTEGER' => ValueParser::Integer,
|
117
|
+
'Gauge32' => ValueParser::Integer,
|
118
|
+
'Gauge64' => ValueParser::Integer,
|
119
|
+
'Counter32' => ValueParser::Integer,
|
120
|
+
'Counter64' => ValueParser::Integer,
|
121
|
+
'Hex-STRING' => HexString,
|
122
|
+
'Timeticks' => Timeticks
|
123
|
+
}.freeze
|
124
|
+
end # class ValueParser
|
125
|
+
end # class Parser
|
126
|
+
end # class Open
|
127
|
+
end # module SNMP
|
data/lib/snmp/open/version.rb
CHANGED
data/snmp-open.gemspec
CHANGED
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.
|
4
|
+
version: 0.4.0
|
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-
|
11
|
+
date: 2017-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -89,7 +89,10 @@ files:
|
|
89
89
|
- lib/snmp/open.rb
|
90
90
|
- lib/snmp/open/command_reader.rb
|
91
91
|
- lib/snmp/open/file_reader.rb
|
92
|
+
- lib/snmp/open/options.rb
|
92
93
|
- lib/snmp/open/parser.rb
|
94
|
+
- lib/snmp/open/parser/constants.rb
|
95
|
+
- lib/snmp/open/parser/value_parser.rb
|
93
96
|
- lib/snmp/open/version.rb
|
94
97
|
- snmp-open.gemspec
|
95
98
|
homepage: https://github.com/bjmllr/snmp-open
|