oxidized 0.32.1 → 0.34.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/.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/publishdocker.yml +35 -16
- data/.github/workflows/ruby.yml +4 -2
- data/.gitignore +2 -0
- data/.rubocop.yml +29 -8
- data/.rubocop_todo.yml +1 -60
- data/CHANGELOG.md +103 -2
- data/CONTRIBUTING.md +20 -10
- data/Dockerfile +37 -64
- data/README.md +47 -141
- data/Rakefile +9 -11
- data/docs/Configuration.md +236 -27
- data/docs/DeviceSimulation.md +19 -7
- data/docs/Docker.md +245 -0
- data/docs/Issues.md +27 -1
- data/docs/Model-Notes/EatonNetwork.md +18 -0
- data/docs/Model-Notes/HPEAruba.md +3 -2
- data/docs/ModelUnitTests.md +35 -25
- data/docs/Outputs.md +83 -2
- data/docs/Release.md +34 -24
- data/docs/Supported-OS-Types.md +7 -0
- data/docs/Troubleshooting.md +4 -13
- data/extra/device2yaml.rb +24 -9
- data/extra/rest_client.rb +3 -2
- data/extra/syslog.rb +8 -3
- data/lib/oxidized/cli.rb +7 -3
- data/lib/oxidized/config/vars.rb +22 -14
- data/lib/oxidized/config.rb +3 -2
- data/lib/oxidized/core.rb +30 -8
- data/lib/oxidized/hook/ciscosparkdiff.rb +11 -9
- data/lib/oxidized/hook/exec.rb +5 -4
- data/lib/oxidized/hook/githubrepo.rb +23 -17
- data/lib/oxidized/hook/noophook.rb +2 -2
- data/lib/oxidized/hook/slackdiff.rb +9 -8
- data/lib/oxidized/hook/xmppdiff.rb +9 -9
- data/lib/oxidized/hook.rb +10 -8
- data/lib/oxidized/input/cli.rb +8 -3
- data/lib/oxidized/input/exec.rb +1 -1
- data/lib/oxidized/input/ftp.rb +2 -2
- data/lib/oxidized/input/http.rb +6 -6
- data/lib/oxidized/input/input.rb +1 -0
- data/lib/oxidized/input/scp.rb +2 -2
- data/lib/oxidized/input/ssh.rb +21 -14
- data/lib/oxidized/input/telnet.rb +3 -3
- data/lib/oxidized/input/tftp.rb +1 -1
- data/lib/oxidized/job.rb +7 -4
- data/lib/oxidized/logger.rb +51 -0
- data/lib/oxidized/model/acos.rb +1 -0
- data/lib/oxidized/model/aos7.rb +9 -0
- data/lib/oxidized/model/aoscx.rb +2 -0
- data/lib/oxidized/model/aosw.rb +22 -17
- data/lib/oxidized/model/aricentiss.rb +2 -2
- data/lib/oxidized/model/asa.rb +3 -3
- data/lib/oxidized/model/awplus.rb +13 -10
- data/lib/oxidized/model/eatonnetwork.rb +65 -0
- data/lib/oxidized/model/edgecos.rb +2 -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 +1 -1
- data/lib/oxidized/model/fabricos.rb +1 -1
- data/lib/oxidized/model/fastiron.rb +3 -1
- data/lib/oxidized/model/firelinuxos.rb +12 -3
- data/lib/oxidized/model/fortios.rb +5 -4
- data/lib/oxidized/model/gaiaos.rb +4 -4
- data/lib/oxidized/model/ingate.rb +47 -0
- data/lib/oxidized/model/ios.rb +16 -5
- data/lib/oxidized/model/ironware.rb +1 -1
- data/lib/oxidized/model/junos.rb +4 -0
- data/lib/oxidized/model/linksyssrw.rb +3 -3
- data/lib/oxidized/model/mlnxos.rb +14 -7
- data/lib/oxidized/model/model.rb +4 -3
- data/lib/oxidized/model/netgear.rb +8 -0
- data/lib/oxidized/model/nsxdfw.rb +2 -1
- data/lib/oxidized/model/nsxfirewall.rb +2 -1
- data/lib/oxidized/model/nxos.rb +2 -2
- data/lib/oxidized/model/openwrt.rb +6 -6
- data/lib/oxidized/model/powerconnect.rb +31 -10
- data/lib/oxidized/model/procurve.rb +3 -1
- data/lib/oxidized/model/qtech.rb +3 -1
- data/lib/oxidized/model/quantaos.rb +8 -6
- data/lib/oxidized/model/routeros.rb +3 -2
- data/lib/oxidized/model/saos10.rb +38 -0
- data/lib/oxidized/model/sixwind.rb +28 -0
- data/lib/oxidized/model/sonicos.rb +1 -1
- data/lib/oxidized/model/srosmd.rb +1 -1
- data/lib/oxidized/model/supermicro.rb +1 -1
- data/lib/oxidized/model/timos.rb +1 -1
- data/lib/oxidized/model/tmos.rb +1 -0
- data/lib/oxidized/model/tnsr.rb +53 -0
- data/lib/oxidized/model/trango.rb +3 -1
- data/lib/oxidized/model/unifiap.rb +144 -0
- data/lib/oxidized/model/vrp.rb +3 -1
- data/lib/oxidized/model/xos.rb +3 -1
- data/lib/oxidized/model/zhoneolt.rb +3 -1
- data/lib/oxidized/model/zynos.rb +3 -3
- data/lib/oxidized/node.rb +44 -27
- data/lib/oxidized/nodes.rb +8 -4
- data/lib/oxidized/output/file.rb +28 -0
- data/lib/oxidized/output/git.rb +148 -41
- data/lib/oxidized/output/gitcrypt.rb +18 -13
- data/lib/oxidized/output/http.rb +5 -4
- data/lib/oxidized/output/output.rb +14 -0
- data/lib/oxidized/source/http.rb +4 -2
- data/lib/oxidized/version.rb +6 -4
- data/lib/oxidized/worker.rb +13 -13
- data/lib/oxidized.rb +3 -24
- data/lib/refinements.rb +2 -0
- data/oxidized.gemspec +10 -8
- metadata +74 -41
- data/examples/podman-compose/Makefile +0 -103
- data/examples/podman-compose/README.md +0 -94
- data/examples/podman-compose/docker-compose.yml +0 -30
- data/examples/podman-compose/gitserver/.gitignore +0 -1
- data/examples/podman-compose/gitserver/Dockerfile +0 -14
- data/examples/podman-compose/model-simulation/Dockerfile-model +0 -13
- data/examples/podman-compose/model-simulation/asternos.sh +0 -36
- data/examples/podman-compose/oxidized-config/.gitignore +0 -10
- data/examples/podman-compose/oxidized-config/config +0 -46
- data/examples/podman-compose/oxidized-config/config_csv-file +0 -46
- data/examples/podman-compose/oxidized-config/config_csv-gitserver +0 -56
- data/examples/podman-compose/oxidized-config/router.db +0 -1
- data/examples/podman-compose/oxidized-ssh/.gitignore +0 -1
- data/examples/podman-compose/oxidized-ssh/README.md +0 -14
@@ -5,35 +5,35 @@ class XMPPDiff < Oxidized::Hook
|
|
5
5
|
def connect
|
6
6
|
@client = Jabber::Client.new(Jabber::JID.new(cfg.jid))
|
7
7
|
|
8
|
-
|
8
|
+
logger.info "Connecting to XMPP"
|
9
9
|
begin
|
10
10
|
Timeout.timeout(15) do
|
11
11
|
begin
|
12
12
|
@client.connect
|
13
13
|
rescue StandardError => e
|
14
|
-
|
14
|
+
logger.info "Failed to connect to XMPP: #{e}"
|
15
15
|
end
|
16
16
|
sleep 1
|
17
17
|
|
18
|
-
|
18
|
+
logger.info "Authenticating to XMPP"
|
19
19
|
@client.auth(cfg.password)
|
20
20
|
sleep 1
|
21
21
|
|
22
|
-
|
22
|
+
logger.info "Connected to XMPP"
|
23
23
|
|
24
24
|
@muc = Jabber::MUC::SimpleMUCClient.new(@client)
|
25
25
|
@muc.join(cfg.channel + "/" + cfg.nick)
|
26
26
|
|
27
|
-
|
27
|
+
logger.info "Joined #{cfg.channel}"
|
28
28
|
end
|
29
29
|
rescue Timeout::Error
|
30
|
-
|
30
|
+
logger.info "timed out"
|
31
31
|
@client = nil
|
32
32
|
@muc = nil
|
33
33
|
end
|
34
34
|
|
35
35
|
@client.on_exception do
|
36
|
-
|
36
|
+
logger.info "XMPP connection aborted, reconnecting"
|
37
37
|
@client = nil
|
38
38
|
@muc = nil
|
39
39
|
connect
|
@@ -66,14 +66,14 @@ class XMPPDiff < Oxidized::Hook
|
|
66
66
|
# Maybe connecting failed, so only proceed if we actually joined the MUC
|
67
67
|
unless @muc.nil?
|
68
68
|
title = "#{ctx.node.name} #{ctx.node.group} #{ctx.node.model.class.name.to_s.downcase}"
|
69
|
-
|
69
|
+
logger.info "Posting diff as snippet to #{cfg.channel}"
|
70
70
|
|
71
71
|
@muc.say(title + "\n\n" + diff[:patch].lines.to_a[4..-1].join)
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
75
75
|
rescue Timeout::Error
|
76
|
-
|
76
|
+
logger.info "timed out"
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
data/lib/oxidized/hook.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Oxidized
|
2
2
|
class HookManager
|
3
|
+
include SemanticLogger::Loggable
|
4
|
+
|
3
5
|
class << self
|
4
6
|
def from_config(cfg)
|
5
7
|
mgr = new
|
@@ -14,7 +16,9 @@ module Oxidized
|
|
14
16
|
|
15
17
|
# HookContext is passed to each hook. It can contain anything related to the
|
16
18
|
# event in question. At least it contains the event name
|
17
|
-
|
19
|
+
# The argument keyword_init: true is needed for ruby < 3.2 and can be
|
20
|
+
# dropped with the support of ruby 3.1
|
21
|
+
HookContext = Struct.new(:event, :node, :job, :commitref, keyword_init: true)
|
18
22
|
|
19
23
|
# RegisteredHook is a container for a Hook instance
|
20
24
|
RegisteredHook = Struct.new(:name, :hook)
|
@@ -47,7 +51,7 @@ module Oxidized
|
|
47
51
|
hook.cfg = cfg
|
48
52
|
|
49
53
|
@registered_hooks[event] << RegisteredHook.new(name, hook)
|
50
|
-
|
54
|
+
logger.debug "Hook #{name.inspect} registered #{hook.class} for event #{event.inspect}"
|
51
55
|
end
|
52
56
|
|
53
57
|
def handle(event, ctx_params = {})
|
@@ -57,14 +61,16 @@ module Oxidized
|
|
57
61
|
@registered_hooks[event].each do |r_hook|
|
58
62
|
r_hook.hook.run_hook ctx
|
59
63
|
rescue StandardError => e
|
60
|
-
|
61
|
-
|
64
|
+
logger.error "Hook #{r_hook.name} (#{r_hook.hook}) failed " \
|
65
|
+
"(#{e.inspect}) for event #{event.inspect}"
|
62
66
|
end
|
63
67
|
end
|
64
68
|
end
|
65
69
|
|
66
70
|
# Hook abstract base class
|
67
71
|
class Hook
|
72
|
+
include SemanticLogger::Loggable
|
73
|
+
|
68
74
|
attr_reader :cfg
|
69
75
|
|
70
76
|
def cfg=(cfg)
|
@@ -75,9 +81,5 @@ module Oxidized
|
|
75
81
|
def run_hook(_ctx)
|
76
82
|
raise NotImplementedError
|
77
83
|
end
|
78
|
-
|
79
|
-
def log(msg, level = :info)
|
80
|
-
Oxidized.logger.send(level, "#{self.class.name}: #{msg}")
|
81
|
-
end
|
82
84
|
end
|
83
85
|
end
|
data/lib/oxidized/input/cli.rb
CHANGED
@@ -20,15 +20,16 @@ module Oxidized
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def connect_cli
|
23
|
-
|
23
|
+
logger.debug "Running post_login commands at #{node.name}"
|
24
24
|
@post_login.each do |command, block|
|
25
|
-
|
25
|
+
logger.debug "Running post_login command: #{command.inspect}, " \
|
26
|
+
"block: #{block.inspect} at #{node.name}"
|
26
27
|
block ? block.call : (cmd command)
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
31
|
def disconnect_cli
|
31
|
-
|
32
|
+
logger.debug "Running pre_logout commands at #{node.name}"
|
32
33
|
@pre_logout.each { |command, block| block ? block.call : (cmd command, nil) }
|
33
34
|
end
|
34
35
|
|
@@ -52,6 +53,10 @@ module Oxidized
|
|
52
53
|
@password || (@password = regex)
|
53
54
|
end
|
54
55
|
|
56
|
+
def newline(newline_str = "\n")
|
57
|
+
@newline || (@newline = newline_str)
|
58
|
+
end
|
59
|
+
|
55
60
|
def login
|
56
61
|
match_re = [@node.prompt]
|
57
62
|
match_re << @username if @username
|
data/lib/oxidized/input/exec.rb
CHANGED
@@ -11,7 +11,7 @@ module Oxidized
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def cmd(cmd_str)
|
14
|
-
|
14
|
+
logger.debug "EXEC: #{cmd_str} @ #{@node.name}"
|
15
15
|
# I'd really like to do popen3 with separate arguments, but that would
|
16
16
|
# require refactoring cmd to take parameters
|
17
17
|
%x(#{cmd_str})
|
data/lib/oxidized/input/ftp.rb
CHANGED
@@ -15,7 +15,7 @@ module Oxidized
|
|
15
15
|
}.freeze
|
16
16
|
include Input::CLI
|
17
17
|
|
18
|
-
def connect(node)
|
18
|
+
def connect(node) # rubocop:disable Naming/PredicateMethod
|
19
19
|
@node = node
|
20
20
|
@node.model.cfg['ftp'].each { |cb| instance_exec(&cb) }
|
21
21
|
@log = File.open(Oxidized::Config::LOG + "/#{@node.ip}-ftp", 'w') if Oxidized.config.input.debug?
|
@@ -30,7 +30,7 @@ module Oxidized
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def cmd(file)
|
33
|
-
|
33
|
+
logger.debug "FTP: #{file} @ #{@node.name}"
|
34
34
|
@ftp.getbinaryfile file, nil
|
35
35
|
end
|
36
36
|
|
data/lib/oxidized/input/http.rb
CHANGED
@@ -51,7 +51,7 @@ module Oxidized
|
|
51
51
|
schema = @secure ? "https://" : "http://"
|
52
52
|
uri = URI("#{schema}#{@node.ip}#{path}")
|
53
53
|
|
54
|
-
|
54
|
+
logger.debug "Making request to: #{uri}"
|
55
55
|
|
56
56
|
ssl_verify = Oxidized.config.input.http.ssl_verify? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
57
57
|
|
@@ -59,17 +59,17 @@ module Oxidized
|
|
59
59
|
|
60
60
|
if res.code == '401' && res['www-authenticate']&.include?('Digest')
|
61
61
|
uri.user = @username
|
62
|
-
uri.password = @password
|
63
|
-
|
62
|
+
uri.password = URI.encode_www_form_component(@password)
|
63
|
+
logger.debug "Server requires Digest authentication"
|
64
64
|
auth = Net::HTTP::DigestAuth.new.auth_header(uri, res['www-authenticate'], 'GET')
|
65
65
|
|
66
66
|
res = make_request(uri, ssl_verify, 'Authorization' => auth)
|
67
67
|
elsif @username && @password
|
68
|
-
|
68
|
+
logger.debug "Falling back to Basic authentication"
|
69
69
|
res = make_request(uri, ssl_verify, 'Authorization' => basic_auth_header)
|
70
70
|
end
|
71
71
|
|
72
|
-
|
72
|
+
logger.debug "Response code: #{res.code}"
|
73
73
|
res.body
|
74
74
|
end
|
75
75
|
|
@@ -77,7 +77,7 @@ module Oxidized
|
|
77
77
|
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https", verify_mode: ssl_verify) do |http|
|
78
78
|
req = Net::HTTP::Get.new(uri)
|
79
79
|
@headers.merge(extra_headers).each { |header, value| req.add_field(header, value) }
|
80
|
-
|
80
|
+
logger.debug "Sending request with headers: #{@headers.merge(extra_headers)}"
|
81
81
|
http.request(req)
|
82
82
|
end
|
83
83
|
end
|
data/lib/oxidized/input/input.rb
CHANGED
data/lib/oxidized/input/scp.rb
CHANGED
@@ -16,7 +16,7 @@ module Oxidized
|
|
16
16
|
}.freeze
|
17
17
|
include Input::CLI
|
18
18
|
|
19
|
-
def connect(node)
|
19
|
+
def connect(node) # rubocop:disable Naming/PredicateMethod
|
20
20
|
@node = node
|
21
21
|
@node.model.cfg['scp'].each { |cb| instance_exec(&cb) }
|
22
22
|
@log = File.open(Oxidized::Config::LOG + "/#{@node.ip}-scp", 'w') if Oxidized.config.input.debug?
|
@@ -29,7 +29,7 @@ module Oxidized
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def cmd(file)
|
32
|
-
|
32
|
+
logger.debug "SCP: #{file} @ #{@node.name}"
|
33
33
|
@ssh.scp.download!(file)
|
34
34
|
end
|
35
35
|
|
data/lib/oxidized/input/ssh.rb
CHANGED
@@ -16,7 +16,7 @@ module Oxidized
|
|
16
16
|
include Input::CLI
|
17
17
|
class NoShell < OxidizedError; end
|
18
18
|
|
19
|
-
def connect(node)
|
19
|
+
def connect(node) # rubocop:disable Naming/PredicateMethod
|
20
20
|
@node = node
|
21
21
|
@output = String.new('')
|
22
22
|
@pty_options = { term: "vt100" }
|
@@ -24,10 +24,10 @@ module Oxidized
|
|
24
24
|
if Oxidized.config.input.debug?
|
25
25
|
logfile = Oxidized::Config::LOG + "/#{@node.ip}-ssh"
|
26
26
|
@log = File.open(logfile, 'w')
|
27
|
-
|
27
|
+
logger.debug "I/O Debuging to #{logfile}"
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
logger.debug "Connecting to #{@node.name}"
|
31
31
|
@ssh = Net::SSH.start(@node.ip, @node.auth[:username], make_ssh_opts)
|
32
32
|
unless @exec
|
33
33
|
shell_open @ssh
|
@@ -45,9 +45,9 @@ module Oxidized
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def cmd(cmd, expect = node.prompt)
|
48
|
-
|
48
|
+
logger.debug "Sending '#{cmd.dump}' @ #{node.name} with expect: #{expect.inspect}"
|
49
49
|
if Oxidized.config.input.debug?
|
50
|
-
@log.puts "sent #{cmd.dump}"
|
50
|
+
@log.puts "sent cmd #{@exec ? cmd.dump : (cmd + newline).dump}"
|
51
51
|
@log.flush
|
52
52
|
end
|
53
53
|
cmd_output = if @exec
|
@@ -60,6 +60,10 @@ module Oxidized
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def send(data)
|
63
|
+
if Oxidized.config.input.debug?
|
64
|
+
@log.puts "sent data #{data.dump}"
|
65
|
+
@log.flush
|
66
|
+
end
|
63
67
|
@ses.send_data data
|
64
68
|
end
|
65
69
|
|
@@ -75,8 +79,11 @@ module Oxidized
|
|
75
79
|
disconnect_cli
|
76
80
|
# if disconnect does not disconnect us, give up after timeout
|
77
81
|
Timeout.timeout(Oxidized.config.timeout) { @ssh.loop }
|
78
|
-
rescue Errno::ECONNRESET, Net::SSH::Disconnect, IOError
|
79
|
-
|
82
|
+
rescue Errno::ECONNRESET, Net::SSH::Disconnect, IOError => e
|
83
|
+
logger.debug 'The other side closed the connection while ' \
|
84
|
+
"disconnecting, rasing #{e.class} with #{e.messages}"
|
85
|
+
rescue Timeout::Error
|
86
|
+
logger.debug "#{@node.name} timed out while disconnecting"
|
80
87
|
ensure
|
81
88
|
@log.close if Oxidized.config.input.debug?
|
82
89
|
(@ssh.close rescue true) unless @ssh.closed?
|
@@ -110,7 +117,7 @@ module Oxidized
|
|
110
117
|
|
111
118
|
def cmd_shell(cmd, expect_re)
|
112
119
|
@output = String.new('')
|
113
|
-
@ses.send_data cmd +
|
120
|
+
@ses.send_data cmd + newline
|
114
121
|
@ses.process
|
115
122
|
expect expect_re if expect_re
|
116
123
|
@output
|
@@ -118,7 +125,7 @@ module Oxidized
|
|
118
125
|
|
119
126
|
def expect(*regexps)
|
120
127
|
regexps = [regexps].flatten
|
121
|
-
|
128
|
+
logger.debug "Expecting #{regexps.inspect} at #{node.name}"
|
122
129
|
Timeout.timeout(Oxidized.config.timeout) do
|
123
130
|
@ssh.loop(0.1) do
|
124
131
|
sleep 0.1
|
@@ -145,7 +152,7 @@ module Oxidized
|
|
145
152
|
|
146
153
|
auth_methods = vars(:auth_methods) || %w[none publickey password]
|
147
154
|
ssh_opts[:auth_methods] = auth_methods
|
148
|
-
|
155
|
+
logger.debug "AUTH METHODS::#{auth_methods}"
|
149
156
|
|
150
157
|
ssh_opts[:proxy] = make_ssh_proxy_command(vars(:ssh_proxy), vars(:ssh_proxy_port), secure) if vars(:ssh_proxy)
|
151
158
|
|
@@ -155,10 +162,10 @@ module Oxidized
|
|
155
162
|
ssh_opts[:host_key] = vars(:ssh_host_key).split(/,\s*/) if vars(:ssh_host_key)
|
156
163
|
ssh_opts[:hmac] = vars(:ssh_hmac).split(/,\s*/) if vars(:ssh_hmac)
|
157
164
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
165
|
+
# Use our logger for Net:SSH
|
166
|
+
ssh_logger = SemanticLogger[Net::SSH]
|
167
|
+
ssh_logger.level = Oxidized.config.input.debug? ? :debug : :error
|
168
|
+
ssh_opts[:logger] = ssh_logger
|
162
169
|
|
163
170
|
ssh_opts
|
164
171
|
end
|
@@ -6,7 +6,7 @@ module Oxidized
|
|
6
6
|
include Input::CLI
|
7
7
|
attr_reader :telnet
|
8
8
|
|
9
|
-
def connect(node)
|
9
|
+
def connect(node) # rubocop:disable Naming/PredicateMethod
|
10
10
|
@node = node
|
11
11
|
@timeout = Oxidized.config.timeout
|
12
12
|
@node.model.cfg['telnet'].each { |cb| instance_exec(&cb) }
|
@@ -35,7 +35,7 @@ module Oxidized
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def cmd(cmd_str, expect = @node.prompt)
|
38
|
-
|
38
|
+
logger.debug "Telnet: #{cmd_str} @#{@node.name}"
|
39
39
|
return send(cmd_str + "\r\n") unless expect
|
40
40
|
|
41
41
|
# create a string to be passed to oxidized_expect and modified _there_
|
@@ -78,7 +78,7 @@ module Net
|
|
78
78
|
## FIXME: we also need output (not sure I'm going to support this)
|
79
79
|
attr_reader :output
|
80
80
|
|
81
|
-
def oxidized_expect(options)
|
81
|
+
def oxidized_expect(options)
|
82
82
|
model = @options["Model"]
|
83
83
|
@log = @options["Log"]
|
84
84
|
|
data/lib/oxidized/input/tftp.rb
CHANGED
data/lib/oxidized/job.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
module Oxidized
|
2
2
|
class Job < Thread
|
3
|
+
include SemanticLogger::Loggable
|
4
|
+
|
3
5
|
attr_reader :start, :end, :status, :time, :node, :config
|
4
6
|
|
5
7
|
def initialize(node)
|
6
|
-
@node
|
7
|
-
@start
|
8
|
+
@node = node
|
9
|
+
@start = Time.now.utc
|
10
|
+
self.name = "Oxidized::Job '#{@node.name}'"
|
8
11
|
super do
|
9
|
-
|
12
|
+
logger.debug "Starting fetching process for #{@node.name} at #{Time.now.utc}"
|
10
13
|
@status, @config = @node.run
|
11
14
|
@end = Time.now.utc
|
12
15
|
@time = @end - @start
|
13
|
-
|
16
|
+
logger.debug "Config fetched for #{@node.name} at #{@end}"
|
14
17
|
end
|
15
18
|
end
|
16
19
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'semantic_logger'
|
2
|
+
|
3
|
+
module Oxidized
|
4
|
+
module Logger
|
5
|
+
include SemanticLogger::Loggable
|
6
|
+
|
7
|
+
def self.setup
|
8
|
+
config = Oxidized.config
|
9
|
+
FileUtils.mkdir_p(Config::LOG) unless File.directory?(Config::LOG)
|
10
|
+
|
11
|
+
SemanticLogger.add_signal_handler
|
12
|
+
|
13
|
+
if config.use_syslog?
|
14
|
+
SemanticLogger.add_appender(appender: :syslog)
|
15
|
+
logger.warn("The configuration 'use_syslog' is deprecated. " \
|
16
|
+
"Remove it and use 'logger' instead")
|
17
|
+
elsif config.log?
|
18
|
+
SemanticLogger.add_appender(file_name: File.expand_path(config.log))
|
19
|
+
logger.warn("The configuration 'log' is deprecated. " \
|
20
|
+
"Remove it and use 'logger' instead")
|
21
|
+
elsif config.logger?
|
22
|
+
SemanticLogger.default_level = config.logger.level if config.logger.level?
|
23
|
+
config.logger.appenders.each { |a| add_appender a } if config.logger.has_key?('appenders')
|
24
|
+
end
|
25
|
+
|
26
|
+
# No appenders configured
|
27
|
+
SemanticLogger.add_appender(io: $stderr) if SemanticLogger.appenders.empty?
|
28
|
+
|
29
|
+
return if %i[trace debug].include?(SemanticLogger.default_level)
|
30
|
+
|
31
|
+
SemanticLogger.default_level = :debug if config.debug?
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.add_appender(appender)
|
35
|
+
case appender['type']
|
36
|
+
when 'file'
|
37
|
+
params = { file_name: File.expand_path(appender['file']) }
|
38
|
+
when 'stderr'
|
39
|
+
params = { io: $stderr }
|
40
|
+
when 'stdout'
|
41
|
+
params = { io: $stdout }
|
42
|
+
when 'syslog'
|
43
|
+
params = { appender: :syslog, application: "oxidized" }
|
44
|
+
else
|
45
|
+
raise InvalidConfig, "Unknown logger #{appender['type']}, edit #{Oxidized::Config.configfile}"
|
46
|
+
end
|
47
|
+
params[:level] = appender['level'] if appender.has_key?('level')
|
48
|
+
SemanticLogger.add_appender(**params)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/oxidized/model/acos.rb
CHANGED
@@ -20,6 +20,7 @@ class ACOS < Oxidized::Model
|
|
20
20
|
cfg.gsub! /\s(Memory).*/, ' \\1 <removed>'
|
21
21
|
cfg.gsub! /\s(Current time is).*/, ' \\1 <removed>'
|
22
22
|
cfg.gsub! /\s(The system has been up).*/, ' \\1 <removed>'
|
23
|
+
cfg.gsub! /\s(Hardware: \d+ CPUs\(Stepping \d+\). Single \d+G drive. Free storage is).*/, ' \\1 <removed>'
|
23
24
|
comment cfg
|
24
25
|
end
|
25
26
|
|
data/lib/oxidized/model/aos7.rb
CHANGED
@@ -26,14 +26,23 @@ class AOS7 < Oxidized::Model
|
|
26
26
|
end
|
27
27
|
|
28
28
|
cmd 'show hardware-info' do |cfg|
|
29
|
+
# Remove extra lines occuring when the command runs slow
|
30
|
+
cfg.gsub! /^Please wait...\n/, ''
|
31
|
+
cfg.gsub! /^\n\n\n/, "\n\n"
|
29
32
|
comment cfg
|
30
33
|
end
|
31
34
|
|
32
35
|
cmd 'show running-directory' do |cfg|
|
36
|
+
# Remove extra lines occuring when the command runs slow
|
37
|
+
cfg.gsub! /^Please wait...\n/, ''
|
38
|
+
cfg.gsub! /^\n\n/, "\n"
|
33
39
|
comment cfg
|
34
40
|
end
|
35
41
|
|
36
42
|
cmd 'show configuration snapshot' do |cfg|
|
43
|
+
# Remove extra lines occuring when the command runs slow
|
44
|
+
cfg.gsub! /^Please wait...\n/, ''
|
45
|
+
cfg.gsub! /^\n\n/, "\n"
|
37
46
|
cfg
|
38
47
|
end
|
39
48
|
|
data/lib/oxidized/model/aoscx.rb
CHANGED
@@ -58,6 +58,8 @@ class Aoscx < Oxidized::Model
|
|
58
58
|
cfg.gsub! /^(\d\/\d\/\d.*\s+)\d+\s+$/, '\\1<hidden>'
|
59
59
|
cfg.gsub! /^(\d+\/?\S+\s+\S+\s+)\d+\.\d+\s+C\s+(.*)/, '\\1<hidden> \\2'
|
60
60
|
cfg.gsub! /^(LC.*\s+)\d+\.\d+\s+(C.*)$/, '\\1 <hidden> \\2'
|
61
|
+
# match show environment No speed shown for switches CX83xx, e.g. "PSU-1/1/1 N/A N/A N/A front-to-back ok 7360"
|
62
|
+
cfg.gsub! /^PSU(\S+\s+\S+\s+\s+\S+\s+)(slow|normal|medium|fast|max|N\/A)\s+(\S+\s+\S+\s+)\d+[[:blank:]]+/, '\\1<speed> \\3<rpm>'
|
61
63
|
cfg.gsub! /^(\S+\s+\S+\s+\s+\S+\s+)(slow|normal|medium|fast|max)\s+(\S+\s+\S+\s+)\d+[[:blank:]]+/, '\\1<speed> \\3<rpm>'
|
62
64
|
# match show environment power-consumption on VSF or standadlone, non-chassis and non-6400 switch, e.g. "2 6300M 48G 4SFP56 Swch 156.00 155.94"
|
63
65
|
cfg.gsub! /^(\d+\s+.+\s+)(\s{2}\d{2}\.\d{2}|\s{1}\d{3}\.\d{2}|\d{4}\.\d{2})(\s+)(\s{2}\d{2}\.\d{2}|\s{1}\d{3}\.\d{2}|\d{4}\.\d{2})$/, '\\1<power>\\3<power>'
|
data/lib/oxidized/model/aosw.rb
CHANGED
@@ -25,24 +25,25 @@ class AOSW < Oxidized::Model
|
|
25
25
|
end
|
26
26
|
|
27
27
|
cmd :secret do |cfg|
|
28
|
-
cfg.gsub!(/secret (\S+)
|
29
|
-
cfg.gsub!(/enable secret (\S+)
|
30
|
-
cfg.gsub!(/PRE-SHARE (\S+)
|
31
|
-
cfg.gsub!(/ipsec (\S+)
|
32
|
-
cfg.gsub!(/community (\S+)
|
28
|
+
cfg.gsub!(/secret (\S+)\s?$/, 'secret <secret removed>')
|
29
|
+
cfg.gsub!(/enable secret (\S+)\s?$/, 'enable secret <secret removed>')
|
30
|
+
cfg.gsub!(/PRE-SHARE (\S+)\s?$/, 'PRE-SHARE <secret removed>')
|
31
|
+
cfg.gsub!(/ipsec (\S+)\s?$/, 'ipsec <secret removed>')
|
32
|
+
cfg.gsub!(/community (\S+)\s?$/, 'community <secret removed>')
|
33
33
|
cfg.gsub!(/ sha (\S+)/, ' sha <secret removed>')
|
34
34
|
cfg.gsub!(/ des (\S+)/, ' des <secret removed>')
|
35
35
|
cfg.gsub!(/mobility-manager (\S+) user (\S+) (\S+)/, 'mobility-manager \1 user \2 <secret removed>')
|
36
|
-
cfg.gsub!(/mgmt-user (\S+) (root|guest-provisioning|network-operations|read-only|location-api-mgmt) (\S+)
|
37
|
-
cfg.gsub!(/mgmt-user (\S+) (\S+)( (read-only|guest-mgmt))?$/, 'mgmt-user \1 <secret removed> \3') # IAP
|
36
|
+
cfg.gsub!(/mgmt-user (\S+) (root|guest-provisioning|network-operations|read-only|location-api-mgmt) (\S+)\s?$/, 'mgmt-user \1 \2 <secret removed>') # MAS & Wireless Controler
|
37
|
+
cfg.gsub!(/mgmt-user (\S+) (\S+)( (read-only|guest-mgmt))?\s?$/, 'mgmt-user \1 <secret removed> \3') # IAP
|
38
38
|
# MAS format: mgmt-user <username> <accesslevel> <password hash>
|
39
39
|
# IAP format (root user): mgmt-user <username> <password hash>
|
40
40
|
# IAP format: mgmt-user <username> <password hash> <access level>
|
41
|
-
cfg.gsub!(/key (\S+)
|
42
|
-
cfg.gsub!(/
|
43
|
-
cfg.gsub!(/
|
44
|
-
cfg.gsub!(/
|
45
|
-
cfg.gsub!(/
|
41
|
+
cfg.gsub!(/key (\S+)\s?$/, 'key <secret removed>')
|
42
|
+
cfg.gsub!(/vrrp-passphrase (\S+)\s?$/, 'vrrp-passphrase <secret removed>')
|
43
|
+
cfg.gsub!(/wpa-passphrase (\S+)\s?$/, 'wpa-passphrase <secret removed>')
|
44
|
+
cfg.gsub!(/bkup-passwords (\S+)\s?$/, 'bkup-passwords <secret removed>')
|
45
|
+
cfg.gsub!(/ap-console-password (\S+)\s?$/, 'ap-console-password <secret removed>')
|
46
|
+
cfg.gsub!(/virtual-controller-key (\S+)\s?$/, 'virtual-controller-key <secret removed>')
|
46
47
|
cfg
|
47
48
|
end
|
48
49
|
|
@@ -52,22 +53,26 @@ class AOSW < Oxidized::Model
|
|
52
53
|
end
|
53
54
|
|
54
55
|
cmd 'show inventory' do |cfg|
|
55
|
-
|
56
|
+
# Don't show for unsupported devices (IAP and MAS)
|
57
|
+
cfg = "" if cfg =~ /(Invalid input detected at '\^' marker|Parse error)/
|
56
58
|
rstrip_cfg clean cfg
|
57
59
|
end
|
58
60
|
|
59
61
|
cmd 'show slots' do |cfg|
|
60
|
-
|
62
|
+
# Don't show for unsupported devices (IAP and MAS)
|
63
|
+
cfg = "" if cfg =~ /(Invalid input detected at '\^' marker|Parse error)/
|
61
64
|
rstrip_cfg comment cfg
|
62
65
|
end
|
63
66
|
|
64
67
|
cmd 'show license' do |cfg|
|
65
|
-
|
68
|
+
# Don't show for unsupported devices (IAP and MAS)
|
69
|
+
cfg = "" if cfg =~ /(Invalid input detected at '\^' marker|Parse error)/
|
66
70
|
rstrip_cfg comment cfg
|
67
71
|
end
|
68
72
|
|
69
73
|
cmd 'show license passphrase' do |cfg|
|
70
|
-
|
74
|
+
# Don't show for unsupported devices (IAP and MAS)
|
75
|
+
cfg = "" if cfg.match /(Invalid input detected at '\^' marker|Parse error)/
|
71
76
|
rstrip_cfg comment cfg
|
72
77
|
end
|
73
78
|
|
@@ -117,7 +122,7 @@ class AOSW < Oxidized::Model
|
|
117
122
|
next if line =~ /Output \d Config/i
|
118
123
|
next if line =~ /(Tachometers|Temperatures|Voltages)/
|
119
124
|
next if line =~ /((Card|CPU) Temperature|Chassis Fan|VMON1[0-9])/
|
120
|
-
next if line =~ /[0-9]
|
125
|
+
next if line =~ /[0-9.]{1,6}\s+(RPMS?|m?V|C|W)/i
|
121
126
|
|
122
127
|
out << line.strip
|
123
128
|
end
|
@@ -37,7 +37,7 @@ class AricentISS < Oxidized::Model
|
|
37
37
|
cmd 'show system information' do |cfg|
|
38
38
|
cfg.sub! /^Device Up Time.*\n/, ''
|
39
39
|
cfg.delete! "\r"
|
40
|
-
comment(cfg).
|
40
|
+
comment(cfg).rstrip
|
41
41
|
end
|
42
42
|
|
43
43
|
cmd 'show running-config' do |cfg|
|
@@ -53,6 +53,6 @@ class AricentISS < Oxidized::Model
|
|
53
53
|
end
|
54
54
|
|
55
55
|
l
|
56
|
-
end.join.
|
56
|
+
end.join.rstrip
|
57
57
|
end
|
58
58
|
end
|
data/lib/oxidized/model/asa.rb
CHANGED
@@ -16,8 +16,7 @@ class ASA < Oxidized::Model
|
|
16
16
|
cfg.gsub! /^passwd (\S+) (.*)/, 'passwd <secret hidden> \2'
|
17
17
|
cfg.gsub! /username (\S+) password (\S+) (.*)/, 'username \1 password <secret hidden> \3'
|
18
18
|
cfg.gsub! /(ikev[12] ((remote|local)-authentication )?pre-shared-key( hex)?) (\S+)/, '\1 <secret hidden>'
|
19
|
-
cfg.gsub! /^(aaa-server
|
20
|
-
cfg.gsub! /^(aaa-server \S+ \(\S+\) host[^\n]*\n(\s+[^\n]+\n)*\s+key) \S+$/mi, '\1 <secret hidden>'
|
19
|
+
cfg.gsub! /^(aaa-server \S+(?: \(\S+\))? host \S+\n(?: [^\n]+\n)* +key) \S+$/mi, '\1 <secret hidden>'
|
21
20
|
cfg.gsub! /ldap-login-password (\S+)/, 'ldap-login-password <secret hidden>'
|
22
21
|
cfg.gsub! /^snmp-server host (.*) community (\S+)/, 'snmp-server host \1 community <secret hidden>'
|
23
22
|
cfg.gsub! /^(failover key) .+/, '\1 <secret hidden>'
|
@@ -97,7 +96,8 @@ class ASA < Oxidized::Model
|
|
97
96
|
contexts = systemcfg.scan(/^context (\S+)$/)
|
98
97
|
files = systemcfg.scan(/config-url (\S+)$/)
|
99
98
|
contexts.each_with_index do |cont, i|
|
100
|
-
allcfg = allcfg + "\n\n----------========== [ CONTEXT " + cont.join(" ") +
|
99
|
+
allcfg = allcfg + "\n\n----------========== [ CONTEXT " + cont.join(" ") +
|
100
|
+
" FILE " + files[i].join(" ") + " ] ==========----------\n\n"
|
101
101
|
cmd "more " + files[i].join(" ") do |cfgcontext|
|
102
102
|
allcfg = allcfg + "\n\n" + cfgcontext
|
103
103
|
end
|
@@ -61,25 +61,28 @@ class AWPlus < Oxidized::Model
|
|
61
61
|
cfg
|
62
62
|
end
|
63
63
|
|
64
|
-
# Config required for telnet to detect username prompt
|
64
|
+
# Config required for telnet to detect username & password prompt.
|
65
65
|
cfg :telnet do
|
66
66
|
username /login:\s/
|
67
|
+
password /^Password:\s/
|
67
68
|
end
|
68
69
|
|
69
|
-
#
|
70
|
+
# Config required for ssh to specify newline characters.
|
70
71
|
cfg :telnet, :ssh do
|
72
|
+
newline "\r\n"
|
73
|
+
|
71
74
|
post_login do
|
72
|
-
if vars
|
73
|
-
|
74
|
-
|
75
|
-
cmd
|
76
|
-
|
77
|
-
cmd 'enable' # Required for Priv-Exec users without enable PW to be put into "enable mode".
|
75
|
+
if vars(:enable) == true
|
76
|
+
cmd "enable"
|
77
|
+
elsif vars(:enable)
|
78
|
+
cmd "enable", /^[pP]assword:/
|
79
|
+
cmd vars(:enable)
|
78
80
|
end
|
79
|
-
#
|
81
|
+
# cmd 'terminal length 0' # set so the entire config is output without intervention.
|
80
82
|
end
|
83
|
+
|
81
84
|
pre_logout do
|
82
|
-
#
|
85
|
+
# cmd 'terminal no length' # sets term length back to default on exit.
|
83
86
|
send "exit\r\n"
|
84
87
|
end
|
85
88
|
end
|