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/node.rb
CHANGED
@@ -6,15 +6,18 @@ module Oxidized
|
|
6
6
|
class ModelNotFound < OxidizedError; end
|
7
7
|
|
8
8
|
class Node
|
9
|
+
include SemanticLogger::Loggable
|
10
|
+
|
9
11
|
attr_reader :name, :ip, :model, :input, :output, :group, :auth, :prompt, :vars, :last, :repo
|
10
12
|
attr_accessor :running, :user, :email, :msg, :from, :stats, :retry, :err_type, :err_reason
|
11
13
|
alias running? running
|
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?
|
@@ -37,7 +40,8 @@ module Oxidized
|
|
37
40
|
end
|
38
41
|
|
39
42
|
def run
|
40
|
-
status
|
43
|
+
status = :fail
|
44
|
+
config = nil
|
41
45
|
@input.each do |input|
|
42
46
|
# don't try input if model is missing config block, we may need strong config to class_name map
|
43
47
|
cfg_name = input.to_s.split('::').last.downcase
|
@@ -45,14 +49,16 @@ module Oxidized
|
|
45
49
|
|
46
50
|
@model.input = input = input.new
|
47
51
|
if (config = run_input(input))
|
48
|
-
|
52
|
+
logger.debug "#{input.class.name} ran for #{name} successfully"
|
49
53
|
status = :success
|
50
54
|
break
|
51
55
|
else
|
52
|
-
|
56
|
+
logger.debug "#{input.class.name} failed for #{name}"
|
53
57
|
status = :no_connection
|
54
58
|
end
|
55
59
|
end
|
60
|
+
logger.error "No suitable input found for #{name}" unless @model.input
|
61
|
+
|
56
62
|
@model.input = nil
|
57
63
|
[status, config]
|
58
64
|
end
|
@@ -75,13 +81,18 @@ module Oxidized
|
|
75
81
|
level = rescue_fail[resc]
|
76
82
|
resc = " (rescued #{resc})"
|
77
83
|
end
|
78
|
-
|
84
|
+
logger.send(level, '%s raised %s%s with msg "%s"' % [ip, err.class, resc, err.message])
|
79
85
|
@err_type = err.class.to_s
|
80
86
|
@err_reason = err.message.to_s
|
81
87
|
false
|
82
88
|
rescue StandardError => e
|
83
89
|
# Send a message in debug mode in case we are not able to create a crashfile
|
84
|
-
|
90
|
+
logger.error "#{ip} raised #{e.class} with msg #{e.message}, creating crashfile"
|
91
|
+
unless Oxidized.config.crash.directory?
|
92
|
+
logger.error "Cannot create crashfile for exception", e
|
93
|
+
return false
|
94
|
+
end
|
95
|
+
|
85
96
|
crashdir = Oxidized.config.crash.directory
|
86
97
|
crashfile = Oxidized.config.crash.hostnames? ? name : ip.to_s
|
87
98
|
FileUtils.mkdir_p(crashdir) unless File.directory?(crashdir)
|
@@ -92,7 +103,7 @@ module Oxidized
|
|
92
103
|
fh.puts '-' * 50
|
93
104
|
fh.puts e.backtrace
|
94
105
|
end
|
95
|
-
|
106
|
+
logger.error '%s raised %s with msg "%s", %s saved' % [ip, e.class, e.message, crashfile]
|
96
107
|
@err_type = e.class.to_s
|
97
108
|
@err_reason = e.message.to_s
|
98
109
|
false
|
@@ -122,14 +133,10 @@ module Oxidized
|
|
122
133
|
h
|
123
134
|
end
|
124
135
|
|
136
|
+
JobStruct = Struct.new(:start, :end, :status, :time)
|
125
137
|
def last=(job)
|
126
138
|
if job
|
127
|
-
|
128
|
-
ostruct.start = job.start
|
129
|
-
ostruct.end = job.end
|
130
|
-
ostruct.status = job.status
|
131
|
-
ostruct.time = job.time
|
132
|
-
@last = ostruct
|
139
|
+
@last = JobStruct.new(job.start, job.end, job.status, job.time)
|
133
140
|
else
|
134
141
|
@last = nil
|
135
142
|
end
|
@@ -160,8 +167,11 @@ module Oxidized
|
|
160
167
|
|
161
168
|
def resolve_input(opt)
|
162
169
|
inputs = resolve_key :input, opt, Oxidized.config.input.default
|
163
|
-
inputs.split(
|
164
|
-
|
170
|
+
inputs.split(',').map do |input|
|
171
|
+
input.strip!
|
172
|
+
unless Oxidized.mgr.input[input]
|
173
|
+
Oxidized.mgr.add_input(input) || raise(MethodNotFound, "#{input} not found for node #{ip}")
|
174
|
+
end
|
165
175
|
|
166
176
|
Oxidized.mgr.input[input]
|
167
177
|
end
|
@@ -169,7 +179,10 @@ module Oxidized
|
|
169
179
|
|
170
180
|
def resolve_output(opt)
|
171
181
|
output = resolve_key :output, opt, Oxidized.config.output.default
|
172
|
-
|
182
|
+
unless Oxidized.mgr.output[output]
|
183
|
+
Oxidized.mgr.add_output(output) || raise(MethodNotFound,
|
184
|
+
"#{output} not found for node #{ip}")
|
185
|
+
end
|
173
186
|
|
174
187
|
Oxidized.mgr.output[output]
|
175
188
|
end
|
@@ -177,7 +190,7 @@ module Oxidized
|
|
177
190
|
def resolve_model(opt)
|
178
191
|
model = resolve_key :model, opt
|
179
192
|
unless Oxidized.mgr.model[model]
|
180
|
-
|
193
|
+
logger.debug "Loading model #{model.inspect}"
|
181
194
|
Oxidized.mgr.add_model(model) || raise(ModelNotFound, "#{model} not found for node #{ip}")
|
182
195
|
end
|
183
196
|
Oxidized.mgr.model[model].new
|
@@ -200,42 +213,46 @@ module Oxidized
|
|
200
213
|
end
|
201
214
|
|
202
215
|
def resolve_key(key, opt, global = nil)
|
203
|
-
# resolve key: the priority is as follows:
|
216
|
+
# resolve key: the priority is as follows:
|
217
|
+
# node -> group specific model -> group -> model -> global passed -> global
|
204
218
|
# where node has the highest priority (= if defined, overwrites other values)
|
205
219
|
key_sym = key.to_sym
|
206
220
|
key_str = key.to_s
|
207
221
|
model_name = @model.class.name.to_s.downcase
|
208
|
-
|
222
|
+
logger.debug "resolving node key '#{key}', with passed global value of '#{global}' " \
|
223
|
+
"and node value '#{opt[key_sym]}'"
|
209
224
|
|
210
225
|
# Node
|
211
226
|
if opt[key_sym]
|
212
227
|
value = opt[key_sym]
|
213
|
-
|
228
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from node"
|
214
229
|
|
215
230
|
# Group specific model
|
216
|
-
elsif Oxidized.config.groups.has_key?(@group) &&
|
231
|
+
elsif Oxidized.config.groups.has_key?(@group) &&
|
232
|
+
Oxidized.config.groups[@group].models.has_key?(model_name) &&
|
233
|
+
Oxidized.config.groups[@group].models[model_name].has_key?(key_str)
|
217
234
|
value = Oxidized.config.groups[@group].models[model_name][key_str]
|
218
|
-
|
235
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from model in group"
|
219
236
|
|
220
237
|
# Group
|
221
238
|
elsif Oxidized.config.groups.has_key?(@group) && Oxidized.config.groups[@group].has_key?(key_str)
|
222
239
|
value = Oxidized.config.groups[@group][key_str]
|
223
|
-
|
240
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from group"
|
224
241
|
|
225
242
|
# Model
|
226
243
|
elsif Oxidized.config.models.has_key?(model_name) && Oxidized.config.models[model_name].has_key?(key_str)
|
227
244
|
value = Oxidized.config.models[model_name][key_str]
|
228
|
-
|
245
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from model"
|
229
246
|
|
230
247
|
# Global passed
|
231
248
|
elsif global
|
232
249
|
value = global
|
233
|
-
|
250
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from passed global value"
|
234
251
|
|
235
252
|
# Global
|
236
253
|
elsif Oxidized.config.has_key?(key_str)
|
237
254
|
value = Oxidized.config[key_str]
|
238
|
-
|
255
|
+
logger.debug "setting node key '#{key}' to value '#{value}' from global"
|
239
256
|
end
|
240
257
|
value
|
241
258
|
end
|
data/lib/oxidized/nodes.rb
CHANGED
@@ -5,6 +5,8 @@ module Oxidized
|
|
5
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
|
@@ -22,13 +24,14 @@ module Oxidized
|
|
22
24
|
node_obj = Node.new node
|
23
25
|
new.push node_obj
|
24
26
|
rescue ModelNotFound => e
|
25
|
-
|
27
|
+
logger.error "node %s raised %s with message '%s'" % [node, e.class, e.message]
|
26
28
|
rescue Resolv::ResolvError => e
|
27
|
-
|
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
|
|
@@ -74,6 +77,7 @@ module Oxidized
|
|
74
77
|
def next(node, opt = {})
|
75
78
|
return if running.find_index(node)
|
76
79
|
|
80
|
+
logger.info "Add node #{node} to running jobs"
|
77
81
|
with_lock do
|
78
82
|
n = del node
|
79
83
|
n.user = opt['user']
|
data/lib/oxidized/output/file.rb
CHANGED
@@ -19,6 +19,9 @@ module Oxidized
|
|
19
19
|
raise NoConfig, "no output file config, edit #{Oxidized::Config.configfile}"
|
20
20
|
end
|
21
21
|
|
22
|
+
# node: node name (String)
|
23
|
+
# outputs: Oxidized::Models::Outputs
|
24
|
+
# opts: hash of node vars
|
22
25
|
def store(node, outputs, opt = {})
|
23
26
|
file = ::File.expand_path @cfg.directory
|
24
27
|
file = ::File.join ::File.dirname(file), opt[:group] if opt[:group]
|
@@ -53,6 +56,31 @@ module Oxidized
|
|
53
56
|
def get_version(_node, _group, _oid)
|
54
57
|
'not supported'
|
55
58
|
end
|
59
|
+
|
60
|
+
def self.node_path(node_name, group_name = nil)
|
61
|
+
cfg_dir = ::File.expand_path Oxidized.config.output.file.directory
|
62
|
+
|
63
|
+
if group_name
|
64
|
+
::File.join ::File.dirname(cfg_dir), group_name, node_name
|
65
|
+
else
|
66
|
+
::File.join cfg_dir, node_name
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.clean_obsolete_nodes(active_nodes)
|
71
|
+
cfg_dir = ::File.expand_path Oxidized.config.output.file.directory
|
72
|
+
dir_base = ::File.dirname(cfg_dir)
|
73
|
+
default_dir = ::File.basename(cfg_dir)
|
74
|
+
|
75
|
+
keep_files = active_nodes.map { |n| node_path(n.name, n.group) }
|
76
|
+
active_groups = active_nodes.map(&:group).compact.uniq
|
77
|
+
|
78
|
+
[default_dir, *active_groups].each do |group|
|
79
|
+
Dir.glob(::File.join(dir_base, group, "*")).each do |file|
|
80
|
+
::File.delete(file) if ::File.file?(file) && !keep_files.include?(file)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
56
84
|
end
|
57
85
|
end
|
58
86
|
end
|
data/lib/oxidized/output/git.rb
CHANGED
@@ -21,17 +21,17 @@ module Oxidized
|
|
21
21
|
if @cfg.empty?
|
22
22
|
Oxidized.asetus.user.output.git.user = 'Oxidized'
|
23
23
|
Oxidized.asetus.user.output.git.email = 'o@example.com'
|
24
|
-
Oxidized.asetus.user.output.git.repo = File.join(Config::ROOT, 'oxidized.git')
|
24
|
+
Oxidized.asetus.user.output.git.repo = ::File.join(Config::ROOT, 'oxidized.git')
|
25
25
|
Oxidized.asetus.save :user
|
26
26
|
raise NoConfig, "no output git config, edit #{Oxidized::Config.configfile}"
|
27
27
|
end
|
28
28
|
|
29
29
|
if @cfg.repo.respond_to?(:each)
|
30
30
|
@cfg.repo.each do |group, repo|
|
31
|
-
@cfg.repo["#{group}="] = File.expand_path repo
|
31
|
+
@cfg.repo["#{group}="] = ::File.expand_path repo
|
32
32
|
end
|
33
33
|
else
|
34
|
-
@cfg.repo = File.expand_path @cfg.repo
|
34
|
+
@cfg.repo = ::File.expand_path @cfg.repo
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -45,7 +45,7 @@ module Oxidized
|
|
45
45
|
|
46
46
|
outputs.types.each do |type|
|
47
47
|
type_cfg = ''
|
48
|
-
type_repo = File.join(File.dirname(repo), type + '.git')
|
48
|
+
type_repo = ::File.join(::File.dirname(repo), type + '.git')
|
49
49
|
outputs.type(type).each do |output|
|
50
50
|
(type_cfg << output; next) unless output.name # rubocop:disable Style/Semicolon
|
51
51
|
type_file = file + '--' + output.name
|
@@ -200,10 +200,66 @@ module Oxidized
|
|
200
200
|
@gitcache = nil
|
201
201
|
end
|
202
202
|
|
203
|
+
def self.clean_obsolete_nodes(active_nodes)
|
204
|
+
git_config = Oxidized.config.output.git
|
205
|
+
repo_path = git_config.repo
|
206
|
+
|
207
|
+
unless git_config.single_repo?
|
208
|
+
logger.warn "clean_obsolete_nodes is not implemented for " \
|
209
|
+
"multiple git repositories"
|
210
|
+
return
|
211
|
+
end
|
212
|
+
|
213
|
+
if git_config.type_as_directory?
|
214
|
+
logger.warn "clean_obsolete_nodes is not implemented for output " \
|
215
|
+
"types as a directory within the git repository"
|
216
|
+
return
|
217
|
+
end
|
218
|
+
|
219
|
+
# The repo might not exist on the first run
|
220
|
+
return unless ::File.directory?(repo_path)
|
221
|
+
|
222
|
+
repo = Rugged::Repository.new repo_path
|
223
|
+
return if repo.empty?
|
224
|
+
|
225
|
+
keep_files = active_nodes.map do |n|
|
226
|
+
n.group ? ::File.join(n.group, n.name) : n.name
|
227
|
+
end
|
228
|
+
|
229
|
+
tree = repo.last_commit.tree
|
230
|
+
files_to_delete = []
|
231
|
+
|
232
|
+
tree.walk_blobs do |root, entry|
|
233
|
+
file_path = root.empty? ? entry[:name] : ::File.join(root, entry[:name])
|
234
|
+
files_to_delete << file_path unless keep_files.include?(file_path)
|
235
|
+
end
|
236
|
+
|
237
|
+
return if files_to_delete.empty?
|
238
|
+
|
239
|
+
logger.info "clean_obsolete_nodes: removing " \
|
240
|
+
"#{files_to_delete.size} obsolete configs"
|
241
|
+
index = repo.index
|
242
|
+
|
243
|
+
files_to_delete.each { |file_path| index.remove(file_path) }
|
244
|
+
|
245
|
+
repo.config['user.name'] = git_config.user
|
246
|
+
repo.config['user.email'] = git_config.email
|
247
|
+
Rugged::Commit.create(
|
248
|
+
repo,
|
249
|
+
tree: index.write_tree(repo),
|
250
|
+
message: "Removing #{files_to_delete.size} obsolete configs",
|
251
|
+
parents: [repo.head.target].compact,
|
252
|
+
update_ref: 'HEAD'
|
253
|
+
)
|
254
|
+
|
255
|
+
index.write
|
256
|
+
end
|
257
|
+
|
203
258
|
private
|
204
259
|
|
205
260
|
def yield_repo_and_path(node, group)
|
206
|
-
repo
|
261
|
+
repo = node.repo
|
262
|
+
path = node.name
|
207
263
|
|
208
264
|
path = "#{group}/#{node.name}" if group && !group.empty? && @cfg.single_repo?
|
209
265
|
|
@@ -215,10 +271,10 @@ module Oxidized
|
|
215
271
|
|
216
272
|
if @opt[:group]
|
217
273
|
if @cfg.single_repo?
|
218
|
-
file = File.join @opt[:group], file
|
274
|
+
file = ::File.join @opt[:group], file
|
219
275
|
else
|
220
276
|
repo = if repo.is_a?(::String)
|
221
|
-
File.join File.dirname(repo), @opt[:group] + '.git'
|
277
|
+
::File.join ::File.dirname(repo), @opt[:group] + '.git'
|
222
278
|
else
|
223
279
|
repo[@opt[:group]]
|
224
280
|
end
|
@@ -232,7 +288,8 @@ module Oxidized
|
|
232
288
|
begin
|
233
289
|
Rugged::Repository.init_at repo, :bare
|
234
290
|
rescue StandardError => create_error
|
235
|
-
raise GitError, "first '#{e.message}' was raised while opening git repo, then '#{create_error.message}'
|
291
|
+
raise GitError, "first '#{e.message}' was raised while opening git repo, then '#{create_error.message}' " \
|
292
|
+
"was while trying to create git repo"
|
236
293
|
end
|
237
294
|
retry
|
238
295
|
end
|
@@ -245,7 +302,7 @@ module Oxidized
|
|
245
302
|
# The alternative would be to rebuild the index each time, which a little
|
246
303
|
# time consuming. Caching the index in memory is difficult because a new
|
247
304
|
# Output object is created each time #store is called.
|
248
|
-
def update_repo(repo, file, data)
|
305
|
+
def update_repo(repo, file, data) # rubocop:disable Naming/PredicateMethod
|
249
306
|
oid_old = repo.blob_at(repo.head.target_id, file) rescue nil
|
250
307
|
return false if oid_old && (oid_old.content.b == data.b)
|
251
308
|
|
@@ -25,17 +25,17 @@ module Oxidized
|
|
25
25
|
if @cfg.empty?
|
26
26
|
Oxidized.asetus.user.output.gitcrypt.user = 'Oxidized'
|
27
27
|
Oxidized.asetus.user.output.gitcrypt.email = 'o@example.com'
|
28
|
-
Oxidized.asetus.user.output.gitcrypt.repo = File.join(Config::ROOT, 'oxidized.git')
|
28
|
+
Oxidized.asetus.user.output.gitcrypt.repo = ::File.join(Config::ROOT, 'oxidized.git')
|
29
29
|
Oxidized.asetus.save :user
|
30
30
|
raise NoConfig, "no output git config, edit #{Oxidized::Config.configfile}"
|
31
31
|
end
|
32
32
|
|
33
33
|
if @cfg.repo.respond_to?(:each)
|
34
34
|
@cfg.repo.each do |group, repo|
|
35
|
-
@cfg.repo["#{group}="] = File.expand_path repo
|
35
|
+
@cfg.repo["#{group}="] = ::File.expand_path repo
|
36
36
|
end
|
37
37
|
else
|
38
|
-
@cfg.repo = File.expand_path @cfg.repo
|
38
|
+
@cfg.repo = ::File.expand_path @cfg.repo
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -45,7 +45,7 @@ module Oxidized
|
|
45
45
|
@cfg.users.each do |user|
|
46
46
|
system("#{@gitcrypt_adduser} #{user}")
|
47
47
|
end
|
48
|
-
File.write(".gitattributes", "* filter=git-crypt diff=git-crypt\n.gitattributes !filter !diff")
|
48
|
+
::File.write(".gitattributes", "* filter=git-crypt diff=git-crypt\n.gitattributes !filter !diff")
|
49
49
|
repo.add(".gitattributes")
|
50
50
|
repo.commit("Initial commit: crypt all config files")
|
51
51
|
end
|
@@ -73,7 +73,7 @@ module Oxidized
|
|
73
73
|
|
74
74
|
outputs.types.each do |type|
|
75
75
|
type_cfg = ''
|
76
|
-
type_repo = File.join(File.dirname(repo), type + '.git')
|
76
|
+
type_repo = ::File.join(::File.dirname(repo), type + '.git')
|
77
77
|
outputs.type(type).each do |output|
|
78
78
|
(type_cfg << output; next) unless output.name # rubocop:disable Style/Semicolon
|
79
79
|
type_file = file + '--' + output.name
|
@@ -95,9 +95,9 @@ module Oxidized
|
|
95
95
|
unlock repo
|
96
96
|
index = repo.index
|
97
97
|
# Empty repo ?
|
98
|
-
raise 'Empty git repo' if File.exist?(index.path)
|
98
|
+
raise 'Empty git repo' if ::File.exist?(index.path)
|
99
99
|
|
100
|
-
File.read path
|
100
|
+
::File.read path
|
101
101
|
lock repo
|
102
102
|
rescue StandardError
|
103
103
|
'node not found'
|
@@ -176,7 +176,8 @@ module Oxidized
|
|
176
176
|
private
|
177
177
|
|
178
178
|
def yield_repo_and_path(node, group)
|
179
|
-
repo
|
179
|
+
repo = node.repo
|
180
|
+
path = node.name
|
180
181
|
|
181
182
|
path = "#{group}/#{node.name}" if group && @cfg.single_repo?
|
182
183
|
|
@@ -188,10 +189,10 @@ module Oxidized
|
|
188
189
|
|
189
190
|
if @opt[:group]
|
190
191
|
if @cfg.single_repo?
|
191
|
-
file = File.join @opt[:group], file
|
192
|
+
file = ::File.join @opt[:group], file
|
192
193
|
else
|
193
194
|
repo = if repo.is_a?(::String)
|
194
|
-
File.join File.dirname(repo), @opt[:group] + '.git'
|
195
|
+
::File.join ::File.dirname(repo), @opt[:group] + '.git'
|
195
196
|
else
|
196
197
|
repo[@opt[:group]]
|
197
198
|
end
|
@@ -201,12 +202,13 @@ module Oxidized
|
|
201
202
|
begin
|
202
203
|
update_repo repo, file, data, @msg, @user, @email
|
203
204
|
rescue Git::GitExecuteError, ArgumentError => e
|
204
|
-
|
205
|
+
logger.debug "open_error #{e} #{file}"
|
205
206
|
begin
|
206
207
|
grepo = Git.init repo
|
207
208
|
crypt_init grepo
|
208
209
|
rescue StandardError => create_error
|
209
|
-
raise GitCryptError, "first '#{e.message}' was raised while opening git repo, then
|
210
|
+
raise GitCryptError, "first '#{e.message}' was raised while opening git repo, then " \
|
211
|
+
"'#{create_error.message}' was while trying to create git repo"
|
210
212
|
end
|
211
213
|
retry
|
212
214
|
end
|
@@ -218,7 +220,7 @@ module Oxidized
|
|
218
220
|
grepo.config('user.email', email)
|
219
221
|
grepo.chdir do
|
220
222
|
unlock grepo
|
221
|
-
File.write(file, data)
|
223
|
+
::File.write(file, data)
|
222
224
|
grepo.add(file)
|
223
225
|
if grepo.status[file].nil? || !grepo.status[file].type.nil?
|
224
226
|
grepo.commit(msg)
|
data/lib/oxidized/output/http.rb
CHANGED
@@ -34,14 +34,14 @@ module Oxidized
|
|
34
34
|
|
35
35
|
case response.code.to_i
|
36
36
|
when 200 || 201
|
37
|
-
|
37
|
+
logger.info "Configuration http backup complete for #{node}"
|
38
38
|
p [:success]
|
39
39
|
when (400..499)
|
40
|
-
|
40
|
+
logger.info "Configuration http backup for #{node} failed status: #{response.body}"
|
41
41
|
p [:bad_request]
|
42
42
|
when (500..599)
|
43
43
|
p [:server_problems]
|
44
|
-
|
44
|
+
logger.info "Configuration http backup for #{node} failed status: #{response.body}"
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -55,7 +55,8 @@ module Oxidized
|
|
55
55
|
'group' => opt[:group],
|
56
56
|
'node' => node,
|
57
57
|
'config' => outputs.to_cfg
|
58
|
-
# actually we need to also iterate outputs, for other types like in gitlab.
|
58
|
+
# actually we need to also iterate outputs, for other types like in gitlab.
|
59
|
+
# But most people don't use 'type' functionality.
|
59
60
|
)
|
60
61
|
end
|
61
62
|
end
|
@@ -1,11 +1,25 @@
|
|
1
1
|
module Oxidized
|
2
2
|
module Output
|
3
|
+
def self.clean_obsolete_nodes(active_nodes)
|
4
|
+
return unless Oxidized.config.output.clean_obsolete_nodes?
|
5
|
+
|
6
|
+
output_name = Oxidized.config.output.default
|
7
|
+
output = Oxidized.mgr.add_output output_name
|
8
|
+
output[output_name].clean_obsolete_nodes(active_nodes)
|
9
|
+
end
|
10
|
+
|
3
11
|
class Output
|
12
|
+
include SemanticLogger::Loggable
|
13
|
+
|
4
14
|
class NoConfig < OxidizedError; end
|
5
15
|
|
6
16
|
def cfg_to_str(cfg)
|
7
17
|
cfg.select { |h| h[:type] == 'cfg' }.map { |h| h[:data] }.join
|
8
18
|
end
|
19
|
+
|
20
|
+
def self.clean_obsolete_nodes(_active_nodes)
|
21
|
+
logger.warn "clean_obsolete_nodes is not implemented for #{name}"
|
22
|
+
end
|
9
23
|
end
|
10
24
|
end
|
11
25
|
end
|
data/lib/oxidized/source/http.rb
CHANGED
@@ -8,7 +8,6 @@ module Oxidized
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def setup
|
11
|
-
Oxidized.setup_logger
|
12
11
|
if @cfg.empty?
|
13
12
|
Oxidized.asetus.user.source.http.url = 'https://url/api'
|
14
13
|
Oxidized.asetus.user.source.http.map.name = 'name'
|
@@ -45,7 +44,10 @@ module Oxidized
|
|
45
44
|
|
46
45
|
def pagination(data, node_want)
|
47
46
|
node_data = []
|
48
|
-
|
47
|
+
unless @cfg.pagination_key_name?
|
48
|
+
raise Oxidized::OxidizedError,
|
49
|
+
"if using pagination, 'pagination_key_name' setting must be set"
|
50
|
+
end
|
49
51
|
|
50
52
|
next_key = @cfg.pagination_key_name
|
51
53
|
loop do
|
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.34.0'
|
5
|
+
VERSION_FULL = '0.34.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
@@ -2,6 +2,8 @@ module Oxidized
|
|
2
2
|
require 'oxidized/job'
|
3
3
|
require 'oxidized/jobs'
|
4
4
|
class Worker
|
5
|
+
include SemanticLogger::Loggable
|
6
|
+
|
5
7
|
def initialize(nodes)
|
6
8
|
@jobs_done = 0
|
7
9
|
@nodes = nodes
|
@@ -17,7 +19,8 @@ module Oxidized
|
|
17
19
|
@jobs.work
|
18
20
|
|
19
21
|
while @jobs.size < @jobs.want
|
20
|
-
|
22
|
+
logger.debug "Jobs running: #{@jobs.size} of #{@jobs.want} - ended: " \
|
23
|
+
"#{@jobs_done} of #{@nodes.size}"
|
21
24
|
# ask for next node in queue non destructive way
|
22
25
|
nextnode = @nodes.first
|
23
26
|
unless nextnode.last.nil?
|
@@ -30,14 +33,14 @@ module Oxidized
|
|
30
33
|
node.running? ? next : node.running = true
|
31
34
|
|
32
35
|
@jobs.push Job.new node
|
33
|
-
|
36
|
+
logger.debug "Added #{node.group}/#{node.name} to the job queue"
|
34
37
|
end
|
35
38
|
|
36
39
|
if cycle_finished?
|
37
40
|
run_done_hook
|
38
41
|
exit 0 if Oxidized.config.run_once
|
39
42
|
end
|
40
|
-
|
43
|
+
logger.debug("#{@jobs.size} jobs running in parallel") unless @jobs.empty?
|
41
44
|
end
|
42
45
|
|
43
46
|
def process(job)
|
@@ -52,7 +55,7 @@ module Oxidized
|
|
52
55
|
process_failure node, job
|
53
56
|
end
|
54
57
|
rescue NodeNotFound
|
55
|
-
|
58
|
+
logger.warn "#{node.group}/#{node.name} not found, removed while collecting?"
|
56
59
|
end
|
57
60
|
|
58
61
|
def reload
|
@@ -72,7 +75,7 @@ module Oxidized
|
|
72
75
|
if output.store node.name, job.config,
|
73
76
|
msg: msg, email: node.email, user: node.user, group: node.group
|
74
77
|
node.modified
|
75
|
-
|
78
|
+
logger.info "Configuration updated for #{node.group}/#{node.name}"
|
76
79
|
Oxidized.hooks.handle :post_store, node: node,
|
77
80
|
job: job,
|
78
81
|
commitref: output.commitref
|
@@ -97,7 +100,7 @@ module Oxidized
|
|
97
100
|
Oxidized.hooks.handle :node_fail, node: node,
|
98
101
|
job: job
|
99
102
|
end
|
100
|
-
|
103
|
+
logger.warn msg
|
101
104
|
end
|
102
105
|
|
103
106
|
def cycle_finished?
|
@@ -106,11 +109,11 @@ module Oxidized
|
|
106
109
|
end
|
107
110
|
|
108
111
|
def run_done_hook
|
109
|
-
|
112
|
+
logger.debug "Running :nodes_done hook"
|
110
113
|
Oxidized.hooks.handle :nodes_done
|
111
114
|
rescue StandardError => e
|
112
115
|
# swallow the hook erros and continue as normal
|
113
|
-
|
116
|
+
logger.error e.message
|
114
117
|
ensure
|
115
118
|
@jobs_done = 0
|
116
119
|
end
|