oxidized 0.29.1 → 0.37.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/.coderabbit.yaml +21 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +45 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- data/.github/ISSUE_TEMPLATE/support-request.md +39 -0
- data/.github/workflows/codeql.yml +4 -4
- data/.github/workflows/publishdocker.yml +108 -13
- data/.github/workflows/ruby.yml +3 -12
- data/.github/workflows/stale.yml +6 -1
- data/.gitignore +2 -0
- data/.rubocop.yml +69 -13
- data/.rubocop_todo.yml +13 -143
- data/CHANGELOG.md +431 -4
- data/CONTRIBUTING.md +189 -0
- data/Dockerfile +89 -34
- data/README.md +59 -188
- data/Rakefile +58 -12
- data/bin/oxidized +2 -5
- data/docs/Configuration.md +382 -149
- data/docs/Creating-Models.md +262 -10
- data/docs/DeviceSimulation.md +196 -0
- data/docs/Docker.md +246 -0
- data/docs/Hooks.md +146 -51
- data/docs/Inputs.md +237 -0
- data/docs/Issues.md +123 -0
- data/docs/Model-Notes/APC.md +72 -0
- data/docs/Model-Notes/Cumulus.md +5 -0
- data/docs/Model-Notes/EatonNetwork.md +18 -0
- data/docs/Model-Notes/ExaLink.md +43 -0
- data/docs/Model-Notes/FSOS.md +17 -0
- data/docs/Model-Notes/Fortinet.md +75 -0
- data/docs/Model-Notes/GrandstreamHT8xx.md +8 -0
- data/docs/Model-Notes/HPEAruba.md +32 -0
- data/docs/Model-Notes/IvantiConnectSecure.md +59 -0
- data/docs/Model-Notes/OS6.md +10 -0
- data/docs/Model-Notes/README.md +1 -20
- data/docs/Model-Notes/RouterOS.md +28 -0
- data/docs/Model-Notes/SikluMHTG.md +7 -0
- data/docs/Model-Notes/TrueNAS.md +23 -0
- data/docs/Model-Notes/XGS4600-Zyxel.md +5 -0
- data/docs/ModelUnitTests.md +219 -0
- data/docs/Outputs.md +102 -5
- data/docs/Release.md +102 -0
- data/docs/Ruby-API.md +135 -2
- data/docs/Sources.md +34 -0
- data/docs/Supported-OS-Types.md +207 -270
- data/docs/Troubleshooting.md +43 -1
- data/extra/device2yaml.rb +259 -0
- data/extra/gitdiff-msteams.sh +32 -5
- data/extra/hooks/modelrules.rb +55 -0
- data/extra/hooks/modelrulesadvanced.rb +167 -0
- data/extra/hooks/srcipmap.rb +54 -0
- data/extra/nagios_check_failing_nodes.rb +1 -1
- data/extra/oxidized.runit +1 -1
- data/extra/rest_client.rb +5 -4
- data/extra/syslog.rb +11 -6
- data/lib/oxidized/cli/support.rb +152 -0
- data/lib/oxidized/cli.rb +21 -6
- data/lib/oxidized/config/vars.rb +33 -14
- data/lib/oxidized/config.rb +28 -17
- data/lib/oxidized/core.rb +50 -8
- data/lib/oxidized/hook/ciscosparkdiff.rb +11 -9
- data/lib/oxidized/hook/exec.rb +5 -4
- data/lib/oxidized/hook/githubrepo.rb +55 -18
- data/lib/oxidized/hook/noophook.rb +2 -2
- data/lib/oxidized/hook/slackdiff.rb +50 -14
- data/lib/oxidized/hook/xmppdiff.rb +9 -9
- data/lib/oxidized/hook.rb +68 -16
- data/lib/oxidized/input/cli.rb +8 -3
- data/lib/oxidized/input/debugtext.rb +40 -0
- data/lib/oxidized/input/debugyaml.rb +82 -0
- data/lib/oxidized/input/exec.rb +2 -11
- data/lib/oxidized/input/ftp.rb +2 -19
- data/lib/oxidized/input/http.rb +67 -17
- data/lib/oxidized/input/input.rb +35 -14
- data/lib/oxidized/input/scp.rb +27 -0
- data/lib/oxidized/input/ssh.rb +59 -83
- data/lib/oxidized/input/sshbase.rb +102 -0
- data/lib/oxidized/input/telnet.rb +20 -19
- data/lib/oxidized/input/tftp.rb +8 -8
- data/lib/oxidized/job.rb +18 -7
- data/lib/oxidized/jobs.rb +11 -1
- data/lib/oxidized/logger.rb +51 -0
- data/lib/oxidized/manager.rb +18 -17
- data/lib/oxidized/model/acos.rb +2 -1
- data/lib/oxidized/model/addpack.rb +26 -0
- data/lib/oxidized/model/adtran.rb +5 -1
- data/lib/oxidized/model/adva.rb +3 -3
- data/lib/oxidized/model/airfiber.rb +1 -1
- data/lib/oxidized/model/aos7.rb +11 -0
- data/lib/oxidized/model/aoscx.rb +37 -29
- data/lib/oxidized/model/aosw.rb +39 -29
- data/lib/oxidized/model/apc_aos.rb +7 -2
- data/lib/oxidized/model/apcaos.rb +39 -0
- data/lib/oxidized/model/aricentiss.rb +9 -2
- data/lib/oxidized/model/arubainstant.rb +93 -0
- data/lib/oxidized/model/asa.rb +11 -10
- data/lib/oxidized/model/asternos.rb +22 -0
- data/lib/oxidized/model/asyncos.rb +3 -3
- data/lib/oxidized/model/audiocodes.rb +2 -2
- data/lib/oxidized/model/awplus.rb +15 -12
- data/lib/oxidized/model/axos.rb +1 -1
- data/lib/oxidized/model/bdcom.rb +1 -0
- data/lib/oxidized/model/c4cmts.rb +1 -2
- data/lib/oxidized/model/ciscosma.rb +1 -1
- data/lib/oxidized/model/ciscosmb.rb +6 -1
- data/lib/oxidized/model/cnos.rb +13 -10
- data/lib/oxidized/model/comtrol.rb +1 -1
- data/lib/oxidized/model/comware.rb +5 -3
- data/lib/oxidized/model/cumulus.rb +14 -2
- data/lib/oxidized/model/defacto.rb +26 -0
- data/lib/oxidized/model/dellx.rb +1 -1
- data/lib/oxidized/model/dlink.rb +5 -2
- data/lib/oxidized/model/dlinknextgen.rb +55 -0
- data/lib/oxidized/model/dnos.rb +3 -0
- data/lib/oxidized/model/dslcommands.rb +93 -0
- data/lib/oxidized/model/dslsetup.rb +102 -0
- data/lib/oxidized/model/eatonnetwork.rb +70 -0
- data/lib/oxidized/model/edgecos.rb +3 -1
- data/lib/oxidized/model/edgeos.rb +7 -6
- data/lib/oxidized/model/edgeswitch.rb +3 -1
- data/lib/oxidized/model/efos.rb +41 -0
- data/lib/oxidized/model/eltex.rb +4 -2
- data/lib/oxidized/model/enterasys800.rb +2 -2
- data/lib/oxidized/model/enterprise_sonic.rb +46 -0
- data/lib/oxidized/model/eos.rb +3 -1
- data/lib/oxidized/model/exalink.rb +36 -0
- data/lib/oxidized/model/f5os.rb +17 -0
- data/lib/oxidized/model/fabricos.rb +2 -2
- data/lib/oxidized/model/fastiron.rb +5 -3
- data/lib/oxidized/model/firebrick.rb +2 -2
- data/lib/oxidized/model/firelinuxos.rb +13 -6
- data/lib/oxidized/model/firewareos.rb +10 -1
- data/lib/oxidized/model/fortigate.rb +160 -0
- data/lib/oxidized/model/fortios.rb +38 -48
- data/lib/oxidized/model/fsos.rb +46 -0
- data/lib/oxidized/model/gaiaos.rb +4 -4
- data/lib/oxidized/model/garderos.rb +38 -0
- data/lib/oxidized/model/grandstreamht8xx.rb +19 -0
- data/lib/oxidized/model/h3c.rb +1 -1
- data/lib/oxidized/model/ibos.rb +1 -0
- data/lib/oxidized/model/ingate.rb +47 -0
- data/lib/oxidized/model/ios.rb +57 -30
- data/lib/oxidized/model/iosxr.rb +2 -2
- data/lib/oxidized/model/ironware.rb +7 -5
- data/lib/oxidized/model/ivanti.rb +54 -0
- data/lib/oxidized/model/junos.rb +12 -5
- data/lib/oxidized/model/kornfeldos.rb +33 -0
- data/lib/oxidized/model/lenovonos.rb +2 -0
- data/lib/oxidized/model/linksyssrw.rb +3 -3
- data/lib/oxidized/model/linuxgeneric.rb +4 -2
- data/lib/oxidized/model/macros.rb +60 -0
- data/lib/oxidized/model/mimosab11.rb +34 -0
- data/lib/oxidized/model/ml66.rb +33 -0
- data/lib/oxidized/model/mlnxos.rb +18 -14
- data/lib/oxidized/model/model.rb +98 -103
- data/lib/oxidized/model/mtrlrfs.rb +1 -0
- data/lib/oxidized/model/ndms.rb +6 -0
- data/lib/oxidized/model/netgear.rb +14 -3
- data/lib/oxidized/model/netonix.rb +1 -1
- data/lib/oxidized/model/netscaler.rb +1 -1
- data/lib/oxidized/model/nodegrid.rb +1 -1
- data/lib/oxidized/model/nsxdfw.rb +31 -0
- data/lib/oxidized/model/nsxfirewall.rb +2 -1
- data/lib/oxidized/model/nxos.rb +20 -15
- data/lib/oxidized/model/ocnos.rb +42 -0
- data/lib/oxidized/model/onefinity.rb +18 -0
- data/lib/oxidized/model/openbsd.rb +1 -1
- data/lib/oxidized/model/opengear.rb +36 -1
- data/lib/oxidized/model/openwrt.rb +6 -6
- data/lib/oxidized/model/opnsense.rb +9 -1
- data/lib/oxidized/model/os6.rb +48 -0
- data/lib/oxidized/model/outputs.rb +5 -0
- data/lib/oxidized/model/panos.rb +2 -0
- data/lib/oxidized/model/perle.rb +41 -0
- data/lib/oxidized/model/pfsense.rb +9 -0
- data/lib/oxidized/model/powerconnect.rb +32 -11
- data/lib/oxidized/model/procurve.rb +6 -2
- data/lib/oxidized/model/qtech.rb +3 -1
- data/lib/oxidized/model/quantaos.rb +8 -6
- data/lib/oxidized/model/rgos.rb +33 -0
- data/lib/oxidized/model/riverbed.rb +104 -0
- data/lib/oxidized/model/routeros.rb +18 -11
- data/lib/oxidized/model/saos.rb +18 -1
- data/lib/oxidized/model/saos10.rb +38 -0
- data/lib/oxidized/model/siklu.rb +1 -1
- data/lib/oxidized/model/siklumhtg.rb +22 -0
- data/lib/oxidized/model/sixwind.rb +28 -0
- data/lib/oxidized/model/slxos.rb +3 -3
- data/lib/oxidized/model/smartbyte.rb +48 -0
- data/lib/oxidized/model/sonicos.rb +27 -20
- data/lib/oxidized/model/speedtouch.rb +1 -1
- data/lib/oxidized/model/sros.rb +3 -3
- data/lib/oxidized/model/srosmd.rb +1 -1
- data/lib/oxidized/model/supermicro.rb +1 -1
- data/lib/oxidized/model/telco.rb +1 -1
- data/lib/oxidized/model/tmos.rb +1 -0
- data/lib/oxidized/model/tnsr.rb +57 -0
- data/lib/oxidized/model/tplink.rb +5 -5
- data/lib/oxidized/model/trango.rb +4 -2
- data/lib/oxidized/model/truenas.rb +64 -3
- data/lib/oxidized/model/ucs.rb +1 -1
- data/lib/oxidized/model/unifiap.rb +144 -0
- data/lib/oxidized/model/uplinkolt.rb +46 -0
- data/lib/oxidized/model/voltaire.rb +1 -1
- data/lib/oxidized/model/voss.rb +3 -0
- data/lib/oxidized/model/vrp.rb +5 -1
- data/lib/oxidized/model/vyatta.rb +9 -3
- data/lib/oxidized/model/vyos.rb +37 -0
- data/lib/oxidized/model/xos.rb +10 -1
- data/lib/oxidized/model/zhoneolt.rb +4 -2
- data/lib/oxidized/model/zynos.rb +67 -3
- data/lib/oxidized/model/zynosadsl.rb +14 -0
- data/lib/oxidized/model/zynoscli.rb +1 -1
- data/lib/oxidized/model/zynosgs.rb +2 -0
- data/lib/oxidized/model/zynosmgs.rb +32 -0
- data/lib/oxidized/node.rb +99 -64
- data/lib/oxidized/nodes.rb +40 -19
- data/lib/oxidized/output/file.rb +80 -43
- data/lib/oxidized/output/git.rb +295 -151
- data/lib/oxidized/output/gitcrypt.rb +193 -185
- data/lib/oxidized/output/http.rb +63 -51
- data/lib/oxidized/output/output.rb +20 -4
- data/lib/oxidized/signals.rb +44 -0
- data/lib/oxidized/source/csv.rb +49 -49
- data/lib/oxidized/source/http.rb +76 -63
- data/lib/oxidized/source/jsonfile.rb +68 -0
- data/lib/oxidized/source/source.rb +73 -18
- data/lib/oxidized/source/sql.rb +71 -59
- data/lib/oxidized/version.rb +6 -4
- data/lib/oxidized/worker.rb +57 -29
- data/lib/oxidized.rb +4 -24
- data/lib/refinements.rb +21 -1
- data/oxidized.gemspec +45 -21
- metadata +248 -41
- data/lib/oxidized/model/timos.rb +0 -10
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class Vyos < Oxidized::Model
|
|
2
|
+
using Refinements
|
|
3
|
+
|
|
4
|
+
# VyOS model #
|
|
5
|
+
# Vyos is a Fork of Vyatta and is being actively developed.
|
|
6
|
+
# https://vyos.org/
|
|
7
|
+
|
|
8
|
+
prompt /^\S+@\S+(:~\$|>) $/
|
|
9
|
+
clean :escape_codes
|
|
10
|
+
|
|
11
|
+
cmd :all do |cfg|
|
|
12
|
+
cfg.lines.to_a[1..-2].join
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
cmd :secret do |cfg|
|
|
16
|
+
cfg.gsub! /secret (\S+).*/, 'secret <secret removed>'
|
|
17
|
+
cfg.gsub! /password (\S+).*/, 'password <secret removed>'
|
|
18
|
+
cfg.gsub! /snmp community (\S+)/, 'snmp community <secret removed>'
|
|
19
|
+
cfg.gsub! /snmp trap-target ([^\s\\]*) community (\S+)/, 'snmp trap-target \1 community <secret removed>'
|
|
20
|
+
cfg.gsub! /preshared-key (\S+).*/, 'preshared-key <secret removed>'
|
|
21
|
+
cfg.gsub! /private key (\S+).*/, 'private key <secret removed>'
|
|
22
|
+
cfg.gsub! /private-key (\S+).*/, 'private-key <secret removed>'
|
|
23
|
+
# password in URLs like protocol://user:password@domain.tld/
|
|
24
|
+
cfg.gsub! /([a-z]+:\/\/[^:\s]+:)\S+@/, '\1<secret removed>@'
|
|
25
|
+
cfg
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
cmd 'show version' do |cfg|
|
|
29
|
+
comment cfg
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
cmd 'show configuration commands | no-more'
|
|
33
|
+
|
|
34
|
+
cfg :ssh do
|
|
35
|
+
pre_logout 'exit'
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/oxidized/model/xos.rb
CHANGED
|
@@ -12,6 +12,13 @@ class XOS < Oxidized::Model
|
|
|
12
12
|
cfg.each_line.to_a[1..-2].map { |line| line.delete("\r").rstrip }.join("\n") + "\n"
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
cmd :secret do |cfg|
|
|
16
|
+
cfg.gsub! /^(configure (radius|radius-accounting) (netlogin|mgmt-access) (primary|secondary) shared-secret encrypted).+/, '\\1 <secret hidden>'
|
|
17
|
+
cfg.gsub! /^(configure account admin encrypted).+/, '\\1 <secret hidden>'
|
|
18
|
+
cfg.gsub! /^(create account (admin|user) (.+) encrypted).+/, '\\1 <secret hidden>'
|
|
19
|
+
cfg
|
|
20
|
+
end
|
|
21
|
+
|
|
15
22
|
cmd 'show version' do |cfg|
|
|
16
23
|
comment cfg
|
|
17
24
|
end
|
|
@@ -26,7 +33,9 @@ class XOS < Oxidized::Model
|
|
|
26
33
|
|
|
27
34
|
cmd 'show switch' do |cfg|
|
|
28
35
|
cfg.gsub! /Next periodic save on.*/, ''
|
|
29
|
-
comment cfg.each_line.reject { |line|
|
|
36
|
+
comment cfg.each_line.reject { |line|
|
|
37
|
+
line.match(/Time:/) || line.match(/boot/i) || line.match(/Next periodic/)
|
|
38
|
+
}.join
|
|
30
39
|
end
|
|
31
40
|
|
|
32
41
|
cmd 'show configuration' do |cfg|
|
|
@@ -5,7 +5,7 @@ class ZhoneOLT < Oxidized::Model
|
|
|
5
5
|
|
|
6
6
|
# the prompt can be anything on zhone, but it defaults to 'zXX>' and we
|
|
7
7
|
# always use hostname>
|
|
8
|
-
prompt /^(\r*[\w.@():-]
|
|
8
|
+
prompt /^(\r*[\w.@():-]+>\s?)$/
|
|
9
9
|
comment '# '
|
|
10
10
|
|
|
11
11
|
cmd :secret do |cfg|
|
|
@@ -36,7 +36,9 @@ class ZhoneOLT < Oxidized::Model
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
cmd 'ethrpshow' do |cfg|
|
|
39
|
-
cfg = cfg.each_line.select
|
|
39
|
+
cfg = cfg.each_line.select do |line|
|
|
40
|
+
line.match /Vendor (Name|OUI|Part|Revision)|Serial Number|Manufacturing Date/
|
|
41
|
+
end.join
|
|
40
42
|
comment cfg
|
|
41
43
|
end
|
|
42
44
|
|
data/lib/oxidized/model/zynos.rb
CHANGED
|
@@ -1,12 +1,76 @@
|
|
|
1
1
|
class ZyNOS < Oxidized::Model
|
|
2
2
|
using Refinements
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
prompt /^([\w.@()\-<]+[#>]\s?)$/
|
|
5
|
+
# if there is something you can not identify after prompt, uncomment next line and comment previous line
|
|
6
|
+
# prompt /^([\w.@()\-<]+[#>]\s?).*$/
|
|
5
7
|
|
|
6
8
|
comment '! '
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
# Used in Zyxel DSLAMs, such as SAM1316. Uncomment next line to enable ftp.
|
|
11
|
+
# cmd 'config-0'
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
# replace next line control sequence with a new line
|
|
14
|
+
expect /(\e\[1M\e\[\??\d+(;\d+)*[A-Za-z]\e\[1L)|(\eE)/ do |data, re|
|
|
15
|
+
data.gsub re, "\n"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# replace all used vt100 control sequences
|
|
19
|
+
expect /\e\[\??\d+(;\d+)*[A-Za-z]/ do |data, re|
|
|
20
|
+
data.gsub re, ''
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# ignore copyright motd
|
|
24
|
+
expect /^(Copyright .*)\n^([\w.@()\-<]+[#>]\s?)$/ do
|
|
25
|
+
send '\n'
|
|
26
|
+
""
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
cmd :all do |cfg|
|
|
30
|
+
cfg = cfg.gsub /^\r/, ''
|
|
31
|
+
# Additional filtering for elder switches sending vt100 control chars via telnet
|
|
32
|
+
cfg.gsub! /\e\[\??\d+(;\d+)*[A-Za-z]/, ''
|
|
33
|
+
cfg
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# remove snmp community, username, password and admin-password
|
|
37
|
+
cmd :secret do |cfg|
|
|
38
|
+
cfg.gsub! /^(snmp-server get-community) \S+(.*)/, '\\1 <secret hidden> \\2'
|
|
39
|
+
cfg.gsub! /^(snmp-server set-community) \S+(.*)/, '\\1 <secret hidden> \\2'
|
|
40
|
+
cfg.gsub! /^(logins username) \S+(.*) (password) \S+(.*)/, '\\1 <secret hidden> \\2 \\3 <secret hidden> \\4'
|
|
41
|
+
cfg.gsub! /^(admin-password) \S+(.*)/, '\\1 <secret hidden> \\2'
|
|
42
|
+
cfg.gsub! /^(password) \S+(.*) (privilege \S+)/, '\\1 <secret hidden> \\2 \\3'
|
|
43
|
+
cfg
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
cmd 'show version' do |cfg|
|
|
47
|
+
comment cfg
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
cmd 'show system-information' do |cfg|
|
|
51
|
+
cfg.gsub! /^([Ss]ystem up [Tt]ime\s*:)(.*)/, '\\1 <time removed>'
|
|
52
|
+
comment cfg
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
cmd 'show running-config' do |cfg|
|
|
56
|
+
cfg = cfg.split("\n")[4..-2].join("\n")
|
|
57
|
+
cfg
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
cfg :telnet do
|
|
61
|
+
username /^User name:/i
|
|
62
|
+
password /^Password:/i
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
cfg :telnet, :ssh do
|
|
66
|
+
post_login do
|
|
67
|
+
if vars(:enable) == true
|
|
68
|
+
cmd "enable"
|
|
69
|
+
elsif vars(:enable)
|
|
70
|
+
cmd "enable", /^[pP]assword:/
|
|
71
|
+
cmd vars(:enable)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
pre_logout 'exit'
|
|
11
75
|
end
|
|
12
76
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class ZyNOSMGS < Oxidized::Model
|
|
2
|
+
using Refinements
|
|
3
|
+
|
|
4
|
+
PROMPT = /^(\w.*)>(.*)?$/
|
|
5
|
+
# Used in Zyxel MGS Series switches
|
|
6
|
+
|
|
7
|
+
prompt PROMPT
|
|
8
|
+
comment '! '
|
|
9
|
+
|
|
10
|
+
cmd 'show version' do |cfg|
|
|
11
|
+
clear_output cfg
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
cmd 'show running-config' do |cfg|
|
|
15
|
+
clear_output cfg
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
cfg :telnet do
|
|
19
|
+
username /^User\s?name(\(1-32 chars\))?:/i
|
|
20
|
+
password /^Password(\(1-32 chars\))?:/i
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
cfg :telnet, :ssh do
|
|
24
|
+
pre_logout 'exit'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def clear_output(output)
|
|
30
|
+
output.gsub PROMPT, ''
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/oxidized/node.rb
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
module Oxidized
|
|
2
2
|
require 'resolv'
|
|
3
|
-
require 'ostruct'
|
|
4
3
|
require_relative 'node/stats'
|
|
5
4
|
class MethodNotFound < OxidizedError; end
|
|
6
5
|
class ModelNotFound < OxidizedError; end
|
|
7
6
|
|
|
8
7
|
class Node
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
include SemanticLogger::Loggable
|
|
9
|
+
|
|
10
|
+
attr_reader :name, :ip, :model, :input, :output, :group, :auth, :prompt, :timeout, :vars, :last, :repo
|
|
11
|
+
attr_accessor :running, :user, :email, :msg, :from, :stats, :retry, :err_type, :err_reason, :nexted
|
|
11
12
|
alias running? running
|
|
13
|
+
alias nexted? nexted
|
|
12
14
|
|
|
15
|
+
# opt is a hash with the node parameters given in the source (:name, :group, :ip...)
|
|
13
16
|
def initialize(opt)
|
|
14
|
-
|
|
17
|
+
logger.debug 'resolving DNS for %s...' % opt[:name]
|
|
15
18
|
# remove the prefix if an IP Address is provided with one as IPAddr converts it to a network address.
|
|
16
19
|
ip_addr, = opt[:ip].to_s.split("/")
|
|
17
|
-
|
|
20
|
+
logger.debug 'IPADDR %s' % ip_addr.to_s
|
|
18
21
|
@name = opt[:name]
|
|
19
22
|
@ip = IPAddr.new(ip_addr).to_s rescue nil
|
|
20
23
|
@ip ||= Resolv.new.getaddress(@name) if Oxidized.config.resolve_dns?
|
|
@@ -25,47 +28,52 @@ module Oxidized
|
|
|
25
28
|
@output = resolve_output opt
|
|
26
29
|
@auth = resolve_auth opt
|
|
27
30
|
@prompt = resolve_prompt opt
|
|
28
|
-
@
|
|
31
|
+
@timeout = resolve_timeout opt
|
|
32
|
+
@vars = opt[:vars] || {}
|
|
29
33
|
@stats = Stats.new
|
|
30
34
|
@retry = 0
|
|
31
35
|
@repo = resolve_repo opt
|
|
32
36
|
@err_type = nil
|
|
33
37
|
@err_reason = nil
|
|
38
|
+
@nexted = false
|
|
34
39
|
|
|
35
40
|
# model instance needs to access node instance
|
|
36
41
|
@model.node = self
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
def run
|
|
40
|
-
status
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
status = :fail
|
|
46
|
+
config = Oxidized::Model::Outputs.new
|
|
47
|
+
input_sequence = @model.class.input_sequence(@input)
|
|
48
|
+
|
|
49
|
+
input_sequence.each do |sequence|
|
|
50
|
+
status = :fail
|
|
51
|
+
sequence_config = nil
|
|
52
|
+
sequence.each do |input|
|
|
53
|
+
@model.input = input = input.new
|
|
54
|
+
if (sequence_config = run_input(input))
|
|
55
|
+
logger.debug "#{input.class.name} ran for #{name} successfully"
|
|
56
|
+
status = :success
|
|
57
|
+
break
|
|
58
|
+
else
|
|
59
|
+
logger.debug "#{input.class.name} failed for #{name}"
|
|
60
|
+
status = :no_connection
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
if status == :success
|
|
64
|
+
config.merge! sequence_config
|
|
51
65
|
else
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
config = nil
|
|
67
|
+
break
|
|
54
68
|
end
|
|
55
69
|
end
|
|
70
|
+
|
|
56
71
|
@model.input = nil
|
|
57
72
|
[status, config]
|
|
58
73
|
end
|
|
59
74
|
|
|
60
75
|
def run_input(input)
|
|
61
|
-
rescue_fail =
|
|
62
|
-
[input.class::RescueFail, input.class.superclass::RescueFail].each do |hash|
|
|
63
|
-
hash.each do |level, errors|
|
|
64
|
-
errors.each do |err|
|
|
65
|
-
rescue_fail[err] = level
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
76
|
+
rescue_fail = input.class.rescue_fail
|
|
69
77
|
begin
|
|
70
78
|
input.connect(self) && input.get
|
|
71
79
|
rescue *rescue_fail.keys => err
|
|
@@ -75,24 +83,31 @@ module Oxidized
|
|
|
75
83
|
level = rescue_fail[resc]
|
|
76
84
|
resc = " (rescued #{resc})"
|
|
77
85
|
end
|
|
78
|
-
|
|
86
|
+
logger.send(level, '%s raised %s%s with msg "%s"' % [ip, err.class, resc, err.message])
|
|
79
87
|
@err_type = err.class.to_s
|
|
80
88
|
@err_reason = err.message.to_s
|
|
81
89
|
false
|
|
82
|
-
rescue StandardError =>
|
|
90
|
+
rescue StandardError => e
|
|
91
|
+
# Send a message in debug mode in case we are not able to create a crashfile
|
|
92
|
+
logger.error "#{ip} raised #{e.class} with msg #{e.message}, creating crashfile"
|
|
93
|
+
unless Oxidized.config.crash.directory?
|
|
94
|
+
logger.error "Cannot create crashfile for exception", e
|
|
95
|
+
return false
|
|
96
|
+
end
|
|
97
|
+
|
|
83
98
|
crashdir = Oxidized.config.crash.directory
|
|
84
99
|
crashfile = Oxidized.config.crash.hostnames? ? name : ip.to_s
|
|
85
100
|
FileUtils.mkdir_p(crashdir) unless File.directory?(crashdir)
|
|
86
101
|
|
|
87
102
|
File.open File.join(crashdir, crashfile), 'w' do |fh|
|
|
88
103
|
fh.puts Time.now.utc
|
|
89
|
-
fh.puts
|
|
104
|
+
fh.puts e.message + ' [' + e.class.to_s + ']'
|
|
90
105
|
fh.puts '-' * 50
|
|
91
|
-
fh.puts
|
|
106
|
+
fh.puts e.backtrace
|
|
92
107
|
end
|
|
93
|
-
|
|
94
|
-
@err_type =
|
|
95
|
-
@err_reason =
|
|
108
|
+
logger.error '%s raised %s with msg "%s", %s saved' % [ip, e.class, e.message, crashfile]
|
|
109
|
+
@err_type = e.class.to_s
|
|
110
|
+
@err_reason = e.message.to_s
|
|
96
111
|
false
|
|
97
112
|
end
|
|
98
113
|
end
|
|
@@ -120,14 +135,10 @@ module Oxidized
|
|
|
120
135
|
h
|
|
121
136
|
end
|
|
122
137
|
|
|
138
|
+
JobStruct = Struct.new(:start, :end, :status, :time)
|
|
123
139
|
def last=(job)
|
|
124
140
|
if job
|
|
125
|
-
|
|
126
|
-
ostruct.start = job.start
|
|
127
|
-
ostruct.end = job.end
|
|
128
|
-
ostruct.status = job.status
|
|
129
|
-
ostruct.time = job.time
|
|
130
|
-
@last = ostruct
|
|
141
|
+
@last = JobStruct.new(job.start, job.end, job.status, job.time)
|
|
131
142
|
else
|
|
132
143
|
@last = nil
|
|
133
144
|
end
|
|
@@ -148,6 +159,10 @@ module Oxidized
|
|
|
148
159
|
opt[:prompt] || @model.prompt || Oxidized.config.prompt
|
|
149
160
|
end
|
|
150
161
|
|
|
162
|
+
def resolve_timeout(opt)
|
|
163
|
+
resolve_key :timeout, opt, Oxidized.config.timeout
|
|
164
|
+
end
|
|
165
|
+
|
|
151
166
|
def resolve_auth(opt)
|
|
152
167
|
# Resolve configured username/password
|
|
153
168
|
{
|
|
@@ -158,8 +173,11 @@ module Oxidized
|
|
|
158
173
|
|
|
159
174
|
def resolve_input(opt)
|
|
160
175
|
inputs = resolve_key :input, opt, Oxidized.config.input.default
|
|
161
|
-
inputs.split(
|
|
162
|
-
|
|
176
|
+
inputs.split(',').map do |input|
|
|
177
|
+
input.strip!
|
|
178
|
+
unless Oxidized.mgr.input[input]
|
|
179
|
+
Oxidized.mgr.add_input(input) || raise(MethodNotFound, "#{input} not found for node #{ip}")
|
|
180
|
+
end
|
|
163
181
|
|
|
164
182
|
Oxidized.mgr.input[input]
|
|
165
183
|
end
|
|
@@ -167,7 +185,10 @@ module Oxidized
|
|
|
167
185
|
|
|
168
186
|
def resolve_output(opt)
|
|
169
187
|
output = resolve_key :output, opt, Oxidized.config.output.default
|
|
170
|
-
|
|
188
|
+
unless Oxidized.mgr.output[output]
|
|
189
|
+
Oxidized.mgr.add_output(output) || raise(MethodNotFound,
|
|
190
|
+
"#{output} not found for node #{ip}")
|
|
191
|
+
end
|
|
171
192
|
|
|
172
193
|
Oxidized.mgr.output[output]
|
|
173
194
|
end
|
|
@@ -175,7 +196,7 @@ module Oxidized
|
|
|
175
196
|
def resolve_model(opt)
|
|
176
197
|
model = resolve_key :model, opt
|
|
177
198
|
unless Oxidized.mgr.model[model]
|
|
178
|
-
|
|
199
|
+
logger.debug "Loading model #{model.inspect}"
|
|
179
200
|
Oxidized.mgr.add_model(model) || raise(ModelNotFound, "#{model} not found for node #{ip}")
|
|
180
201
|
end
|
|
181
202
|
Oxidized.mgr.model[model].new
|
|
@@ -198,33 +219,47 @@ module Oxidized
|
|
|
198
219
|
end
|
|
199
220
|
|
|
200
221
|
def resolve_key(key, opt, global = nil)
|
|
201
|
-
# resolve key
|
|
222
|
+
# resolve key: the priority is as follows:
|
|
223
|
+
# node -> group specific model -> group -> model -> global passed -> global
|
|
224
|
+
# where node has the highest priority (= if defined, overwrites other values)
|
|
202
225
|
key_sym = key.to_sym
|
|
203
226
|
key_str = key.to_s
|
|
204
|
-
|
|
205
|
-
|
|
227
|
+
model_name = @model.class.name.to_s.downcase
|
|
228
|
+
logger.debug "resolving node key '#{key}', with passed global value of '#{global}' " \
|
|
229
|
+
"and node value '#{opt[key_sym]}'"
|
|
206
230
|
|
|
207
|
-
#
|
|
208
|
-
if
|
|
209
|
-
value =
|
|
210
|
-
|
|
211
|
-
end
|
|
231
|
+
# Node
|
|
232
|
+
if opt[key_sym]
|
|
233
|
+
value = opt[key_sym]
|
|
234
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from node"
|
|
212
235
|
|
|
213
|
-
#
|
|
214
|
-
|
|
236
|
+
# Group specific model
|
|
237
|
+
elsif Oxidized.config.groups.has_key?(@group) &&
|
|
238
|
+
Oxidized.config.groups[@group].models.has_key?(model_name) &&
|
|
239
|
+
Oxidized.config.groups[@group].models[model_name].has_key?(key_str)
|
|
240
|
+
value = Oxidized.config.groups[@group].models[model_name][key_str]
|
|
241
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from model in group"
|
|
242
|
+
|
|
243
|
+
# Group
|
|
244
|
+
elsif Oxidized.config.groups.has_key?(@group) && Oxidized.config.groups[@group].has_key?(key_str)
|
|
215
245
|
value = Oxidized.config.groups[@group][key_str]
|
|
216
|
-
|
|
217
|
-
end
|
|
246
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from group"
|
|
218
247
|
|
|
219
|
-
#
|
|
220
|
-
|
|
221
|
-
value = Oxidized.config.models[
|
|
222
|
-
|
|
223
|
-
end
|
|
248
|
+
# Model
|
|
249
|
+
elsif Oxidized.config.models.has_key?(model_name) && Oxidized.config.models[model_name].has_key?(key_str)
|
|
250
|
+
value = Oxidized.config.models[model_name][key_str]
|
|
251
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from model"
|
|
224
252
|
|
|
225
|
-
#
|
|
226
|
-
|
|
227
|
-
|
|
253
|
+
# Global passed
|
|
254
|
+
elsif global
|
|
255
|
+
value = global
|
|
256
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from passed global value"
|
|
257
|
+
|
|
258
|
+
# Global
|
|
259
|
+
elsif Oxidized.config.has_key?(key_str)
|
|
260
|
+
value = Oxidized.config[key_str]
|
|
261
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from global"
|
|
262
|
+
end
|
|
228
263
|
value
|
|
229
264
|
end
|
|
230
265
|
|
data/lib/oxidized/nodes.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
module Oxidized
|
|
2
2
|
require 'ipaddr'
|
|
3
3
|
require 'oxidized/node'
|
|
4
|
-
class
|
|
5
|
-
class
|
|
4
|
+
class NotSupported < OxidizedError; end
|
|
5
|
+
class NodeNotFound < OxidizedError; end
|
|
6
6
|
|
|
7
7
|
class Nodes < Array
|
|
8
|
+
include SemanticLogger::Loggable
|
|
9
|
+
|
|
8
10
|
attr_accessor :source, :jobs
|
|
9
11
|
alias put unshift
|
|
10
12
|
def load(node_want = nil)
|
|
@@ -12,7 +14,7 @@ module Oxidized
|
|
|
12
14
|
new = []
|
|
13
15
|
@source = Oxidized.config.source.default
|
|
14
16
|
Oxidized.mgr.add_source(@source) || raise(MethodNotFound, "cannot load node source '#{@source}', not found")
|
|
15
|
-
|
|
17
|
+
logger.info "Loading nodes"
|
|
16
18
|
nodes = Oxidized.mgr.source[@source].new.load node_want
|
|
17
19
|
nodes.each do |node|
|
|
18
20
|
# we want to load specific node(s), not all of them
|
|
@@ -21,22 +23,25 @@ module Oxidized
|
|
|
21
23
|
begin
|
|
22
24
|
node_obj = Node.new node
|
|
23
25
|
new.push node_obj
|
|
24
|
-
rescue ModelNotFound =>
|
|
25
|
-
|
|
26
|
-
rescue Resolv::ResolvError =>
|
|
27
|
-
|
|
26
|
+
rescue ModelNotFound => e
|
|
27
|
+
logger.error "node %s raised %s with message '%s'" % [node, e.class, e.message]
|
|
28
|
+
rescue Resolv::ResolvError => e
|
|
29
|
+
logger.error "node %s is not resolvable, raised %s with message '%s'" % [node, e.class, e.message]
|
|
28
30
|
end
|
|
29
31
|
end
|
|
30
32
|
size.zero? ? replace(new) : update_nodes(new)
|
|
31
|
-
|
|
33
|
+
Output.clean_obsolete_nodes(self) if node_want.nil?
|
|
34
|
+
logger.info "Loaded #{size} nodes"
|
|
32
35
|
end
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
def node_want?(node_want, node)
|
|
36
39
|
return true unless node_want
|
|
37
40
|
|
|
41
|
+
# rubocop:disable Style/RedundantParentheses
|
|
38
42
|
node_want_ip = (IPAddr.new(node_want) rescue false)
|
|
39
43
|
name_is_ip = (IPAddr.new(node[:name]) rescue false)
|
|
44
|
+
# rubocop:enable Style/RedundantParentheses
|
|
40
45
|
# rubocop:todo Lint/DuplicateBranch
|
|
41
46
|
if name_is_ip && (node_want_ip == node[:name])
|
|
42
47
|
true
|
|
@@ -61,6 +66,9 @@ module Oxidized
|
|
|
61
66
|
end
|
|
62
67
|
end
|
|
63
68
|
|
|
69
|
+
# Returns the configuration of group/node_name
|
|
70
|
+
#
|
|
71
|
+
# #fetch is called by oxidzed-web
|
|
64
72
|
def fetch(node_name, group)
|
|
65
73
|
yield_node_output(node_name) do |node, output|
|
|
66
74
|
output.fetch node, group
|
|
@@ -69,8 +77,9 @@ module Oxidized
|
|
|
69
77
|
|
|
70
78
|
# @param node [String] name of the node moved into the head of array
|
|
71
79
|
def next(node, opt = {})
|
|
72
|
-
return
|
|
80
|
+
return if running.find_index(node)
|
|
73
81
|
|
|
82
|
+
logger.info "Add node #{node} to running jobs"
|
|
74
83
|
with_lock do
|
|
75
84
|
n = del node
|
|
76
85
|
n.user = opt['user']
|
|
@@ -79,8 +88,10 @@ module Oxidized
|
|
|
79
88
|
n.from = opt['from']
|
|
80
89
|
# set last job to nil so that the node is picked for immediate update
|
|
81
90
|
n.last = nil
|
|
91
|
+
# set nexted to true so that the node will not be skipped with interval 0
|
|
92
|
+
n.nexted = true
|
|
82
93
|
put n
|
|
83
|
-
jobs.
|
|
94
|
+
jobs.increment if Oxidized.config.next_adds_job?
|
|
84
95
|
end
|
|
85
96
|
end
|
|
86
97
|
alias top next
|
|
@@ -95,9 +106,12 @@ module Oxidized
|
|
|
95
106
|
# @param node node whose index number in Nodes to find
|
|
96
107
|
# @return [Fixnum] index number of node in Nodes
|
|
97
108
|
def find_node_index(node)
|
|
98
|
-
find_index(node) || raise(
|
|
109
|
+
find_index(node) || raise(NodeNotFound, "unable to find '#{node}'")
|
|
99
110
|
end
|
|
100
111
|
|
|
112
|
+
# Returns all stored versions of group/node_name
|
|
113
|
+
#
|
|
114
|
+
# Called by oxidized-web
|
|
101
115
|
def version(node_name, group)
|
|
102
116
|
yield_node_output(node_name) do |node, output|
|
|
103
117
|
output.version node, group
|
|
@@ -116,6 +130,10 @@ module Oxidized
|
|
|
116
130
|
end
|
|
117
131
|
end
|
|
118
132
|
|
|
133
|
+
def find_index(node)
|
|
134
|
+
index { |e| [e.name, e.ip].include? node }
|
|
135
|
+
end
|
|
136
|
+
|
|
119
137
|
private
|
|
120
138
|
|
|
121
139
|
def initialize(opts = {})
|
|
@@ -129,12 +147,8 @@ module Oxidized
|
|
|
129
147
|
end
|
|
130
148
|
end
|
|
131
149
|
|
|
132
|
-
def with_lock(
|
|
133
|
-
@mutex.synchronize(
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def find_index(node)
|
|
137
|
-
index { |e| [e.name, e.ip].include? node }
|
|
150
|
+
def with_lock(...)
|
|
151
|
+
@mutex.synchronize(...)
|
|
138
152
|
end
|
|
139
153
|
|
|
140
154
|
# @param node node which is removed from nodes list
|
|
@@ -160,13 +174,18 @@ module Oxidized
|
|
|
160
174
|
# @param [Array] nodes Array of nodes used to replace+update old
|
|
161
175
|
def update_nodes(nodes)
|
|
162
176
|
old = dup
|
|
177
|
+
# load the Array "nodes" in self (the class Nodes inherits Array)
|
|
163
178
|
replace(nodes)
|
|
164
179
|
each do |node|
|
|
165
180
|
if (i = old.find_node_index(node.name))
|
|
166
181
|
node.stats = old[i].stats
|
|
167
182
|
node.last = old[i].last
|
|
168
183
|
end
|
|
169
|
-
rescue
|
|
184
|
+
rescue NodeNotFound
|
|
185
|
+
# Do nothing:
|
|
186
|
+
# when a node is not found, we have nothing to do:
|
|
187
|
+
# it has already been loaded by replace(nodes) and there are no
|
|
188
|
+
# stats to copy
|
|
170
189
|
end
|
|
171
190
|
sort_by! { |x| x.last.nil? ? Time.new(0) : x.last.end }
|
|
172
191
|
end
|
|
@@ -174,8 +193,10 @@ module Oxidized
|
|
|
174
193
|
def yield_node_output(node_name)
|
|
175
194
|
with_lock do
|
|
176
195
|
node = find { |n| n.name == node_name }
|
|
196
|
+
raise(NodeNotFound, "unable to find '#{node_name}'") if node.nil?
|
|
197
|
+
|
|
177
198
|
output = node.output.new
|
|
178
|
-
raise
|
|
199
|
+
raise NotSupported unless output.respond_to? :fetch
|
|
179
200
|
|
|
180
201
|
yield node, output
|
|
181
202
|
end
|