oxidized 0.33.0 → 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 +4 -1
- data/.github/ISSUE_TEMPLATE/support-request.md +4 -1
- data/.github/workflows/ruby.yml +4 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +29 -6
- data/.rubocop_todo.yml +2 -35
- data/CHANGELOG.md +49 -0
- data/CONTRIBUTING.md +10 -3
- data/Dockerfile +4 -4
- data/README.md +52 -55
- data/Rakefile +2 -3
- data/docs/Configuration.md +97 -0
- data/docs/DeviceSimulation.md +19 -7
- data/docs/Docker.md +9 -4
- data/docs/Issues.md +11 -2
- data/docs/ModelUnitTests.md +35 -25
- data/docs/Outputs.md +83 -2
- data/docs/Release.md +30 -22
- data/docs/Supported-OS-Types.md +4 -0
- data/docs/Troubleshooting.md +4 -18
- data/extra/device2yaml.rb +24 -9
- data/extra/rest_client.rb +2 -1
- data/extra/syslog.rb +8 -3
- data/lib/oxidized/cli.rb +7 -3
- data/lib/oxidized/config/vars.rb +7 -3
- data/lib/oxidized/config.rb +0 -1
- data/lib/oxidized/core.rb +5 -4
- 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 +5 -5
- 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 +6 -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/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 +2 -1
- data/lib/oxidized/model/gaiaos.rb +4 -4
- data/lib/oxidized/model/ios.rb +15 -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 +2 -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/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/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 +7 -5
- 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 +66 -9
- data/lib/oxidized/output/gitcrypt.rb +15 -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 +2 -2
- data/lib/oxidized/worker.rb +11 -8
- data/lib/oxidized.rb +3 -24
- data/oxidized.gemspec +8 -5
- metadata +54 -21
data/lib/oxidized/cli.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require 'semantic_logger'
|
2
|
+
|
1
3
|
module Oxidized
|
2
4
|
class CLI
|
5
|
+
include SemanticLogger::Loggable
|
6
|
+
|
3
7
|
require 'slop'
|
4
8
|
require 'oxidized'
|
5
9
|
require 'English'
|
@@ -9,7 +13,7 @@ module Oxidized
|
|
9
13
|
Process.daemon if @opts[:daemonize]
|
10
14
|
write_pid
|
11
15
|
begin
|
12
|
-
|
16
|
+
logger.info "Oxidized starting, running as pid #{$PROCESS_ID}"
|
13
17
|
Oxidized.new
|
14
18
|
rescue StandardError => e
|
15
19
|
crash e
|
@@ -23,13 +27,13 @@ module Oxidized
|
|
23
27
|
_args, @opts = parse_opts
|
24
28
|
|
25
29
|
Config.load(@opts)
|
26
|
-
Oxidized.
|
30
|
+
Oxidized::Logger.setup
|
27
31
|
|
28
32
|
@pidfile = File.expand_path(Oxidized.config.pid)
|
29
33
|
end
|
30
34
|
|
31
35
|
def crash(error)
|
32
|
-
|
36
|
+
logger.fatal "Oxidized crashed, crashfile written in #{Config::CRASH}"
|
33
37
|
File.open Config::CRASH, 'w' do |file|
|
34
38
|
file.puts '-' * 50
|
35
39
|
file.puts Time.now.utc
|
data/lib/oxidized/config/vars.rb
CHANGED
@@ -6,11 +6,15 @@ module Oxidized
|
|
6
6
|
model_name = @node.model.class.name.to_s.downcase
|
7
7
|
if @node.vars&.has_key?(name)
|
8
8
|
@node.vars[name]
|
9
|
-
elsif Oxidized.config.groups.has_key?(@node.group) &&
|
9
|
+
elsif Oxidized.config.groups.has_key?(@node.group) &&
|
10
|
+
Oxidized.config.groups[@node.group].models.has_key(model_name) &&
|
11
|
+
Oxidized.config.groups[@node.group].models[model_name].vars.has_key?(name.to_s)
|
10
12
|
Oxidized.config.groups[@node.group].models[model_name].vars[name.to_s]
|
11
|
-
elsif Oxidized.config.groups.has_key?(@node.group) &&
|
13
|
+
elsif Oxidized.config.groups.has_key?(@node.group) &&
|
14
|
+
Oxidized.config.groups[@node.group].vars.has_key?(name.to_s)
|
12
15
|
Oxidized.config.groups[@node.group].vars[name.to_s]
|
13
|
-
elsif Oxidized.config.models.has_key(model_name) &&
|
16
|
+
elsif Oxidized.config.models.has_key(model_name) &&
|
17
|
+
Oxidized.config.models[model_name].vars.has_key?(name.to_s)
|
14
18
|
Oxidized.config.models[model_name].vars[name.to_s]
|
15
19
|
elsif Oxidized.config.vars.has_key?(name.to_s)
|
16
20
|
Oxidized.config.vars[name.to_s]
|
data/lib/oxidized/config.rb
CHANGED
@@ -27,7 +27,6 @@ module Oxidized
|
|
27
27
|
asetus.default.model = 'junos'
|
28
28
|
asetus.default.resolve_dns = true # if false, don't resolve DNS to IP
|
29
29
|
asetus.default.interval = 3600
|
30
|
-
asetus.default.use_syslog = false
|
31
30
|
asetus.default.debug = false
|
32
31
|
asetus.default.run_once = false
|
33
32
|
asetus.default.threads = 30
|
data/lib/oxidized/core.rb
CHANGED
@@ -6,6 +6,8 @@ module Oxidized
|
|
6
6
|
end
|
7
7
|
|
8
8
|
class Core
|
9
|
+
include SemanticLogger::Loggable
|
10
|
+
|
9
11
|
class NoNodesFound < OxidizedError; end
|
10
12
|
|
11
13
|
def initialize(_args)
|
@@ -33,7 +35,7 @@ module Oxidized
|
|
33
35
|
|
34
36
|
# Initialize oxidized-web if requested
|
35
37
|
if Oxidized.config.has_key? 'rest'
|
36
|
-
|
38
|
+
logger.warn(
|
37
39
|
'configuration: "rest" is deprecated. Migrate to ' \
|
38
40
|
'"extensions.oxidized-web" and remove "rest" from the configuration'
|
39
41
|
)
|
@@ -61,14 +63,13 @@ module Oxidized
|
|
61
63
|
private
|
62
64
|
|
63
65
|
def reload
|
64
|
-
|
66
|
+
logger.info("Reloading node list")
|
65
67
|
@worker.reload
|
66
|
-
Oxidized.logger.reopen
|
67
68
|
@need_reload = false
|
68
69
|
end
|
69
70
|
|
70
71
|
def run
|
71
|
-
|
72
|
+
logger.debug "Starting the worker..."
|
72
73
|
loop do
|
73
74
|
reload if @need_reload
|
74
75
|
@worker.work
|
@@ -14,30 +14,32 @@ class CiscoSparkDiff < Oxidized::Hook
|
|
14
14
|
return unless ctx.node
|
15
15
|
return unless ctx.event.to_s == "post_store"
|
16
16
|
|
17
|
-
|
17
|
+
logger.info "Connecting to Cisco Spark"
|
18
18
|
CiscoSpark.configure do |config|
|
19
19
|
config.api_key = cfg.accesskey
|
20
20
|
config.proxy = cfg.proxy if cfg.has_key?('proxy')
|
21
21
|
end
|
22
22
|
room = CiscoSpark::Room.new(id: cfg.space)
|
23
|
-
|
23
|
+
logger.info "Connected"
|
24
24
|
|
25
25
|
if cfg.has_key?("diff") ? cfg.diff : true
|
26
26
|
gitoutput = ctx.node.output.new
|
27
27
|
diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil
|
28
28
|
title = ctx.node.name.to_s
|
29
|
-
|
30
|
-
room.send_message CiscoSpark::Message.new(text:
|
29
|
+
logger.info "Posting diff as snippet to #{cfg.space}"
|
30
|
+
room.send_message CiscoSpark::Message.new(text: "Device #{title} modified:\n" +
|
31
|
+
diff[:patch].lines.to_a[4..-1].join)
|
31
32
|
end
|
32
33
|
|
33
34
|
if cfg.message?
|
34
|
-
|
35
|
-
msg = cfg.message % { node: ctx.node.name.to_s, group: ctx.node.group.to_s, commitref: ctx.commitref,
|
36
|
-
|
37
|
-
|
35
|
+
logger.info cfg.message
|
36
|
+
msg = cfg.message % { node: ctx.node.name.to_s, group: ctx.node.group.to_s, commitref: ctx.commitref,
|
37
|
+
model: ctx.node.model.class.name.to_s.downcase }
|
38
|
+
logger.info msg
|
39
|
+
logger.info "Posting message to #{cfg.space}"
|
38
40
|
room.send_message CiscoSpark::Message.new(text: msg)
|
39
41
|
end
|
40
42
|
|
41
|
-
|
43
|
+
logger.info "Finished"
|
42
44
|
end
|
43
45
|
end
|
data/lib/oxidized/hook/exec.rb
CHANGED
@@ -28,7 +28,7 @@ class Exec < Oxidized::Hook
|
|
28
28
|
|
29
29
|
def run_hook(ctx)
|
30
30
|
env = make_env ctx
|
31
|
-
|
31
|
+
logger.debug "Execute: #{@cmd.inspect}"
|
32
32
|
th = Thread.new do
|
33
33
|
run_cmd! env
|
34
34
|
rescue StandardError => e
|
@@ -38,20 +38,21 @@ class Exec < Oxidized::Hook
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def run_cmd!(env)
|
41
|
-
pid
|
41
|
+
pid = nil
|
42
|
+
status = nil
|
42
43
|
Timeout.timeout(@timeout) do
|
43
44
|
pid = spawn env, @cmd, unsetenv_others: true
|
44
45
|
pid, status = wait2 pid
|
45
46
|
unless status.exitstatus.zero?
|
46
47
|
msg = "#{@cmd.inspect} failed with exit value #{status.exitstatus}"
|
47
|
-
|
48
|
+
logger.error msg
|
48
49
|
raise msg
|
49
50
|
end
|
50
51
|
end
|
51
52
|
rescue Timeout::Error
|
52
53
|
kill "TERM", pid
|
53
54
|
msg = "#{@cmd} timed out"
|
54
|
-
|
55
|
+
logger.error msg
|
55
56
|
raise Timeout::Error, msg
|
56
57
|
end
|
57
58
|
|
@@ -6,8 +6,13 @@ class GithubRepo < Oxidized::Hook
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def run_hook(ctx)
|
9
|
+
unless ctx.node
|
10
|
+
logger.error 'GithubRepo.run_hook: no node provided'
|
11
|
+
return
|
12
|
+
end
|
13
|
+
|
9
14
|
unless ctx.node.repo
|
10
|
-
|
15
|
+
logger.error "Oxidized output is not git, can't push to remote"
|
11
16
|
return
|
12
17
|
end
|
13
18
|
repo = Rugged::Repository.new(ctx.node.repo)
|
@@ -15,12 +20,11 @@ class GithubRepo < Oxidized::Hook
|
|
15
20
|
url = remote_repo(ctx.node)
|
16
21
|
|
17
22
|
if url.nil? || url.empty?
|
18
|
-
|
23
|
+
logger.error "No repository defined for #{ctx.node.group}/#{ctx.node.name}"
|
19
24
|
return
|
20
25
|
end
|
21
26
|
|
22
|
-
|
23
|
-
log "to remote: #{url}"
|
27
|
+
logger.info "Pushing local repository(#{repo.path}) to remote: #{url}"
|
24
28
|
|
25
29
|
if repo.remotes['origin'].nil?
|
26
30
|
repo.remotes.create('origin', url)
|
@@ -34,10 +38,10 @@ class GithubRepo < Oxidized::Hook
|
|
34
38
|
remote.push([repo.head.name], credentials: creds)
|
35
39
|
rescue Rugged::NetworkError => e
|
36
40
|
if e.message == 'unsupported URL protocol'
|
37
|
-
|
41
|
+
logger.warn "Rugged does not support the git URL '#{url}'."
|
38
42
|
unless Rugged.features.include?(:ssh)
|
39
|
-
|
40
|
-
|
43
|
+
logger.warn "Note: Rugged isn't installed with ssh support. You may need " \
|
44
|
+
'"gem install rugged -- --with-ssh"'
|
41
45
|
end
|
42
46
|
end
|
43
47
|
# re-raise exception for the calling method
|
@@ -47,28 +51,28 @@ class GithubRepo < Oxidized::Hook
|
|
47
51
|
|
48
52
|
def fetch_and_merge_remote(repo, creds)
|
49
53
|
result = repo.fetch('origin', [repo.head.name], credentials: creds)
|
50
|
-
|
54
|
+
logger.debug result.inspect
|
51
55
|
|
52
56
|
their_branch = remote_branch(repo)
|
53
57
|
|
54
58
|
unless their_branch
|
55
|
-
|
59
|
+
logger.debug 'remote branch does not exist yet, nothing to merge'
|
56
60
|
return
|
57
61
|
end
|
58
62
|
|
59
63
|
result = repo.merge_analysis(their_branch.target_id)
|
60
64
|
|
61
65
|
if result.include? :up_to_date
|
62
|
-
|
66
|
+
logger.debug 'nothing to merge'
|
63
67
|
return
|
64
68
|
end
|
65
69
|
|
66
|
-
|
70
|
+
logger.debug "merging fetched branch #{their_branch.name}"
|
67
71
|
|
68
72
|
merge_index = repo.merge_commits(repo.head.target_id, their_branch.target_id)
|
69
73
|
|
70
74
|
if merge_index.conflicts?
|
71
|
-
|
75
|
+
logger.warn "Conflicts detected, skipping Rugged::Commit.create"
|
72
76
|
return
|
73
77
|
end
|
74
78
|
|
@@ -85,18 +89,20 @@ class GithubRepo < Oxidized::Hook
|
|
85
89
|
Proc.new do |_url, username_from_url, _allowed_types| # rubocop:disable Style/Proc
|
86
90
|
git_user = cfg.has_key?('username') ? cfg.username : (username_from_url || 'git')
|
87
91
|
if cfg.has_key?('password')
|
88
|
-
|
92
|
+
logger.debug "Authenticating using username and password as '#{git_user}'"
|
89
93
|
Rugged::Credentials::UserPassword.new(username: git_user, password: cfg.password)
|
90
94
|
elsif cfg.has_key?('privatekey')
|
91
95
|
pubkey = cfg.has_key?('publickey') ? cfg.publickey : nil
|
92
|
-
|
96
|
+
logger.debug "Authenticating using ssh keys as '#{git_user}'"
|
93
97
|
rugged_sshkey(git_user: git_user, privkey: cfg.privatekey, pubkey: pubkey)
|
94
|
-
elsif cfg.has_key?('remote_repo') &&
|
98
|
+
elsif cfg.has_key?('remote_repo') &&
|
99
|
+
cfg.remote_repo.has_key?(node.group) &&
|
100
|
+
cfg.remote_repo[node.group].has_key?('privatekey')
|
95
101
|
pubkey = cfg.remote_repo[node.group].has_key?('publickey') ? cfg.remote_repo[node.group].publickey : nil
|
96
|
-
|
102
|
+
logger.debug "Authenticating using ssh keys as '#{git_user}' for '#{node.group}/#{node.name}'"
|
97
103
|
rugged_sshkey(git_user: git_user, privkey: cfg.remote_repo[node.group].privatekey, pubkey: pubkey)
|
98
104
|
else
|
99
|
-
|
105
|
+
logger.debug "Authenticating using ssh agent as '#{git_user}'"
|
100
106
|
Rugged::Credentials::SshKeyFromAgent.new(username: git_user)
|
101
107
|
end
|
102
108
|
end
|
@@ -12,7 +12,7 @@ class SlackDiff < Oxidized::Hook
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def slack_upload(client, title, content, channel)
|
15
|
-
|
15
|
+
logger.info "Posting diff as snippet to #{channel}"
|
16
16
|
upload_dest = client.files_getUploadURLExternal(filename: "change",
|
17
17
|
length: content.length,
|
18
18
|
snippet_type: "diff")
|
@@ -39,14 +39,14 @@ class SlackDiff < Oxidized::Hook
|
|
39
39
|
return unless ctx.node
|
40
40
|
return unless ctx.event.to_s == "post_store"
|
41
41
|
|
42
|
-
|
42
|
+
logger.info "Connecting to slack"
|
43
43
|
Slack::Web::Client.configure do |config|
|
44
44
|
config.token = cfg.token
|
45
45
|
config.proxy = cfg.proxy if cfg.has_key?('proxy')
|
46
46
|
end
|
47
47
|
client = Slack::Web::Client.new
|
48
48
|
client.auth_test
|
49
|
-
|
49
|
+
logger.info "Connected"
|
50
50
|
if cfg.has_key?("diff") ? cfg.diff : true
|
51
51
|
gitoutput = ctx.node.output.new
|
52
52
|
diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil
|
@@ -58,12 +58,13 @@ class SlackDiff < Oxidized::Hook
|
|
58
58
|
end
|
59
59
|
# message custom formatted - optional
|
60
60
|
if cfg.message?
|
61
|
-
|
62
|
-
msg = cfg.message % { node: ctx.node.name.to_s, group: ctx.node.group.to_s, commitref: ctx.commitref,
|
63
|
-
|
64
|
-
|
61
|
+
logger.info cfg.message
|
62
|
+
msg = cfg.message % { node: ctx.node.name.to_s, group: ctx.node.group.to_s, commitref: ctx.commitref,
|
63
|
+
model: ctx.node.model.class.name.to_s.downcase }
|
64
|
+
logger.info msg
|
65
|
+
logger.info "Posting message to #{cfg.channel}"
|
65
66
|
client.chat_postMessage(channel: cfg.channel, text: msg, as_user: true)
|
66
67
|
end
|
67
|
-
|
68
|
+
logger.info "Finished"
|
68
69
|
end
|
69
70
|
end
|
@@ -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
|
|
@@ -60,16 +60,16 @@ module Oxidized
|
|
60
60
|
if res.code == '401' && res['www-authenticate']&.include?('Digest')
|
61
61
|
uri.user = @username
|
62
62
|
uri.password = URI.encode_www_form_component(@password)
|
63
|
-
|
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
|
|