snmp-open 0.1.3 → 0.1.4
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/bin/console +1 -1
- data/bin/get +8 -0
- data/bin/walk +8 -0
- data/lib/snmp/open.rb +17 -70
- data/lib/snmp/open/command_reader.rb +75 -0
- data/lib/snmp/open/file_reader.rb +8 -26
- data/lib/snmp/open/parser.rb +22 -12
- data/lib/snmp/open/version.rb +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: 9ae08ac661e97b5c47899d166a7bdcd6b71e0c55
|
4
|
+
data.tar.gz: b10aae94bb31fc05b38ec3d3ab9ce1d450c3b104
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 998d8abcd4e3e7b5967affb6441f590201c7a0c15b24ebe7f56911fa17a103086a2c6392586baa4fb9fe26083985e9de8cbc174eb2524a4303602a11757301be
|
7
|
+
data.tar.gz: ecf925444abd22e218b7235985aa5d98357f9e6e34b759ac760d3bbc5c1e83c89c46c261132663ee479124932c5b8d07e3313c88edd812cccf18aed1a179ce31
|
data/bin/console
CHANGED
data/bin/get
ADDED
data/bin/walk
ADDED
data/lib/snmp/open.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'open3'
|
2
1
|
require 'snmp/open/parser'
|
2
|
+
require 'snmp/open/command_reader'
|
3
3
|
|
4
4
|
# Simple Network Management Protocol
|
5
5
|
module SNMP
|
@@ -19,92 +19,39 @@ module SNMP
|
|
19
19
|
|
20
20
|
# Open3-based wrapper for SNMP CLI commands
|
21
21
|
class Open
|
22
|
-
attr_reader :
|
22
|
+
attr_reader :reader
|
23
23
|
|
24
|
-
# see
|
25
|
-
OPTIONS = {
|
26
|
-
version: '-v',
|
27
|
-
auth_password: '-A',
|
28
|
-
auth_protocol: '-a',
|
29
|
-
community: '-c',
|
30
|
-
context: '-n',
|
31
|
-
numeric: '-On', # needed by parser, should always be enabled
|
32
|
-
priv_password: '-X', # not recommended, see snmp.conf(5)
|
33
|
-
priv_protocol: '-x',
|
34
|
-
sec_level: '-l',
|
35
|
-
sec_user: '-u',
|
36
|
-
retries: '-r',
|
37
|
-
timeout: '-t',
|
38
|
-
host: nil
|
39
|
-
}.freeze
|
40
|
-
|
41
|
-
# +options+ accepts options dealing with making connections to the host,
|
42
|
-
# including all of the options listed in the +OPTIONS+ constant hash. Other
|
43
|
-
# options can be given as strings (or any object with a suitable +to_s+
|
44
|
-
# method), e.g., these are equivalent:
|
45
|
-
#
|
46
|
-
# SNMP::Open.new(host: hostname, timeout: 3, '-m' => miblist)
|
47
|
-
# SNMP::Open.new(hostname => nil, '-t' => '3', '-m' => miblist)
|
48
|
-
#
|
24
|
+
# see CommandReader for a description of options
|
49
25
|
def initialize(options = {})
|
50
|
-
|
51
|
-
(raise ArgumentError, 'Host expected but not given')
|
52
|
-
@host_options = merge_options(options)
|
53
|
-
.merge('-On' => nil, host => nil)
|
54
|
-
return if @host_options.key?(nil)
|
55
|
-
end
|
56
|
-
|
57
|
-
# Generate a CLI command string
|
58
|
-
def cli(command, id = nil, options = {})
|
59
|
-
command = case command
|
60
|
-
when Symbol then "snmp#{command}"
|
61
|
-
else command.to_s
|
62
|
-
end
|
63
|
-
|
64
|
-
[
|
65
|
-
command,
|
66
|
-
*options.map { |k, v| "#{k}#{v}" },
|
67
|
-
*@host_options.map { |k, v| "#{k}#{v}" },
|
68
|
-
*id
|
69
|
-
].join(' ')
|
26
|
+
@reader = options[:reader] || CommandReader.new(options)
|
70
27
|
end
|
71
28
|
|
72
29
|
# Perform an SNMP get using the "snmpget" command and parse the output
|
73
30
|
def get(oids)
|
74
31
|
return enum_for(:get, oids) unless block_given?
|
75
|
-
texts = oids.map { |oid|
|
76
|
-
Parser.new(oids).parse(texts).each { |arg
|
32
|
+
texts = oids.map { |oid| reader.capture(:get, oid) }
|
33
|
+
Parser.new(oids).parse(texts).first.each { |arg| yield(arg) }
|
77
34
|
end
|
78
35
|
|
79
36
|
# Perform an SNMP walk using the "snmpwalk" or "snmpbulkwalk" commands and
|
80
37
|
# parse the output
|
81
38
|
def walk(oids, **kwargs)
|
82
|
-
kwargs = { bulk: true, non_repeaters: 0, max_repetitions: 10 }
|
83
|
-
.merge(kwargs)
|
84
39
|
return enum_for(:walk, oids, **kwargs) unless block_given?
|
40
|
+
bulk = kwargs.fetch(:bulk, true)
|
41
|
+
options = walk_options(bulk, **kwargs)
|
85
42
|
cmd = bulk ? :bulkwalk : :walk
|
86
|
-
|
87
|
-
texts = oids.map { |oid| capture_command(cmd, oid, options) }
|
43
|
+
texts = oids.map { |oid| reader.capture(cmd, oid, options) }
|
88
44
|
Parser.new(oids).parse(texts).each { |*args| yield(*args) }
|
89
45
|
end
|
90
46
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
def merge_options(options = {})
|
100
|
-
options.each_pair.with_object({}) do |(key, value), opts|
|
101
|
-
if OPTIONS.key?(key)
|
102
|
-
opts[OPTIONS[key]] = value
|
103
|
-
elsif key.is_a?(String)
|
104
|
-
opts[key] = value
|
105
|
-
else
|
106
|
-
raise "Unknown option #{key}"
|
107
|
-
end
|
47
|
+
def walk_options(bulk, **kwargs)
|
48
|
+
if bulk
|
49
|
+
{
|
50
|
+
'-Cn' => kwargs.fetch(:non_repeaters, 0),
|
51
|
+
'-Cr' => kwargs.fetch(:max_repetitions, 10)
|
52
|
+
}
|
53
|
+
else
|
54
|
+
{}
|
108
55
|
end
|
109
56
|
end
|
110
57
|
end # class Open
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module SNMP
|
4
|
+
class Open
|
5
|
+
# Open3-based data source that executes an snmp* command and captures the
|
6
|
+
# output
|
7
|
+
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
|
+
numeric: '-On', # needed by parser, should always be enabled
|
16
|
+
priv_password: '-X', # not recommended, see snmp.conf(5)
|
17
|
+
priv_protocol: '-x',
|
18
|
+
sec_level: '-l',
|
19
|
+
sec_user: '-u',
|
20
|
+
retries: '-r',
|
21
|
+
timeout: '-t',
|
22
|
+
host: nil
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
# +options+ accepts options dealing with making connections to the host,
|
26
|
+
# including all of the options listed in the +OPTIONS+ constant hash.
|
27
|
+
# Other options can be given as strings (or any object with a suitable
|
28
|
+
# +to_s+ method), e.g., these are equivalent:
|
29
|
+
#
|
30
|
+
# SNMP::Open.new(host: hostname, timeout: 3, '-m' => miblist)
|
31
|
+
# SNMP::Open.new(hostname => nil, '-t' => '3', '-m' => miblist)
|
32
|
+
#
|
33
|
+
def initialize(options)
|
34
|
+
host = options.delete(:host) ||
|
35
|
+
(raise ArgumentError, 'Host expected but not given')
|
36
|
+
@host_options = merge_options(options).merge('-On' => nil, host => nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
def capture(cmd, oid, options = {})
|
40
|
+
out, err = Open3.capture3(cli(cmd, oid, options))
|
41
|
+
raise err unless err.empty?
|
42
|
+
out
|
43
|
+
end
|
44
|
+
|
45
|
+
# Generate a CLI command string
|
46
|
+
def cli(command, id = nil, options = {})
|
47
|
+
command = case command
|
48
|
+
when Symbol then "snmp#{command}"
|
49
|
+
else command.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
[
|
53
|
+
command,
|
54
|
+
*options.map { |k, v| "#{k}#{v}" },
|
55
|
+
*@host_options.map { |k, v| "#{k}#{v}" },
|
56
|
+
*id
|
57
|
+
].join(' ')
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def merge_options(options = {})
|
63
|
+
options.each_pair.with_object({}) do |(key, value), opts|
|
64
|
+
if OPTIONS.key?(key)
|
65
|
+
opts[OPTIONS[key]] = value
|
66
|
+
elsif key.is_a?(String)
|
67
|
+
opts[key] = value
|
68
|
+
else
|
69
|
+
raise "Unknown option #{key}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end # class CommandReader
|
74
|
+
end # class Open
|
75
|
+
end # module SNMP
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'snmp/open/
|
1
|
+
require 'snmp/open/command_reader'
|
2
2
|
|
3
3
|
module SNMP
|
4
4
|
class Open
|
5
|
-
# Test
|
5
|
+
# Test data source for SNMP::Open that reads from the filesystem instead of
|
6
6
|
# running SNMP commands. Expects a 'walk' directory to be present if #walk
|
7
7
|
# will be used, and a 'get' directory if #get will be used. Within each
|
8
8
|
# directory, files named according to the numeric OIDs to be used are
|
@@ -12,37 +12,19 @@ module SNMP
|
|
12
12
|
# Produces warnings describing an snmpbulkwalk or snmpget command that could
|
13
13
|
# be used to generate a needed file, if the file is unavailable. Controlled
|
14
14
|
# by the `warnings` option.
|
15
|
-
|
16
15
|
class FileReader
|
17
16
|
def initialize(directory, options = {})
|
18
17
|
@directory = directory
|
19
18
|
@warnings = options.delete(:warnings)
|
20
|
-
@command_generator =
|
21
|
-
|
22
|
-
|
23
|
-
def get(oids)
|
24
|
-
return enum_for(:get, oids) unless block_given?
|
25
|
-
texts = oids.map { |o| File.read(File.join(@directory, 'get', o)) }
|
26
|
-
Parser.new(oids).parse(texts).each { |arg, *| yield(arg) }
|
27
|
-
rescue Errno::ENOENT => err
|
28
|
-
if @warnings
|
29
|
-
oids.each do |oid|
|
30
|
-
warn "#{@command_generator.cli(:get, oid)} > get/#{oid}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
raise err
|
19
|
+
@command_generator =
|
20
|
+
SNMP::Open::CommandReader.new(options.merge(host: '$OPTIONS'))
|
34
21
|
end
|
35
22
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
Parser.new(oids).parse(texts).each { |*args| yield(*args) }
|
23
|
+
def capture(cmd, oid, _options = {})
|
24
|
+
outfile = File.join(cmd.to_s, oid)
|
25
|
+
File.read(File.join(@directory, outfile))
|
40
26
|
rescue Errno::ENOENT => err
|
41
|
-
if @warnings
|
42
|
-
oids.each do |oid|
|
43
|
-
warn "#{@command_generator.cli(:bulkwalk, oid)} > walk/#{oid}"
|
44
|
-
end
|
45
|
-
end
|
27
|
+
warn "#{@command_generator.cli(cmd, oid)} > #{outfile}" if @warnings
|
46
28
|
raise err
|
47
29
|
end
|
48
30
|
end # class FileReader
|
data/lib/snmp/open/parser.rb
CHANGED
@@ -13,6 +13,8 @@ module SNMP
|
|
13
13
|
class Parser
|
14
14
|
NOSUCHOBJECT_STR =
|
15
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
18
|
|
17
19
|
def initialize(oids)
|
18
20
|
@oids = oids
|
@@ -21,7 +23,10 @@ module SNMP
|
|
21
23
|
def parse(texts)
|
22
24
|
columns = texts.map do |text|
|
23
25
|
tokenized =
|
24
|
-
text
|
26
|
+
text
|
27
|
+
.gsub(NOSUCHOBJECT_STR, %("#{NOSUCHOBJECT_STR}"))
|
28
|
+
.gsub(NOSUCHINSTANCE_STR, %("#{NOSUCHINSTANCE_STR}"))
|
29
|
+
.shellsplit
|
25
30
|
parse_tokens(tokenized)
|
26
31
|
end
|
27
32
|
|
@@ -80,12 +85,14 @@ module SNMP
|
|
80
85
|
next_token = tokens.next
|
81
86
|
type = next_token.match(/\A([A-Z]+):\z/) { |md| md[1] }
|
82
87
|
type, value = parse_value(tokens, next_token, type)
|
83
|
-
[type, convert_value(type, value)]
|
88
|
+
[type, Conversions.convert_value(type, value)]
|
84
89
|
end
|
85
90
|
|
86
91
|
def parse_value(tokens, token, type)
|
87
92
|
if token == NOSUCHOBJECT_STR
|
88
93
|
['No Such Object', nil]
|
94
|
+
elsif token == NOSUCHINSTANCE_STR
|
95
|
+
['No Such Instance', nil]
|
89
96
|
elsif !type
|
90
97
|
['STRING', token]
|
91
98
|
else
|
@@ -109,22 +116,25 @@ module SNMP
|
|
109
116
|
@oids.zip(columns).map do |oid, column|
|
110
117
|
indexes.map do |index|
|
111
118
|
id = (oid == index ? index : "#{oid}.#{index}")
|
112
|
-
column.find { |o| o.oid == id } || absent_value(id)
|
119
|
+
column.find { |o| o.oid == id } || Conversions.absent_value(id)
|
113
120
|
end
|
114
121
|
end
|
115
122
|
end
|
116
123
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
123
133
|
end
|
124
|
-
end
|
125
134
|
|
126
|
-
|
127
|
-
|
135
|
+
module_function def absent_value(id)
|
136
|
+
Value.new(id, 'absent', nil)
|
137
|
+
end
|
128
138
|
end
|
129
139
|
end # class Parser
|
130
140
|
end # class Open
|
data/lib/snmp/open/version.rb
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.1.
|
4
|
+
version: 0.1.4
|
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-03-
|
11
|
+
date: 2017-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -83,8 +83,11 @@ files:
|
|
83
83
|
- README.md
|
84
84
|
- Rakefile
|
85
85
|
- bin/console
|
86
|
+
- bin/get
|
86
87
|
- bin/setup
|
88
|
+
- bin/walk
|
87
89
|
- lib/snmp/open.rb
|
90
|
+
- lib/snmp/open/command_reader.rb
|
88
91
|
- lib/snmp/open/file_reader.rb
|
89
92
|
- lib/snmp/open/parser.rb
|
90
93
|
- lib/snmp/open/version.rb
|