oxidized 0.26.3 → 0.27.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +20 -4
- data/CHANGELOG.md +48 -4
- data/Dockerfile +6 -4
- data/README.md +2 -2
- data/Rakefile +4 -4
- data/bin/oxidized +2 -0
- data/docs/Configuration.md +40 -0
- data/docs/Creating-Models.md +39 -1
- data/docs/Model-Notes/JunOS.md +7 -7
- data/docs/Model-Notes/LinuxGeneric.md +23 -0
- data/docs/Model-Notes/Netgear.md +12 -1
- data/docs/Model-Notes/README.md +2 -0
- data/docs/Model-Notes/ios.md +29 -0
- data/docs/Supported-OS-Types.md +19 -3
- data/docs/Troubleshooting.md +66 -0
- data/extra/nagios_check_failing_nodes.rb +9 -2
- data/extra/oxidized.service +2 -0
- data/extra/syslog.rb +28 -23
- data/lib/oxidized/cli.rb +10 -6
- data/lib/oxidized/config/vars.rb +8 -9
- data/lib/oxidized/hook/githubrepo.rb +1 -1
- data/lib/oxidized/input/exec.rb +28 -0
- data/lib/oxidized/input/telnet.rb +1 -1
- data/lib/oxidized/model/adtran.rb +4 -0
- data/lib/oxidized/model/airfiber.rb +22 -0
- data/lib/oxidized/model/aos.rb +8 -0
- data/lib/oxidized/model/aosw.rb +1 -1
- data/lib/oxidized/model/c4cmts.rb +1 -1
- data/lib/oxidized/model/cambium.rb +1 -0
- data/lib/oxidized/model/ciscosmb.rb +0 -5
- data/lib/oxidized/model/comware.rb +17 -8
- data/lib/oxidized/model/dlink.rb +1 -1
- data/lib/oxidized/model/fastiron.rb +66 -0
- data/lib/oxidized/model/firelinuxos.rb +41 -0
- data/lib/oxidized/model/fortios.rb +5 -0
- data/lib/oxidized/model/hpmsm.rb +84 -0
- data/lib/oxidized/model/icotera.rb +27 -0
- data/lib/oxidized/model/ios.rb +4 -0
- data/lib/oxidized/model/ironware.rb +1 -0
- data/lib/oxidized/model/junos.rb +2 -2
- data/lib/oxidized/model/linuxgeneric.rb +74 -0
- data/lib/oxidized/model/model.rb +23 -13
- data/lib/oxidized/model/netgear.rb +16 -1
- data/lib/oxidized/model/oneos.rb +8 -0
- data/lib/oxidized/model/procurve.rb +8 -6
- data/lib/oxidized/model/purityos.rb +12 -0
- data/lib/oxidized/model/routeros.rb +13 -3
- data/lib/oxidized/model/screenos.rb +2 -3
- data/lib/oxidized/model/sonicos.rb +46 -0
- data/lib/oxidized/model/speedtouch.rb +34 -0
- data/lib/oxidized/model/sros.rb +11 -32
- data/lib/oxidized/model/voss.rb +5 -2
- data/lib/oxidized/model/zynosgs.rb +38 -0
- data/lib/oxidized/node.rb +14 -14
- data/lib/oxidized/version.rb +2 -2
- data/oxidized.gemspec +6 -4
- metadata +52 -17
- data/lib/oxidized/model/netgearxs716.rb +0 -23
@@ -0,0 +1,66 @@
|
|
1
|
+
# Troubleshooting
|
2
|
+
|
3
|
+
## Oxidized connects to a supported device but no (or partial) configuration is collected
|
4
|
+
|
5
|
+
A common reason for configuration collection to fail after successful authentication is prompt mismatches. The symptoms typically fall into one of two categories:
|
6
|
+
|
7
|
+
* Oxidized successfully logs into the device, then reports a timeout without collecting configuration. This can be caused by an unmatched prompt.
|
8
|
+
* Only partial output is collected and collection stops abruptly. This can be caused by overly greedy prompt being matched against non-prompt output.
|
9
|
+
|
10
|
+
*Troubleshooting an unmatched prompt:*
|
11
|
+
|
12
|
+
Log in manually into the device. Use the same username and password or key configured for Oxidized. Observe the prompt returned by the device.
|
13
|
+
|
14
|
+
```text
|
15
|
+
Logging into this device is dangerous! Do so at your own risk.
|
16
|
+
|
17
|
+
Username: superuser
|
18
|
+
Password: *********
|
19
|
+
|
20
|
+
Welcome to the advanced nuclear launchinator 5A-X20. Proceed with caution.
|
21
|
+
|
22
|
+
SEKRET-5A-X20#
|
23
|
+
```
|
24
|
+
|
25
|
+
Review the relevant device model file and identify the defined prompt. You can find the device models in the `lib/oxidized/model` sub-folder of the repository. For example, the Cisco IOS model, `ios.rb` may use the following prompt:
|
26
|
+
|
27
|
+
```text
|
28
|
+
prompt /^([\w.@()-]+[#>]\s?)$/
|
29
|
+
```
|
30
|
+
|
31
|
+
Use IRB to verify if the prompt you've observed would match:
|
32
|
+
|
33
|
+
An example of a successful match:
|
34
|
+
|
35
|
+
```shell
|
36
|
+
# irb
|
37
|
+
irb(main):001:0> 'SEKRET-5A-X20#'.match /^([\w.@()-]+[#>]\s?)$/
|
38
|
+
=> #<MatchData "SEKRET-5A-X20#" 1:"SEKRET-5A-X20#">
|
39
|
+
irb(main):002:0>
|
40
|
+
```
|
41
|
+
|
42
|
+
An example of an unsuccessful match, for the prompt `$EKRET-5A-X20#` ($ used instead of capital S at the beginning of the prompt):
|
43
|
+
|
44
|
+
```shell
|
45
|
+
irb(main):002:0> '$EKRET-5A-X20#'.match /^([\w.@()-]+[#>]\s?)$/
|
46
|
+
=> nil
|
47
|
+
```
|
48
|
+
|
49
|
+
The prompt can then be adapted and re-tested, for example, by allowing the $ character as part of the prompt via `/^([\$\w.@()-]+[#>]\s?)$/`
|
50
|
+
|
51
|
+
```shell
|
52
|
+
irb(main):003:0> '$EKRET-5A-X20#'.match /^([\$\w.@()-]+[#>]\s?)$/
|
53
|
+
=> #<MatchData "$EKRET-5A-X20#" 1:"$EKRET-5A-X20#">
|
54
|
+
```
|
55
|
+
|
56
|
+
The new prompt now matches. You can copy the current model into the `~/.config/oxidized/` directory (keeping the original file name), and modify the prompt within the model file. After restarting Oxidized, the adapted model will be used.
|
57
|
+
|
58
|
+
*Troubleshooting an overly greedy prompt:*
|
59
|
+
|
60
|
+
Log in manually into the device. Use the same username and password or key configured for Oxidized. Execute the last command (which may be the first command to run) from which partial output is collected.
|
61
|
+
|
62
|
+
Compare the output to the partial output collected by Oxidized, focusing on the the difference that has been truncated. You can evaluate if this output could have matched the prompt regexp unexpectedly with IRB in a manner similar to the outlined in the previous section.
|
63
|
+
|
64
|
+
Adapt the prompt regexp to be more conservative if necessary in a local model override file.
|
65
|
+
|
66
|
+
*We encourage you to submit a PR for any prompt issues you encounter.*
|
@@ -10,8 +10,11 @@ pending = false
|
|
10
10
|
critical_nodes = []
|
11
11
|
pending_nodes = []
|
12
12
|
|
13
|
-
json = JSON.parse(open("http://localhost:8888/nodes.json"))
|
13
|
+
json = JSON.parse(open("http://localhost:8888/nodes.json").read)
|
14
14
|
json.each do |node|
|
15
|
+
unless ARGV.empty?
|
16
|
+
next if ARGV[0] != node['name']
|
17
|
+
end
|
15
18
|
if not node['last'].nil?
|
16
19
|
if node['last']['status'] != 'success'
|
17
20
|
critical_nodes << node['name']
|
@@ -30,6 +33,10 @@ elsif pending
|
|
30
33
|
puts '[WARN] Pending backup: ' + pending_nodes.join(',')
|
31
34
|
exit 1
|
32
35
|
else
|
33
|
-
|
36
|
+
if ARGV.empty?
|
37
|
+
puts '[OK] Backup of all nodes completed successfully.'
|
38
|
+
else
|
39
|
+
puts '[OK] Backup of node ' + ARGV[0] + ' completed successfully.'
|
40
|
+
end
|
34
41
|
exit 0
|
35
42
|
end
|
data/extra/oxidized.service
CHANGED
data/extra/syslog.rb
CHANGED
@@ -36,6 +36,10 @@ module Oxidized
|
|
36
36
|
CFGS.default.syslogd.port = 514
|
37
37
|
CFGS.default.syslogd.file = 'messages'
|
38
38
|
CFGS.default.syslogd.resolve = true
|
39
|
+
CFGS.default.syslogd.dns_map = {
|
40
|
+
'(.*)\.strip\.this\.domain\.com' => '\\1',
|
41
|
+
'(.*)\.also\.this\.net' => '\\1'
|
42
|
+
}
|
39
43
|
|
40
44
|
begin
|
41
45
|
CFGS.load
|
@@ -46,15 +50,12 @@ module Oxidized
|
|
46
50
|
end
|
47
51
|
|
48
52
|
class SyslogMonitor
|
49
|
-
NAME_MAP = {
|
50
|
-
/(.*)\.ip\.tdc\.net/ => '\1',
|
51
|
-
/(.*)\.ip\.fi/ => '\1'
|
52
|
-
}.freeze
|
53
53
|
MSG = {
|
54
54
|
ios: /%SYS-(SW[0-9]+-)?5-CONFIG_I:/,
|
55
55
|
junos: 'UI_COMMIT:',
|
56
56
|
eos: /%SYS-5-CONFIG_I:/,
|
57
|
-
nxos: /%VSHD-5-VSHD_SYSLOG_CONFIG_I
|
57
|
+
nxos: /%VSHD-5-VSHD_SYSLOG_CONFIG_I:/,
|
58
|
+
aruba: 'Notice-Type=\'Running'
|
58
59
|
}.freeze
|
59
60
|
|
60
61
|
class << self
|
@@ -82,30 +83,34 @@ module Oxidized
|
|
82
83
|
Oxidized::RestClient.next opt
|
83
84
|
end
|
84
85
|
|
85
|
-
def ios(
|
86
|
+
def ios(log, index, **opts)
|
86
87
|
# TODO: we need to fetch 'ip/name' in mode == :file here
|
87
|
-
user = log[index + 5]
|
88
|
-
from = log[-1][1..-2]
|
89
|
-
|
90
|
-
name: getname(ipaddr))
|
88
|
+
opts[:user] = log[index + 5]
|
89
|
+
opts[:from] = log[-1][1..-2]
|
90
|
+
opts
|
91
91
|
end
|
92
|
+
alias nxos ios
|
93
|
+
alias eos ios
|
92
94
|
|
93
|
-
def
|
95
|
+
def junos(log, index, **opts)
|
94
96
|
# TODO: we need to fetch 'ip/name' in mode == :file here
|
95
|
-
user = log[index + 2][1..-2]
|
96
|
-
msg
|
97
|
-
msg
|
98
|
-
|
99
|
-
|
97
|
+
opts[:user] = log[index + 2][1..-2]
|
98
|
+
opts[:msg] = log[(index + 6)..-1].join(' ')[10..-2]
|
99
|
+
opts.delete(:msg) if opts[:msg] == 'none'
|
100
|
+
opts
|
101
|
+
end
|
102
|
+
|
103
|
+
def aruba(log, index, **opts)
|
104
|
+
opts.merge user: log[index + 2].split('=')[4].split(',')[0][1..-2]
|
100
105
|
end
|
101
106
|
|
102
107
|
def handle_log(log, ipaddr)
|
103
108
|
log = log.to_s.split ' '
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
jnpr ipaddr, log, i
|
109
|
+
index, vendor = MSG.find do |key, value|
|
110
|
+
index = log.find_index { |e| e.match value }
|
111
|
+
break index, key if index
|
108
112
|
end
|
113
|
+
rest send(vendor, log, index, ip: ipaddr, name: getname(ipaddr), model: vendor.to_s) if index
|
109
114
|
end
|
110
115
|
|
111
116
|
def run(io)
|
@@ -129,10 +134,10 @@ module Oxidized
|
|
129
134
|
|
130
135
|
def getname(ipaddr)
|
131
136
|
if Oxidized::CFG.syslogd.resolve == false
|
132
|
-
|
137
|
+
ipaddr
|
133
138
|
else
|
134
|
-
name = (Resolv.getname ipaddr.to_s rescue
|
135
|
-
|
139
|
+
name = (Resolv.getname ipaddr.to_s rescue ipaddr)
|
140
|
+
Oxidized::CFG.syslogd.dns_map.each { |re, sub| name.sub! Regexp.new(re.to_s), sub }
|
136
141
|
name
|
137
142
|
end
|
138
143
|
end
|
data/lib/oxidized/cli.rb
CHANGED
@@ -41,20 +41,24 @@ module Oxidized
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def parse_opts
|
44
|
-
opts = Slop.
|
45
|
-
on 'd', 'debug', 'turn on debugging'
|
46
|
-
on 'daemonize',
|
47
|
-
on '
|
44
|
+
opts = Slop.parse do |opt|
|
45
|
+
opt.on '-d', '--debug', 'turn on debugging'
|
46
|
+
opt.on '--daemonize', 'Daemonize/fork the process'
|
47
|
+
opt.on '-h', '--help', 'show usage' do
|
48
|
+
puts opt
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
opt.on '--show-exhaustive-config', 'output entire configuration, including defaults' do
|
48
52
|
asetus = Config.load
|
49
53
|
puts asetus.to_yaml asetus.cfg
|
50
54
|
Kernel.exit
|
51
55
|
end
|
52
|
-
on 'v', 'version', 'show version' do
|
56
|
+
opt.on '-v', '--version', 'show version' do
|
53
57
|
puts Oxidized::VERSION_FULL
|
54
58
|
Kernel.exit
|
55
59
|
end
|
56
60
|
end
|
57
|
-
[opts.
|
61
|
+
[opts.arguments, opts]
|
58
62
|
end
|
59
63
|
|
60
64
|
attr_reader :pidfile
|
data/lib/oxidized/config/vars.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
module Oxidized::Config::Vars
|
2
2
|
# convenience method for accessing node, group or global level user variables
|
3
|
-
# nil values will be ignored
|
4
3
|
def vars(name)
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
if @node.vars&.has_key?(name)
|
5
|
+
@node.vars[name]
|
6
|
+
elsif Oxidized.config.groups.has_key?(@node.group) && Oxidized.config.groups[@node.group].vars.has_key?(name.to_s)
|
7
|
+
Oxidized.config.groups[@node.group].vars[name.to_s]
|
8
|
+
elsif Oxidized.config.models.has_key(@node.model.class.name.to_s.downcase) && Oxidized.config.models[@node.model.class.name.to_s.downcase].vars.has_key?(name.to_s)
|
9
|
+
Oxidized.config.models[@node.model.class.name.to_s.downcase].vars[name.to_s]
|
10
|
+
elsif Oxidized.config.vars.has_key?(name.to_s)
|
11
|
+
Oxidized.config.vars[name.to_s]
|
8
12
|
end
|
9
|
-
if Oxidized.config.models.has_key?(@node.model.class.name.to_s.downcase)
|
10
|
-
r ||= Oxidized.config.models[@node.model.class.name.to_s.downcase].vars[name.to_s] if Oxidized.config.models[@node.model.class.name.to_s.downcase].vars.has_key?(name.to_s)
|
11
|
-
end
|
12
|
-
r ||= Oxidized.config.vars[name.to_s] if Oxidized.config.vars.has_key?(name.to_s)
|
13
|
-
r
|
14
13
|
end
|
15
14
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Oxidized
|
2
|
+
require "oxidized/input/cli"
|
3
|
+
|
4
|
+
class Exec < Input
|
5
|
+
include Input::CLI
|
6
|
+
|
7
|
+
def connect(node)
|
8
|
+
@node = node
|
9
|
+
@node.model.cfg["exec"].each { |cb| instance_exec(&cb) }
|
10
|
+
@log = File.open(Oxidized::Config::Log + "/#{@node.ip}-exec", "w") if Oxidized.config.input.debug?
|
11
|
+
end
|
12
|
+
|
13
|
+
def cmd(cmd_str)
|
14
|
+
Oxidized.logger.debug "EXEC: #{cmd_str} @ #{@node.name}"
|
15
|
+
# I'd really like to do popen3 with separate arguments, but that would
|
16
|
+
# require refactoring cmd to take parameters
|
17
|
+
%x(#{cmd_str})
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def disconnect
|
23
|
+
true
|
24
|
+
ensure
|
25
|
+
@log.close if Oxidized.config.input.debug?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Airfiber < Oxidized::Model
|
2
|
+
# Ubiquiti Airfiber (tested with Airfiber 11FX)
|
3
|
+
|
4
|
+
prompt /^AF[\w\.]+#/
|
5
|
+
|
6
|
+
cmd :all do |cfg|
|
7
|
+
cfg.cut_both
|
8
|
+
end
|
9
|
+
|
10
|
+
pre do
|
11
|
+
cmd 'cat /tmp/system.cfg'
|
12
|
+
end
|
13
|
+
|
14
|
+
cfg :telnet do
|
15
|
+
username /^[\w\W]+\slogin:\s$/
|
16
|
+
password /^[p:P]assword:\s$/
|
17
|
+
end
|
18
|
+
|
19
|
+
cfg :telnet, :ssh do
|
20
|
+
pre_logout 'exit'
|
21
|
+
end
|
22
|
+
end
|
data/lib/oxidized/model/aos.rb
CHANGED
data/lib/oxidized/model/aosw.rb
CHANGED
@@ -10,7 +10,7 @@ class AOSW < Oxidized::Model
|
|
10
10
|
# All IAPs connected to a Instant Controller will have the same config output. Only the controller needs to be monitored.
|
11
11
|
|
12
12
|
comment '# '
|
13
|
-
prompt
|
13
|
+
prompt /^([\w\(:.@-]+(\)?\s?)[#>]\s?)$/
|
14
14
|
|
15
15
|
cmd :all do |cfg|
|
16
16
|
cfg.cut_both
|
@@ -17,7 +17,7 @@ class C4CMTS < Oxidized::Model
|
|
17
17
|
end
|
18
18
|
|
19
19
|
cmd 'show environment' do |cfg|
|
20
|
-
cfg.gsub! /\s+[\-\d]+\s+C\s+[(\s\d]+\s+F\)/, ''
|
20
|
+
cfg.gsub! /\s+[\-\d]+\s+C\s+[(\s\d]+\s+F\)/, '' # remove temperature readings
|
21
21
|
comment cfg.cut_both
|
22
22
|
end
|
23
23
|
|
@@ -21,12 +21,13 @@ class Comware < Oxidized::Model
|
|
21
21
|
cmd :secret do |cfg|
|
22
22
|
cfg.gsub! /^( snmp-agent community).*/, '\\1 <configuration removed>'
|
23
23
|
cfg.gsub! /^( password hash).*/, '\\1 <configuration removed>'
|
24
|
+
cfg.gsub! /^( password cipher).*/, '\\1 <configuration removed>'
|
24
25
|
cfg
|
25
26
|
end
|
26
27
|
|
27
28
|
cfg :telnet do
|
28
|
-
username /^Username
|
29
|
-
password /^Password
|
29
|
+
username /^(Username|login):/
|
30
|
+
password /^Password:/
|
30
31
|
end
|
31
32
|
|
32
33
|
cfg :telnet, :ssh do
|
@@ -35,12 +36,15 @@ class Comware < Oxidized::Model
|
|
35
36
|
# the pager cannot be disabled before _cmdline-mode on.
|
36
37
|
if vars :comware_cmdline
|
37
38
|
post_login do
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
# HP V1910, V1920
|
40
|
+
cmd '_cmdline-mode on', /(#{@node.prompt}|Continue)/
|
41
|
+
cmd 'y', /(#{@node.prompt}|input password)/
|
42
|
+
cmd vars(:comware_cmdline)
|
43
|
+
|
44
|
+
# HP V1950
|
45
|
+
cmd 'xtd-cli-mode on', /(#{@node.prompt}|Continue)/
|
46
|
+
cmd 'y', /(#{@node.prompt}|input password)/
|
47
|
+
cmd vars(:comware_cmdline)
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -58,6 +62,11 @@ class Comware < Oxidized::Model
|
|
58
62
|
comment cfg
|
59
63
|
end
|
60
64
|
|
65
|
+
cmd 'display device manuinfo' do |cfg|
|
66
|
+
cfg = cfg.each_line.reject { |l| l.match 'FF'.hex.chr }.join
|
67
|
+
comment cfg
|
68
|
+
end
|
69
|
+
|
61
70
|
cmd 'display current-configuration' do |cfg|
|
62
71
|
cfg
|
63
72
|
end
|