oxidized 0.35.0 → 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/workflows/publishdocker.yml +11 -9
- data/.github/workflows/ruby.yml +1 -3
- data/.rubocop.yml +16 -2
- data/.rubocop_todo.yml +21 -2
- data/CHANGELOG.md +76 -3
- data/README.md +2 -3
- data/Rakefile +1 -1
- data/docs/Configuration.md +40 -2
- data/docs/Creating-Models.md +129 -14
- data/docs/Docker.md +2 -1
- data/docs/Hooks.md +92 -67
- data/docs/Inputs.md +44 -12
- data/docs/Model-Notes/APC.md +72 -0
- data/docs/Model-Notes/ExaLink.md +43 -0
- data/docs/Model-Notes/Fortinet.md +75 -0
- data/docs/Model-Notes/GrandstreamHT8xx.md +8 -0
- data/docs/Model-Notes/IvantiConnectSecure.md +59 -0
- data/docs/Model-Notes/RouterOS.md +13 -0
- data/docs/Model-Notes/TrueNAS.md +23 -0
- data/docs/ModelUnitTests.md +23 -0
- data/docs/Outputs.md +18 -4
- data/docs/Release.md +7 -2
- data/docs/Ruby-API.md +86 -5
- data/docs/Supported-OS-Types.md +21 -9
- data/docs/Troubleshooting.md +1 -1
- data/extra/device2yaml.rb +2 -3
- data/extra/hooks/modelrules.rb +55 -0
- data/extra/hooks/modelrulesadvanced.rb +167 -0
- data/extra/hooks/srcipmap.rb +54 -0
- data/lib/oxidized/cli/support.rb +152 -0
- data/lib/oxidized/cli.rb +9 -0
- data/lib/oxidized/hook/githubrepo.rb +2 -1
- data/lib/oxidized/hook.rb +58 -8
- data/lib/oxidized/input/debugtext.rb +40 -0
- data/lib/oxidized/input/debugyaml.rb +82 -0
- data/lib/oxidized/input/exec.rb +1 -10
- data/lib/oxidized/input/ftp.rb +0 -17
- data/lib/oxidized/input/http.rb +39 -21
- data/lib/oxidized/input/input.rb +33 -13
- data/lib/oxidized/input/scp.rb +10 -64
- data/lib/oxidized/input/ssh.rb +36 -79
- data/lib/oxidized/input/sshbase.rb +102 -0
- data/lib/oxidized/input/telnet.rb +12 -13
- data/lib/oxidized/input/tftp.rb +7 -7
- data/lib/oxidized/model/aoscx.rb +18 -12
- data/lib/oxidized/model/aosw.rb +10 -11
- data/lib/oxidized/model/apc_aos.rb +4 -0
- data/lib/oxidized/model/apcaos.rb +39 -0
- data/lib/oxidized/model/arubainstant.rb +11 -20
- data/lib/oxidized/model/asa.rb +7 -7
- data/lib/oxidized/model/comware.rb +3 -1
- data/lib/oxidized/model/cumulus.rb +3 -3
- data/lib/oxidized/model/defacto.rb +26 -0
- data/lib/oxidized/model/dlinknextgen.rb +1 -0
- data/lib/oxidized/model/dslcommands.rb +93 -0
- data/lib/oxidized/model/dslsetup.rb +102 -0
- data/lib/oxidized/model/efos.rb +5 -5
- data/lib/oxidized/model/exalink.rb +36 -0
- data/lib/oxidized/model/fastiron.rb +2 -2
- data/lib/oxidized/model/firelinuxos.rb +1 -3
- data/lib/oxidized/model/fortigate.rb +160 -0
- data/lib/oxidized/model/fortios.rb +28 -69
- data/lib/oxidized/model/fsos.rb +1 -3
- data/lib/oxidized/model/grandstreamht8xx.rb +19 -0
- data/lib/oxidized/model/h3c.rb +1 -1
- data/lib/oxidized/model/ios.rb +23 -15
- data/lib/oxidized/model/ironware.rb +5 -3
- data/lib/oxidized/model/ivanti.rb +54 -0
- data/lib/oxidized/model/junos.rb +2 -2
- data/lib/oxidized/model/linuxgeneric.rb +4 -2
- data/lib/oxidized/model/macros.rb +60 -0
- data/lib/oxidized/model/mlnxos.rb +11 -7
- data/lib/oxidized/model/model.rb +28 -126
- data/lib/oxidized/model/ndms.rb +6 -0
- data/lib/oxidized/model/netgear.rb +5 -3
- data/lib/oxidized/model/nxos.rb +6 -3
- data/lib/oxidized/model/outputs.rb +5 -0
- data/lib/oxidized/model/perle.rb +14 -8
- data/lib/oxidized/model/routeros.rb +4 -0
- data/lib/oxidized/model/smartbyte.rb +48 -0
- data/lib/oxidized/model/tplink.rb +4 -6
- data/lib/oxidized/model/truenas.rb +63 -3
- data/lib/oxidized/model/voss.rb +3 -0
- data/lib/oxidized/model/vyos.rb +4 -1
- data/lib/oxidized/node.rb +25 -23
- data/lib/oxidized/nodes.rb +2 -0
- data/lib/oxidized/output/file.rb +7 -1
- data/lib/oxidized/output/git.rb +11 -1
- data/lib/oxidized/output/gitcrypt.rb +1 -1
- data/lib/oxidized/output/http.rb +12 -3
- data/lib/oxidized/source/csv.rb +5 -0
- data/lib/oxidized/source/jsonfile.rb +5 -0
- data/lib/oxidized/source/sql.rb +5 -0
- data/lib/oxidized/version.rb +2 -2
- data/lib/oxidized/worker.rb +36 -15
- data/lib/refinements.rb +18 -0
- data/oxidized.gemspec +28 -24
- metadata +103 -55
- data/docs/Model-Notes/APC_AOS.md +0 -65
- data/docs/Model-Notes/FortiOS.md +0 -44
|
@@ -48,19 +48,17 @@ class TPLink < Oxidized::Model
|
|
|
48
48
|
lines[0..lines.index("end\n")].join
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
macro :enable, regex: /^[pP]assword:/
|
|
52
|
+
|
|
51
53
|
cfg :telnet, :ssh do
|
|
52
54
|
username /^User ?[nN]ame:/
|
|
53
55
|
password /^\r?Password:/
|
|
56
|
+
newline "\r\n"
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
cfg :telnet, :ssh do
|
|
57
60
|
post_login do
|
|
58
|
-
|
|
59
|
-
cmd "enable"
|
|
60
|
-
elsif vars(:enable)
|
|
61
|
-
cmd "enable", /^[pP]assword:/
|
|
62
|
-
cmd vars(:enable)
|
|
63
|
-
end
|
|
61
|
+
cmd 'terminal length 0'
|
|
64
62
|
end
|
|
65
63
|
|
|
66
64
|
pre_logout do
|
|
@@ -5,14 +5,74 @@ class TrueNAS < Oxidized::Model
|
|
|
5
5
|
|
|
6
6
|
cmd('uname -a') { |cfg| comment cfg }
|
|
7
7
|
cmd('cat /etc/version') { |cfg| comment cfg }
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
# for TrueNAS SCALE machines, make sure the user you use to connect can run
|
|
10
|
+
# this command, or if needed, with passwordless sudo. Try putting this in
|
|
11
|
+
# /etc/sudoers
|
|
12
|
+
# oxidized ALL=(ALL) NOPASSWD: /usr/bin/find /mnt/.ix-apps/app_configs *, /usr/bin/sqlite3 -readonly file\:/data/freenas-v1.db *
|
|
13
|
+
|
|
14
|
+
cmd("sqlite3 -readonly 'file:/data/freenas-v1.db' .dump") do |cfg|
|
|
15
|
+
if cfg.include? "Error: unable to open database"
|
|
16
|
+
# retry with sudo
|
|
17
|
+
cfg = cmd("sudo sqlite3 -readonly 'file:/data/freenas-v1.db' .dump")
|
|
18
|
+
end
|
|
9
19
|
cfg.lines.reject do |line|
|
|
10
|
-
line.match(/^INSERT INTO storage_replication /) ||
|
|
20
|
+
line.match(/^INSERT INTO storage_replication /) || # ignore storage_replication because repl_status field changes on every run
|
|
11
21
|
line.match(/^INSERT INTO system_alert /) || # ignore system alerts in db
|
|
12
|
-
line.match(/^INSERT INTO sqlite_sequence VALUES\('system_alert',/) # ignore system alerts in db
|
|
22
|
+
line.match(/^INSERT INTO sqlite_sequence VALUES\('system_alert',/) || # ignore system alerts in db
|
|
23
|
+
line.match(/^INSERT INTO tasks_cloudsync /) # ignore cloudsync tasks because job field changes on every run
|
|
13
24
|
end.join
|
|
14
25
|
end
|
|
15
26
|
|
|
27
|
+
post do
|
|
28
|
+
filter_column("storage_replication", "repl_state")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
post do
|
|
32
|
+
filter_column("tasks_cloudsync", "job")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
post do
|
|
36
|
+
collect_ixapps_configurations
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def filter_column(table_name, column_name)
|
|
40
|
+
sqlite_cmd = "sqlite3 -readonly 'file:/data/freenas-v1.db'"
|
|
41
|
+
|
|
42
|
+
# This SQL command will create a SELECT query with all columns except the one we want to skip.
|
|
43
|
+
generate_select_cmd = "select 'select ' || group_concat(name,', ') || ' FROM #{table_name};' FROM pragma_table_info('#{table_name}') WHERE name != '#{column_name}';"
|
|
44
|
+
|
|
45
|
+
select_stmt = cmd("#{sqlite_cmd} \"#{generate_select_cmd}\"")
|
|
46
|
+
if select_stmt.include? "Error: unable to open database"
|
|
47
|
+
# retry with sudo
|
|
48
|
+
sqlite_cmd = "sudo #{sqlite_cmd}"
|
|
49
|
+
select_stmt = cmd("#{sqlite_cmd} \"#{generate_select_cmd}\"")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
insert_cmds = "-header '.mode insert #{table_name}' '#{select_stmt}'"
|
|
53
|
+
cmd("#{sqlite_cmd} #{insert_cmds}") do |cfg|
|
|
54
|
+
if cfg.include? "INSERT"
|
|
55
|
+
# Don't add a COMMIT; if the query came up with no rows
|
|
56
|
+
cfg + "COMMIT;\n"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def collect_ixapps_configurations
|
|
62
|
+
config_command = <<~'CMDEND'
|
|
63
|
+
if [ -d /mnt/.ix-apps ];
|
|
64
|
+
then
|
|
65
|
+
sudo find /mnt/.ix-apps/app_configs
|
|
66
|
+
\( -name "app.yaml" -or -name "user_config.yaml" -or -name "metadata.yaml" \)
|
|
67
|
+
-printf "\n\n#######################\n# %p\n#######################\n"
|
|
68
|
+
-exec cat {} \; ;
|
|
69
|
+
else
|
|
70
|
+
echo "# No Apps configuration found in /mnt/.ix-apps";
|
|
71
|
+
fi
|
|
72
|
+
CMDEND
|
|
73
|
+
cmd(config_command.gsub("\n", ""))
|
|
74
|
+
end
|
|
75
|
+
|
|
16
76
|
cfg :ssh do
|
|
17
77
|
exec true # don't run shell, run each command in exec channel
|
|
18
78
|
end
|
data/lib/oxidized/model/voss.rb
CHANGED
|
@@ -23,6 +23,9 @@ class Voss < Oxidized::Model
|
|
|
23
23
|
cfg.gsub! /(^((.*)Last Vlan Change(.*):(.*))$)/, 'removed Last Vlan Change'
|
|
24
24
|
cfg.gsub! /(^((.*)Temperature(.*):(.*))$)/, 'removed Temperature'
|
|
25
25
|
cfg.gsub! /(^((.*)Total Power Usage(.*):(.*))$)/, 'removed Total Power Usage'
|
|
26
|
+
cfg.gsub! /(^((.*)(Tray \d+ Fan \d+)\s+(\w+)\s+(\w+)\s+(.*))$)/, '\3\4 \5 [removed RPM values]'
|
|
27
|
+
cfg.gsub! /(^((.*)Command Execution Time: (.*))$)/, 'Command Execution Time [removed]'
|
|
28
|
+
cfg.gsub! /(^((.*)(Ambient\s+\d+|CPU|INTERNAL\s+MAC|SODIMM)\s+\d+\s+\d+(.*))$)/, '\3\4 [removed temperature readings]'
|
|
26
29
|
comment "#{cfg}\n"
|
|
27
30
|
end
|
|
28
31
|
|
data/lib/oxidized/model/vyos.rb
CHANGED
|
@@ -15,8 +15,11 @@ class Vyos < Oxidized::Model
|
|
|
15
15
|
cmd :secret do |cfg|
|
|
16
16
|
cfg.gsub! /secret (\S+).*/, 'secret <secret removed>'
|
|
17
17
|
cfg.gsub! /password (\S+).*/, 'password <secret removed>'
|
|
18
|
-
cfg.gsub! /community (\S+)/, 'community <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>'
|
|
19
21
|
cfg.gsub! /private key (\S+).*/, 'private key <secret removed>'
|
|
22
|
+
cfg.gsub! /private-key (\S+).*/, 'private-key <secret removed>'
|
|
20
23
|
# password in URLs like protocol://user:password@domain.tld/
|
|
21
24
|
cfg.gsub! /([a-z]+:\/\/[^:\s]+:)\S+@/, '\1<secret removed>@'
|
|
22
25
|
cfg
|
data/lib/oxidized/node.rb
CHANGED
|
@@ -8,8 +8,9 @@ module Oxidized
|
|
|
8
8
|
include SemanticLogger::Loggable
|
|
9
9
|
|
|
10
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
|
|
11
|
+
attr_accessor :running, :user, :email, :msg, :from, :stats, :retry, :err_type, :err_reason, :nexted
|
|
12
12
|
alias running? running
|
|
13
|
+
alias nexted? nexted
|
|
13
14
|
|
|
14
15
|
# opt is a hash with the node parameters given in the source (:name, :group, :ip...)
|
|
15
16
|
def initialize(opt)
|
|
@@ -34,6 +35,7 @@ module Oxidized
|
|
|
34
35
|
@repo = resolve_repo opt
|
|
35
36
|
@err_type = nil
|
|
36
37
|
@err_reason = nil
|
|
38
|
+
@nexted = false
|
|
37
39
|
|
|
38
40
|
# model instance needs to access node instance
|
|
39
41
|
@model.node = self
|
|
@@ -41,37 +43,37 @@ module Oxidized
|
|
|
41
43
|
|
|
42
44
|
def run
|
|
43
45
|
status = :fail
|
|
44
|
-
config =
|
|
45
|
-
@
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
55
65
|
else
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
config = nil
|
|
67
|
+
break
|
|
58
68
|
end
|
|
59
69
|
end
|
|
60
|
-
logger.error "No suitable input found for #{name}" unless @model.input
|
|
61
70
|
|
|
62
71
|
@model.input = nil
|
|
63
72
|
[status, config]
|
|
64
73
|
end
|
|
65
74
|
|
|
66
75
|
def run_input(input)
|
|
67
|
-
rescue_fail =
|
|
68
|
-
[input.class::RESCUE_FAIL, input.class.superclass::RESCUE_FAIL].each do |hash|
|
|
69
|
-
hash.each do |level, errors|
|
|
70
|
-
errors.each do |err|
|
|
71
|
-
rescue_fail[err] = level
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
76
|
+
rescue_fail = input.class.rescue_fail
|
|
75
77
|
begin
|
|
76
78
|
input.connect(self) && input.get
|
|
77
79
|
rescue *rescue_fail.keys => err
|
data/lib/oxidized/nodes.rb
CHANGED
|
@@ -88,6 +88,8 @@ module Oxidized
|
|
|
88
88
|
n.from = opt['from']
|
|
89
89
|
# set last job to nil so that the node is picked for immediate update
|
|
90
90
|
n.last = nil
|
|
91
|
+
# set nexted to true so that the node will not be skipped with interval 0
|
|
92
|
+
n.nexted = true
|
|
91
93
|
put n
|
|
92
94
|
jobs.increment if Oxidized.config.next_adds_job?
|
|
93
95
|
end
|
data/lib/oxidized/output/file.rb
CHANGED
|
@@ -21,8 +21,14 @@ module Oxidized
|
|
|
21
21
|
|
|
22
22
|
# node: node name (String)
|
|
23
23
|
# outputs: Oxidized::Models::Outputs
|
|
24
|
-
# opts:
|
|
24
|
+
# opts: dict of optional parameters:
|
|
25
|
+
# - group: node group
|
|
26
|
+
# - significant_changes:
|
|
27
|
+
# nil / not set / true -> store as usual
|
|
28
|
+
# false -> do not store
|
|
25
29
|
def store(node, outputs, opt = {})
|
|
30
|
+
return false if opt[:significant_changes] == false
|
|
31
|
+
|
|
26
32
|
file = ::File.expand_path @cfg.directory
|
|
27
33
|
file = ::File.join ::File.dirname(file), opt[:group] if opt[:group]
|
|
28
34
|
FileUtils.mkdir_p file
|
data/lib/oxidized/output/git.rb
CHANGED
|
@@ -35,6 +35,16 @@ module Oxidized
|
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
# file: node name (String)
|
|
39
|
+
# outputs: Oxidized::Models::Outputs
|
|
40
|
+
# opts: dict of optional parameters:
|
|
41
|
+
# - msg: commit message
|
|
42
|
+
# - email: committer email
|
|
43
|
+
# - user: committer name
|
|
44
|
+
# - group: node group
|
|
45
|
+
# - significant_changes:
|
|
46
|
+
# nil / not set / true: store as usual
|
|
47
|
+
# false: skip general config, only store configs where type != nil
|
|
38
48
|
def store(file, outputs, opt = {})
|
|
39
49
|
@msg = opt[:msg]
|
|
40
50
|
@user = opt[:user] || @cfg.user
|
|
@@ -58,7 +68,7 @@ module Oxidized
|
|
|
58
68
|
update type_repo, file, type_cfg
|
|
59
69
|
end
|
|
60
70
|
|
|
61
|
-
update repo, file, outputs.to_cfg
|
|
71
|
+
update repo, file, outputs.to_cfg unless opt[:significant_changes] == false
|
|
62
72
|
end
|
|
63
73
|
|
|
64
74
|
# Returns the configuration of group/node_name
|
data/lib/oxidized/output/http.rb
CHANGED
|
@@ -26,9 +26,18 @@ module Oxidized
|
|
|
26
26
|
@commitref = nil
|
|
27
27
|
uri = URI.parse @cfg.url
|
|
28
28
|
http = Net::HTTP.new uri.host, uri.port
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
|
|
30
|
+
# if uri scheme is https, enable ssl and set verify mode
|
|
31
|
+
if uri.scheme == "https"
|
|
32
|
+
http.use_ssl = true
|
|
33
|
+
http.verify_mode = @cfg.ssl_verify? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
headers = @cfg.headers? ? @cfg.headers : {}
|
|
37
|
+
|
|
38
|
+
req = Net::HTTP::Post.new(uri.request_uri, headers.merge('Content-Type' => 'application/json'))
|
|
39
|
+
req.basic_auth(@cfg.user, @cfg.password) if @cfg.user? && @cfg.password?
|
|
40
|
+
|
|
32
41
|
req.body = generate_json(node, outputs, opt)
|
|
33
42
|
response = http.request req
|
|
34
43
|
|
data/lib/oxidized/source/csv.rb
CHANGED
data/lib/oxidized/source/sql.rb
CHANGED
data/lib/oxidized/version.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Oxidized
|
|
4
|
-
VERSION = '0.
|
|
5
|
-
VERSION_FULL = '0.
|
|
4
|
+
VERSION = '0.37.0'
|
|
5
|
+
VERSION_FULL = '0.37.0'
|
|
6
6
|
def self.version_set
|
|
7
7
|
version_full = %x(git describe --tags).chop rescue ""
|
|
8
8
|
version = %x(git describe --tags --abbrev=0).chop rescue ""
|
data/lib/oxidized/worker.rb
CHANGED
|
@@ -23,11 +23,11 @@ module Oxidized
|
|
|
23
23
|
"#{@jobs_done} of #{@nodes.size}"
|
|
24
24
|
# ask for next node in queue non destructive way
|
|
25
25
|
nextnode = @nodes.first
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
break if Oxidized.config.interval.zero? && !nextnode.nexted?
|
|
27
|
+
|
|
28
|
+
nextnode.nexted = false
|
|
29
|
+
break if !nextnode.last.nil? && (nextnode.last.end + Oxidized.config.interval > Time.now.utc)
|
|
30
|
+
|
|
31
31
|
# shift nodes and get the next node
|
|
32
32
|
node = @nodes.get
|
|
33
33
|
node.running? ? next : node.running = true
|
|
@@ -64,21 +64,43 @@ module Oxidized
|
|
|
64
64
|
|
|
65
65
|
private
|
|
66
66
|
|
|
67
|
+
def significant_changes?(job, output)
|
|
68
|
+
node = job.node
|
|
69
|
+
model = node.model
|
|
70
|
+
return true unless model.vars(:output_store_mode) == "on_significant"
|
|
71
|
+
|
|
72
|
+
unless output.respond_to?(:fetch)
|
|
73
|
+
logger.error("Detection of significant changes needs an output " \
|
|
74
|
+
"capable of fetching the last configuration")
|
|
75
|
+
return true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
old = model.significant_changes output.fetch(node, node.group)
|
|
79
|
+
new = model.significant_changes job.config.to_cfg
|
|
80
|
+
if old == new
|
|
81
|
+
logger.debug "No significant change on node #{node.name}"
|
|
82
|
+
false
|
|
83
|
+
else
|
|
84
|
+
true
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
67
88
|
def process_success(node, job)
|
|
68
89
|
@jobs_done += 1 # needed for :nodes_done hook
|
|
69
|
-
Oxidized.hooks.
|
|
70
|
-
job: job
|
|
90
|
+
Oxidized.hooks.node_success(node: node, job: job)
|
|
71
91
|
msg = "update #{node.group}/#{node.name}"
|
|
72
92
|
msg += " from #{node.from}" if node.from
|
|
73
93
|
msg += " with message '#{node.msg}'" if node.msg
|
|
74
94
|
output = node.output.new
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
|
|
96
|
+
significant_changes = significant_changes?(job, output)
|
|
97
|
+
if output.store(node.name, job.config,
|
|
98
|
+
msg: msg, email: node.email, user: node.user,
|
|
99
|
+
group: node.group,
|
|
100
|
+
significant_changes: significant_changes)
|
|
77
101
|
node.modified
|
|
78
102
|
logger.info "Configuration updated for #{node.group}/#{node.name}"
|
|
79
|
-
Oxidized.hooks.
|
|
80
|
-
job: job,
|
|
81
|
-
commitref: output.commitref
|
|
103
|
+
Oxidized.hooks.post_store(node: node, job: job, commitref: output.commitref)
|
|
82
104
|
end
|
|
83
105
|
node.reset
|
|
84
106
|
end
|
|
@@ -97,8 +119,7 @@ module Oxidized
|
|
|
97
119
|
@jobs_done += 1
|
|
98
120
|
msg += ", retries exhausted, giving up"
|
|
99
121
|
node.retry = 0
|
|
100
|
-
Oxidized.hooks.
|
|
101
|
-
job: job
|
|
122
|
+
Oxidized.hooks.node_fail(node: node, job: job)
|
|
102
123
|
end
|
|
103
124
|
logger.warn msg
|
|
104
125
|
end
|
|
@@ -110,7 +131,7 @@ module Oxidized
|
|
|
110
131
|
|
|
111
132
|
def run_done_hook
|
|
112
133
|
logger.debug "Running :nodes_done hook"
|
|
113
|
-
Oxidized.hooks.
|
|
134
|
+
Oxidized.hooks.nodes_done
|
|
114
135
|
rescue StandardError => e
|
|
115
136
|
# swallow the hook erros and continue as normal
|
|
116
137
|
logger.error e.message
|
data/lib/refinements.rb
CHANGED
|
@@ -32,6 +32,24 @@ module Refinements
|
|
|
32
32
|
# rubocop:enable Naming/MemoizedInstanceVariableName
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
# keeps lines matching any pattern (String or Regexp)
|
|
36
|
+
def keep_lines(patterns)
|
|
37
|
+
each_line.select do |line|
|
|
38
|
+
patterns.any? do |pattern|
|
|
39
|
+
pattern.is_a?(Regexp) ? line =~ pattern : line.include?(pattern)
|
|
40
|
+
end
|
|
41
|
+
end.join
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# remove lines matching any pattern (String or Regexp)
|
|
45
|
+
def reject_lines(patterns)
|
|
46
|
+
each_line.reject do |line|
|
|
47
|
+
patterns.any? do |pattern|
|
|
48
|
+
pattern.is_a?(Regexp) ? line =~ pattern : line.include?(pattern)
|
|
49
|
+
end
|
|
50
|
+
end.join
|
|
51
|
+
end
|
|
52
|
+
|
|
35
53
|
# Initializes the String instance variables from another String instance
|
|
36
54
|
# when the given str is an instance of String with Oxidized refinements applied
|
|
37
55
|
def init_from_string(str = '')
|
data/oxidized.gemspec
CHANGED
|
@@ -18,47 +18,51 @@ Gem::Specification.new do |s|
|
|
|
18
18
|
|
|
19
19
|
s.metadata['rubygems_mfa_required'] = 'true'
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
# Ruby version strategy
|
|
22
|
+
#
|
|
23
|
+
# We try to keep the minimum version of Ruby to match supported LTS versions
|
|
24
|
+
# of common Linux distributions, as long as the maintenance effort remains
|
|
25
|
+
# reasonable.
|
|
26
|
+
s.required_ruby_version = '>= 3.0'
|
|
22
27
|
|
|
23
28
|
# Gemspec strategy
|
|
24
29
|
#
|
|
25
30
|
# For dependency and optional dependencies, we try to set the minimal
|
|
26
|
-
# dependency lower
|
|
31
|
+
# dependency lower or equal to the Debian 13 "Trixie" package version,
|
|
27
32
|
# so that native packages can be used.
|
|
28
|
-
# We limit the maximal version so that dependabot can warn about new
|
|
29
|
-
# and we can test them before activating them in Oxidized.
|
|
30
|
-
#
|
|
31
|
-
# development dependencies are set to the latest minor version of a library
|
|
32
|
-
# and updated after having tested them
|
|
33
|
+
# We limit the maximal minor version so that dependabot can warn about new
|
|
34
|
+
# major versions and we can test them before activating them in Oxidized.
|
|
33
35
|
|
|
34
36
|
s.add_dependency 'asetus', '~> 0.4'
|
|
35
37
|
s.add_dependency 'bcrypt_pbkdf', '~> 1.0'
|
|
36
38
|
s.add_dependency 'ed25519', '~> 1.2'
|
|
37
39
|
s.add_dependency 'net-ftp', '~> 0.2'
|
|
38
40
|
s.add_dependency 'net-http-digest_auth', '~> 1.4'
|
|
39
|
-
s.add_dependency 'net-scp', '~> 4.1'
|
|
40
41
|
s.add_dependency 'net-ssh', '~> 7.3'
|
|
41
42
|
s.add_dependency 'net-telnet', '~> 0.2'
|
|
42
43
|
s.add_dependency 'psych', '~> 5.0'
|
|
43
44
|
s.add_dependency 'rugged', '~> 1.6'
|
|
44
|
-
s.add_dependency 'semantic_logger', '~> 4.17
|
|
45
|
+
s.add_dependency 'semantic_logger', '~> 4.17'
|
|
45
46
|
s.add_dependency 'slop', '~> 4.6'
|
|
46
|
-
s.add_dependency 'syslog', '~> 0.3
|
|
47
|
-
s.add_dependency 'syslog_protocol', '~> 0.9
|
|
47
|
+
s.add_dependency 'syslog', '~> 0.3'
|
|
48
|
+
s.add_dependency 'syslog_protocol', '~> 0.9'
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
s.add_development_dependency '
|
|
51
|
-
s.add_development_dependency '
|
|
52
|
-
s.add_development_dependency '
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
s.add_development_dependency 'rubocop',
|
|
56
|
-
s.add_development_dependency 'rubocop-minitest',
|
|
57
|
-
s.add_development_dependency 'rubocop-rake',
|
|
58
|
-
s.add_development_dependency 'rubocop-sequel',
|
|
59
|
-
s.add_development_dependency 'simplecov',
|
|
50
|
+
s.add_development_dependency 'minitest', '>= 5.18', '<7'
|
|
51
|
+
s.add_development_dependency 'mocha', '>= 2.1', '<4'
|
|
52
|
+
s.add_development_dependency 'pry', '~> 0.15'
|
|
53
|
+
s.add_development_dependency 'rake', '~> 13.0'
|
|
54
|
+
# Rubocop introduces new rules in minor versions, so we limit automatic
|
|
55
|
+
# updates to patches
|
|
56
|
+
s.add_development_dependency 'rubocop', '~> 1.86.0'
|
|
57
|
+
s.add_development_dependency 'rubocop-minitest', '~> 0.39.1'
|
|
58
|
+
s.add_development_dependency 'rubocop-rake', '~> 0.7.0'
|
|
59
|
+
s.add_development_dependency 'rubocop-sequel', '~> 0.4.0'
|
|
60
|
+
s.add_development_dependency 'simplecov', '~> 0.22'
|
|
60
61
|
|
|
61
62
|
# Dependencies on optional libraries, used for unit tests & development
|
|
62
|
-
s.add_development_dependency '
|
|
63
|
-
s.add_development_dependency '
|
|
63
|
+
s.add_development_dependency 'git', '>= 2.0', '< 5'
|
|
64
|
+
s.add_development_dependency 'net-scp', '~> 4.1'
|
|
65
|
+
s.add_development_dependency 'net-tftp', '~> 0.1.0'
|
|
66
|
+
s.add_development_dependency 'oxidized-web', '>= 0.17.1'
|
|
67
|
+
s.add_development_dependency 'sequel', '>= 5.63.0', '< 6'
|
|
64
68
|
end
|