snmp-open 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|