confctl 1.0.0 → 2.1.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/.editorconfig +1 -1
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +30 -1
- data/README.md +4 -9
- data/confctl.gemspec +14 -14
- data/docs/carrier.md +150 -0
- data/lib/confctl/cli/app.rb +19 -0
- data/lib/confctl/cli/cluster.rb +214 -49
- data/lib/confctl/cli/configuration.rb +7 -2
- data/lib/confctl/cli/gen_data.rb +19 -1
- data/lib/confctl/cli/generation.rb +47 -16
- data/lib/confctl/generation/build.rb +42 -1
- data/lib/confctl/generation/build_list.rb +10 -0
- data/lib/confctl/generation/host.rb +9 -5
- data/lib/confctl/generation/host_list.rb +22 -7
- data/lib/confctl/generation/unified.rb +5 -0
- data/lib/confctl/generation/unified_list.rb +10 -0
- data/lib/confctl/git_repo_mirror.rb +2 -2
- data/lib/confctl/machine.rb +105 -11
- data/lib/confctl/machine_control.rb +10 -2
- data/lib/confctl/machine_list.rb +18 -1
- data/lib/confctl/machine_status.rb +51 -4
- data/lib/confctl/nix.rb +90 -22
- data/lib/confctl/nix_copy.rb +5 -5
- data/lib/confctl/null_logger.rb +7 -0
- data/lib/confctl/swpins/specs/git.rb +1 -1
- data/lib/confctl/swpins/specs/git_rev.rb +1 -1
- data/lib/confctl/system_command.rb +3 -2
- data/lib/confctl/version.rb +1 -1
- data/libexec/auto-rollback.rb +106 -0
- data/man/man8/confctl-options.nix.8 +165 -1
- data/man/man8/confctl-options.nix.8.md +165 -1
- data/man/man8/confctl.8 +109 -73
- data/man/man8/confctl.8.md +86 -55
- data/nix/evaluator.nix +26 -7
- data/nix/lib/default.nix +64 -17
- data/nix/lib/machine/default.nix +14 -11
- data/nix/lib/machine/info.nix +3 -3
- data/nix/modules/cluster/default.nix +162 -3
- data/nix/modules/confctl/carrier/base.nix +35 -0
- data/nix/modules/confctl/carrier/carrier-env.rb +81 -0
- data/nix/modules/confctl/carrier/netboot/build-netboot-server.rb +962 -0
- data/nix/modules/confctl/carrier/netboot/nixos.nix +185 -0
- data/nix/modules/confctl/kexec-netboot/default.nix +36 -0
- data/nix/modules/confctl/kexec-netboot/kexec-netboot.8.adoc +62 -0
- data/nix/modules/confctl/kexec-netboot/kexec-netboot.rb +455 -0
- data/nix/modules/system-list.nix +10 -0
- metadata +17 -7
- data/.ruby-version +0 -1
@@ -0,0 +1,455 @@
|
|
1
|
+
#!@ruby@/bin/ruby
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require 'uri'
|
6
|
+
require 'optparse'
|
7
|
+
require 'tempfile'
|
8
|
+
|
9
|
+
class KexecNetboot
|
10
|
+
MACHINE_FQDN = '@machineFqdn@'.freeze
|
11
|
+
|
12
|
+
KEXEC = '@kexecTools@/bin/kexec'.freeze
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@server_url = nil
|
16
|
+
@machine_fqdn = nil
|
17
|
+
@machine_gen = nil
|
18
|
+
@variant_name = nil
|
19
|
+
@interactive = false
|
20
|
+
@append_params = ''
|
21
|
+
@exec = false
|
22
|
+
@unload = false
|
23
|
+
@machines_json = nil
|
24
|
+
@tmp_files = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
parse_arguments
|
29
|
+
|
30
|
+
if @unload && @exec
|
31
|
+
warn 'ERROR: use either --unload or --exec, not both'
|
32
|
+
exit 1
|
33
|
+
elsif @unload
|
34
|
+
return unload_kexec
|
35
|
+
elsif @exec
|
36
|
+
return exec_kexec
|
37
|
+
end
|
38
|
+
|
39
|
+
httproot = parse_httproot_from_cmdline
|
40
|
+
unless httproot
|
41
|
+
warn "ERROR: Could not find 'httproot=' parameter in /proc/cmdline"
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
|
45
|
+
machines_url =
|
46
|
+
if @server_url
|
47
|
+
File.join(@server_url, 'machines.json')
|
48
|
+
else
|
49
|
+
derive_machines_json_url(httproot)
|
50
|
+
end
|
51
|
+
|
52
|
+
@machines_json = fetch_machines_json(machines_url)
|
53
|
+
|
54
|
+
machine_data = pick_machine(@machine_fqdn)
|
55
|
+
|
56
|
+
if machine_data.nil?
|
57
|
+
warn 'ERROR: No suitable machine found.'
|
58
|
+
exit 1
|
59
|
+
end
|
60
|
+
|
61
|
+
generation = pick_generation(machine_data, @machine_gen)
|
62
|
+
|
63
|
+
if generation.nil?
|
64
|
+
warn 'ERROR: No generation found/selected.'
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
variant = pick_variant(generation, @variant_name)
|
69
|
+
|
70
|
+
combined_params = generation['kernel_params'].dup
|
71
|
+
|
72
|
+
if variant && variant['kernel_params']
|
73
|
+
combined_params.concat(variant['kernel_params'])
|
74
|
+
end
|
75
|
+
|
76
|
+
combined_params << @append_params
|
77
|
+
final_params = combined_params.join(' ')
|
78
|
+
|
79
|
+
if @interactive
|
80
|
+
puts
|
81
|
+
puts 'Selected configuration:'
|
82
|
+
puts " Machine: #{machine_data['fqdn']} (spin=#{machine_data['spin']})"
|
83
|
+
puts " Generation: #{generation['generation']} (#{generation['time_s']}, rev=#{generation['shortrev']}, kernel=#{generation['kernel_version']})"
|
84
|
+
if variant
|
85
|
+
puts " Variant: #{variant['name']} (#{variant['label']})"
|
86
|
+
else
|
87
|
+
puts ' Variant: none'
|
88
|
+
end
|
89
|
+
puts " Kernel params: #{final_params}"
|
90
|
+
puts
|
91
|
+
|
92
|
+
loop do
|
93
|
+
print 'Continue? [y/N]: '
|
94
|
+
|
95
|
+
case $stdin.readline.strip.downcase
|
96
|
+
when 'y'
|
97
|
+
puts
|
98
|
+
break
|
99
|
+
when 'n'
|
100
|
+
warn 'Aborting'
|
101
|
+
exit(false)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Download kernel + initrd
|
107
|
+
kernel_path = download_file(generation['boot_files']['bzImage'])
|
108
|
+
initrd_path = download_file(generation['boot_files']['initrd'])
|
109
|
+
|
110
|
+
# kexec -l
|
111
|
+
load_kexec(kernel_path, initrd_path, final_params)
|
112
|
+
|
113
|
+
# Cleanup
|
114
|
+
cleanup_downloads
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def parse_arguments
|
120
|
+
opt_parser = OptionParser.new do |opts|
|
121
|
+
opts.banner = "Usage: #{$0} [options]"
|
122
|
+
|
123
|
+
opts.on('-s', '--server-url URL', 'Specify URL of the netboot server') do |val|
|
124
|
+
@server_url = val
|
125
|
+
end
|
126
|
+
|
127
|
+
opts.on('-m', '--machine FQDN', 'Select machine by FQDN') do |val|
|
128
|
+
@machine_fqdn = val
|
129
|
+
end
|
130
|
+
|
131
|
+
opts.on('-g', '--generation N', 'Select generation by number or negative offset') do |val|
|
132
|
+
@machine_gen = val
|
133
|
+
end
|
134
|
+
|
135
|
+
opts.on('-v', '--variant NAME', 'Select a specific variant by name') do |val|
|
136
|
+
@variant_name = val
|
137
|
+
end
|
138
|
+
|
139
|
+
opts.on('-i', '--interactive', 'Enable interactive mode') do
|
140
|
+
@interactive = true
|
141
|
+
end
|
142
|
+
|
143
|
+
opts.on('-a', '--append PARAMS', 'Append parameters to kernel command line') do |val|
|
144
|
+
@append_params = val
|
145
|
+
end
|
146
|
+
|
147
|
+
opts.on('-e', '--exec', 'Run the currently loaded kernel') do
|
148
|
+
@exec = true
|
149
|
+
end
|
150
|
+
|
151
|
+
opts.on('-u', '--unload', 'Unload the current kexec target kernel and exit') do
|
152
|
+
@unload = true
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
opt_parser.parse!(ARGV)
|
157
|
+
end
|
158
|
+
|
159
|
+
def parse_httproot_from_cmdline
|
160
|
+
cmdline = File.read('/proc/cmdline').strip
|
161
|
+
cmdline[/\bhttproot=([^\s]+)/, 1]
|
162
|
+
end
|
163
|
+
|
164
|
+
def derive_machines_json_url(httproot)
|
165
|
+
uri = URI.parse(httproot)
|
166
|
+
path_parts = uri.path.split('/').reject(&:empty?)
|
167
|
+
|
168
|
+
if path_parts.size >= 3
|
169
|
+
3.times { path_parts.pop }
|
170
|
+
end
|
171
|
+
|
172
|
+
new_path = "/#{path_parts.join('/')}"
|
173
|
+
new_path << '/' unless new_path.end_with?('/')
|
174
|
+
new_path << 'machines.json'
|
175
|
+
|
176
|
+
URI::HTTP.build(host: uri.host, port: uri.port, path: new_path).to_s
|
177
|
+
end
|
178
|
+
|
179
|
+
def fetch_machines_json(machines_url)
|
180
|
+
uri = URI.parse(machines_url)
|
181
|
+
response = Net::HTTP.get_response(uri)
|
182
|
+
|
183
|
+
unless response.is_a?(Net::HTTPSuccess)
|
184
|
+
warn "ERROR: Could not download #{machines_url}, HTTP #{response.code}"
|
185
|
+
exit 1
|
186
|
+
end
|
187
|
+
|
188
|
+
begin
|
189
|
+
JSON.parse(response.body)
|
190
|
+
rescue JSON::ParserError => e
|
191
|
+
warn "ERROR: Could not parse JSON: #{e}"
|
192
|
+
exit 1
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def pick_machine(requested_fqdn)
|
197
|
+
machines = @machines_json['machines']
|
198
|
+
return if machines.nil? || machines.empty?
|
199
|
+
|
200
|
+
if requested_fqdn.nil? && @interactive
|
201
|
+
return interactive_pick_machine(machines)
|
202
|
+
end
|
203
|
+
|
204
|
+
requested_fqdn ||= MACHINE_FQDN
|
205
|
+
|
206
|
+
found = machines.detect { |m| m['fqdn'] == requested_fqdn }
|
207
|
+
|
208
|
+
if found.nil?
|
209
|
+
warn "Machine '#{requested_fqdn}' not found."
|
210
|
+
return
|
211
|
+
end
|
212
|
+
|
213
|
+
found
|
214
|
+
end
|
215
|
+
|
216
|
+
def interactive_pick_machine(machines)
|
217
|
+
format_str = "%5s %-30s %s\n"
|
218
|
+
default_machine = machines.detect { |m| m['fqdn'] == MACHINE_FQDN }
|
219
|
+
|
220
|
+
loop do
|
221
|
+
puts format(format_str, '', 'FQDN', 'SPIN')
|
222
|
+
|
223
|
+
machines.each_with_index do |m, idx|
|
224
|
+
current_mark = m['fqdn'] == default_machine['fqdn'] ? '*' : ''
|
225
|
+
puts format(format_str, "[#{idx + 1}]" + current_mark, m['fqdn'], m['spin'])
|
226
|
+
end
|
227
|
+
|
228
|
+
print 'Select a machine by number: '
|
229
|
+
input = $stdin.gets
|
230
|
+
return if input.nil?
|
231
|
+
|
232
|
+
idx = input.strip.to_i
|
233
|
+
|
234
|
+
if idx == 0 && default_machine
|
235
|
+
return default_machine
|
236
|
+
elsif idx.between?(1, machines.size)
|
237
|
+
return machines[idx - 1]
|
238
|
+
end
|
239
|
+
|
240
|
+
puts 'Invalid selection. Please try again.'
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def pick_generation(machine_data, generation_input)
|
245
|
+
gens = machine_data['generations'] || []
|
246
|
+
return if gens.empty?
|
247
|
+
|
248
|
+
unless generation_input.nil?
|
249
|
+
parsed = parse_generation_input(generation_input, gens)
|
250
|
+
|
251
|
+
if parsed.nil?
|
252
|
+
warn "Requested generation '#{generation_input}' not found (or invalid)."
|
253
|
+
return
|
254
|
+
end
|
255
|
+
|
256
|
+
return parsed
|
257
|
+
end
|
258
|
+
|
259
|
+
if @interactive
|
260
|
+
loop do
|
261
|
+
current = gens.find { |x| x['current'] == true }
|
262
|
+
default_label = if current
|
263
|
+
"(default is #{current['generation']} - current)"
|
264
|
+
else
|
265
|
+
"(no current labeled, default is newest: #{gens[0]['generation']})"
|
266
|
+
end
|
267
|
+
|
268
|
+
puts "Available generations for #{machine_data['fqdn']}: #{default_label}"
|
269
|
+
list_generations(gens)
|
270
|
+
print 'Enter generation number (or negative offset) [ENTER for default]: '
|
271
|
+
input = $stdin.gets
|
272
|
+
return if input.nil?
|
273
|
+
|
274
|
+
line = input.strip
|
275
|
+
return current || gens[0] if line == ''
|
276
|
+
|
277
|
+
parsed = parse_generation_input(line, gens)
|
278
|
+
return parsed if parsed
|
279
|
+
|
280
|
+
puts "Invalid generation '#{line}'. Please try again."
|
281
|
+
end
|
282
|
+
else
|
283
|
+
current = gens.find { |x| x['current'] == true }
|
284
|
+
current || gens[0]
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def list_generations(gens)
|
289
|
+
format_str = "%5s %-19s %-10s %s\n"
|
290
|
+
|
291
|
+
puts format(format_str, '', 'TIME', 'REVISION', 'KERNEL')
|
292
|
+
|
293
|
+
gens.each do |g|
|
294
|
+
current_mark = g['current'] ? '*' : ''
|
295
|
+
|
296
|
+
line = format(
|
297
|
+
format_str,
|
298
|
+
"[#{g['generation']}]" + current_mark,
|
299
|
+
g['time_s'],
|
300
|
+
g['shortrev'],
|
301
|
+
g['kernel_version']
|
302
|
+
)
|
303
|
+
puts line
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def parse_generation_input(input_str, gens)
|
308
|
+
begin
|
309
|
+
val = Integer(input_str)
|
310
|
+
rescue ArgumentError
|
311
|
+
return
|
312
|
+
end
|
313
|
+
|
314
|
+
if val >= 0
|
315
|
+
gens.find { |g| g['generation'] == val }
|
316
|
+
else
|
317
|
+
offset = -val
|
318
|
+
return if offset >= gens.size
|
319
|
+
|
320
|
+
gens[offset]
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def pick_variant(generation_data, desired_variant_name)
|
325
|
+
variants = generation_data['variants'] || []
|
326
|
+
return if variants.empty?
|
327
|
+
|
328
|
+
if desired_variant_name.nil? && @interactive
|
329
|
+
interactive_pick_variant(generation_data)
|
330
|
+
elsif desired_variant_name
|
331
|
+
v = variants.find { |x| x['name'] == desired_variant_name }
|
332
|
+
|
333
|
+
if v.nil?
|
334
|
+
warn "Requested variant '#{desired_variant_name}' not found in generation #{generation_data['generation']}."
|
335
|
+
return
|
336
|
+
end
|
337
|
+
|
338
|
+
v
|
339
|
+
else
|
340
|
+
variants.first
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def interactive_pick_variant(generation_data)
|
345
|
+
variants = generation_data['variants']
|
346
|
+
|
347
|
+
loop do
|
348
|
+
puts "Variants available for generation #{generation_data['generation']}:"
|
349
|
+
format_str = "%5s %s\n"
|
350
|
+
|
351
|
+
puts format(format_str, '', 'LABEL')
|
352
|
+
|
353
|
+
variants.each_with_index do |v, idx|
|
354
|
+
line = format(format_str, "[#{idx + 1}]", v['label'])
|
355
|
+
puts line
|
356
|
+
end
|
357
|
+
|
358
|
+
print "Choose variant by number [ENTER for '#{variants[0]['name']}']: "
|
359
|
+
|
360
|
+
input = $stdin.gets
|
361
|
+
return if input.nil?
|
362
|
+
|
363
|
+
line = input.strip
|
364
|
+
return variants[0] if line == ''
|
365
|
+
|
366
|
+
idx = line.to_i
|
367
|
+
return variants[idx - 1] if idx.between?(1, variants.size)
|
368
|
+
|
369
|
+
puts 'Invalid selection. Please try again.'
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def download_file(url)
|
374
|
+
uri = URI.parse(url)
|
375
|
+
basename = File.basename(uri.path)
|
376
|
+
tmp_file = Tempfile.new(basename)
|
377
|
+
|
378
|
+
puts "Downloading #{url} -> #{tmp_file.path}"
|
379
|
+
|
380
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
381
|
+
resp = http.get(uri.request_uri)
|
382
|
+
|
383
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
384
|
+
warn "ERROR: Could not download #{url}, HTTP #{resp.code}"
|
385
|
+
exit 1
|
386
|
+
end
|
387
|
+
|
388
|
+
tmp_file.write(resp.body)
|
389
|
+
end
|
390
|
+
|
391
|
+
tmp_file.close
|
392
|
+
|
393
|
+
@tmp_files << tmp_file
|
394
|
+
tmp_file.path
|
395
|
+
end
|
396
|
+
|
397
|
+
def load_kexec(kernel_path, initrd_path, kernel_params_string)
|
398
|
+
cmd = [
|
399
|
+
KEXEC,
|
400
|
+
'-l',
|
401
|
+
kernel_path,
|
402
|
+
"--initrd=#{initrd_path}",
|
403
|
+
"--append=\"#{kernel_params_string}\""
|
404
|
+
].join(' ')
|
405
|
+
|
406
|
+
puts "Executing: #{cmd}"
|
407
|
+
system(cmd)
|
408
|
+
|
409
|
+
if $?.exitstatus == 0
|
410
|
+
puts 'kexec -l completed successfully.'
|
411
|
+
else
|
412
|
+
warn 'ERROR: kexec -l failed!'
|
413
|
+
exit 1
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def exec_kexec
|
418
|
+
cmd = [KEXEC, '-e'].join(' ')
|
419
|
+
|
420
|
+
puts "Executing: #{cmd}"
|
421
|
+
system(cmd)
|
422
|
+
|
423
|
+
if $?.exitstatus == 0
|
424
|
+
puts 'kexec -e completed successfully.'
|
425
|
+
else
|
426
|
+
warn 'ERROR: kexec -u failed!'
|
427
|
+
exit 1
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
def unload_kexec
|
432
|
+
cmd = [KEXEC, '-u'].join(' ')
|
433
|
+
|
434
|
+
puts "Executing: #{cmd}"
|
435
|
+
system(cmd)
|
436
|
+
|
437
|
+
if $?.exitstatus == 0
|
438
|
+
puts 'kexec -u completed successfully.'
|
439
|
+
else
|
440
|
+
warn 'ERROR: kexec -u failed!'
|
441
|
+
exit 1
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
def cleanup_downloads
|
446
|
+
@tmp_files.each do |f|
|
447
|
+
f.unlink
|
448
|
+
rescue StandardError => e
|
449
|
+
warn "Warning: Could not remove tmp file #{f.path}: #{e}"
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
loader = KexecNetboot.new
|
455
|
+
loader.run
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: confctl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakub Skokan
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 2.22.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.
|
40
|
+
version: 2.22.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: json
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,14 +184,14 @@ dependencies:
|
|
184
184
|
requirements:
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: 0.
|
187
|
+
version: 0.19.0
|
188
188
|
type: :runtime
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: 0.
|
194
|
+
version: 0.19.0
|
195
195
|
description: Nix deployment management tool
|
196
196
|
email: jakub.skokan@vpsfree.cz
|
197
197
|
executables:
|
@@ -204,7 +204,6 @@ files:
|
|
204
204
|
- ".overcommit.yml"
|
205
205
|
- ".rubocop.yml"
|
206
206
|
- ".rubocop_todo.yml"
|
207
|
-
- ".ruby-version"
|
208
207
|
- CHANGELOG.md
|
209
208
|
- Gemfile
|
210
209
|
- LICENSE.txt
|
@@ -212,6 +211,7 @@ files:
|
|
212
211
|
- Rakefile
|
213
212
|
- bin/confctl
|
214
213
|
- confctl.gemspec
|
214
|
+
- docs/carrier.md
|
215
215
|
- example/.gitignore
|
216
216
|
- example/README.md
|
217
217
|
- example/cluster/cluster.nix
|
@@ -285,6 +285,7 @@ files:
|
|
285
285
|
- lib/confctl/nix_copy.rb
|
286
286
|
- lib/confctl/nix_format.rb
|
287
287
|
- lib/confctl/nix_literal_expression.rb
|
288
|
+
- lib/confctl/null_logger.rb
|
288
289
|
- lib/confctl/parallel_executor.rb
|
289
290
|
- lib/confctl/pattern.rb
|
290
291
|
- lib/confctl/settings.rb
|
@@ -307,6 +308,7 @@ files:
|
|
307
308
|
- lib/confctl/user_scripts.rb
|
308
309
|
- lib/confctl/utils/file.rb
|
309
310
|
- lib/confctl/version.rb
|
311
|
+
- libexec/auto-rollback.rb
|
310
312
|
- man/man8/confctl-options.nix.8
|
311
313
|
- man/man8/confctl-options.nix.8.md
|
312
314
|
- man/man8/confctl.8
|
@@ -319,11 +321,19 @@ files:
|
|
319
321
|
- nix/lib/swpins/options.nix
|
320
322
|
- nix/machines.nix
|
321
323
|
- nix/modules/cluster/default.nix
|
324
|
+
- nix/modules/confctl/carrier/base.nix
|
325
|
+
- nix/modules/confctl/carrier/carrier-env.rb
|
326
|
+
- nix/modules/confctl/carrier/netboot/build-netboot-server.rb
|
327
|
+
- nix/modules/confctl/carrier/netboot/nixos.nix
|
322
328
|
- nix/modules/confctl/cli.nix
|
323
329
|
- nix/modules/confctl/generations.nix
|
330
|
+
- nix/modules/confctl/kexec-netboot/default.nix
|
331
|
+
- nix/modules/confctl/kexec-netboot/kexec-netboot.8.adoc
|
332
|
+
- nix/modules/confctl/kexec-netboot/kexec-netboot.rb
|
324
333
|
- nix/modules/confctl/nix.nix
|
325
334
|
- nix/modules/confctl/swpins.nix
|
326
335
|
- nix/modules/module-list.nix
|
336
|
+
- nix/modules/system-list.nix
|
327
337
|
- shell.nix
|
328
338
|
- template/confctl-options.nix/main.erb
|
329
339
|
- template/confctl-options.nix/options.erb
|
@@ -346,7 +356,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
346
356
|
- !ruby/object:Gem::Version
|
347
357
|
version: '0'
|
348
358
|
requirements: []
|
349
|
-
rubygems_version: 3.
|
359
|
+
rubygems_version: 3.5.22
|
350
360
|
signing_key:
|
351
361
|
specification_version: 4
|
352
362
|
summary: Nix deployment management tool
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
3.1.0
|