confctl 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +1 -1
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +18 -1
- data/README.md +3 -9
- data/confctl.gemspec +14 -14
- data/docs/carrier.md +138 -0
- data/lib/confctl/cli/app.rb +3 -0
- data/lib/confctl/cli/cluster.rb +73 -44
- data/lib/confctl/cli/configuration.rb +7 -2
- data/lib/confctl/cli/gen_data.rb +19 -1
- data/lib/confctl/cli/generation.rb +5 -3
- data/lib/confctl/generation/host_list.rb +3 -3
- data/lib/confctl/git_repo_mirror.rb +2 -2
- data/lib/confctl/machine.rb +101 -11
- data/lib/confctl/machine_control.rb +7 -0
- data/lib/confctl/machine_list.rb +14 -1
- data/lib/confctl/machine_status.rb +51 -4
- data/lib/confctl/nix.rb +28 -5
- data/lib/confctl/swpins/specs/git.rb +1 -1
- data/lib/confctl/version.rb +1 -1
- data/man/man8/confctl-options.nix.8 +165 -1
- data/man/man8/confctl-options.nix.8.md +165 -1
- data/man/man8/confctl.8 +21 -1
- data/man/man8/confctl.8.md +16 -1
- data/nix/evaluator.nix +18 -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 +142 -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 +803 -0
- data/nix/modules/confctl/carrier/netboot/nixos.nix +185 -0
- data/nix/modules/system-list.nix +8 -0
- metadata +12 -7
- data/.ruby-version +0 -1
@@ -46,7 +46,7 @@ let
|
|
46
46
|
|
47
47
|
addresses = mkOption {
|
48
48
|
type = types.nullOr (types.submodule addresses);
|
49
|
-
default =
|
49
|
+
default = {};
|
50
50
|
description = ''
|
51
51
|
IP addresses
|
52
52
|
'';
|
@@ -63,6 +63,29 @@ let
|
|
63
63
|
};
|
64
64
|
};
|
65
65
|
|
66
|
+
buildAttribute = mkOption {
|
67
|
+
type = types.listOf types.str;
|
68
|
+
default = [ "system" "build" "toplevel" ];
|
69
|
+
description = ''
|
70
|
+
Path to the attribute in machine system config that should be built
|
71
|
+
|
72
|
+
For example, `[ "system" "build" "toplevel" ]` will select attribute
|
73
|
+
`config.system.build.toplevel`.
|
74
|
+
'';
|
75
|
+
};
|
76
|
+
|
77
|
+
carrier = {
|
78
|
+
enable = mkEnableOption "This machine is a carrier for other machines";
|
79
|
+
|
80
|
+
machines = mkOption {
|
81
|
+
type = types.listOf (types.submodule carriedMachine);
|
82
|
+
default = [];
|
83
|
+
description = ''
|
84
|
+
List of carried machines
|
85
|
+
'';
|
86
|
+
};
|
87
|
+
};
|
88
|
+
|
66
89
|
host = mkOption {
|
67
90
|
type = types.nullOr (types.submodule host);
|
68
91
|
default = null;
|
@@ -321,11 +344,11 @@ let
|
|
321
344
|
Host FQDN
|
322
345
|
'';
|
323
346
|
apply = v:
|
324
|
-
if isNull v && !isNull config.name
|
347
|
+
if isNull v && !isNull config.name then
|
325
348
|
concatStringsSep "." (
|
326
349
|
[ config.name ]
|
327
350
|
++ (optional (!isNull config.location) config.location)
|
328
|
-
++
|
351
|
+
++ (optional (!isNull config.domain) config.domain)
|
329
352
|
)
|
330
353
|
else
|
331
354
|
v;
|
@@ -336,11 +359,127 @@ let
|
|
336
359
|
default = config.fqdn;
|
337
360
|
description = ''
|
338
361
|
Address/host to which the configuration is deployed to
|
362
|
+
|
363
|
+
Set to null if the machine is not deployable, e.g. when it is only used
|
364
|
+
as a carried machine.
|
339
365
|
'';
|
340
366
|
};
|
341
367
|
};
|
342
368
|
};
|
343
369
|
|
370
|
+
carriedMachine =
|
371
|
+
{ config, ... }:
|
372
|
+
{
|
373
|
+
options = {
|
374
|
+
machine = mkOption {
|
375
|
+
type = types.str;
|
376
|
+
description = "Machine name";
|
377
|
+
};
|
378
|
+
|
379
|
+
alias = mkOption {
|
380
|
+
type = types.nullOr types.str;
|
381
|
+
description = "Alias for carried machine name";
|
382
|
+
};
|
383
|
+
|
384
|
+
labels = mkOption {
|
385
|
+
type = types.attrs;
|
386
|
+
default = {};
|
387
|
+
description = ''
|
388
|
+
Optional user-defined labels to classify the machine
|
389
|
+
'';
|
390
|
+
};
|
391
|
+
|
392
|
+
tags = mkOption {
|
393
|
+
type = types.listOf types.str;
|
394
|
+
default = [];
|
395
|
+
description = ''
|
396
|
+
Optional user-defined tags to classify the machine
|
397
|
+
'';
|
398
|
+
};
|
399
|
+
|
400
|
+
extraModules = mkOption {
|
401
|
+
type = types.listOf types.path;
|
402
|
+
default = [];
|
403
|
+
description = ''
|
404
|
+
A list of additional NixOS modules to be imported for this machine
|
405
|
+
'';
|
406
|
+
};
|
407
|
+
|
408
|
+
buildAttribute = mkOption {
|
409
|
+
type = types.listOf types.str;
|
410
|
+
default = [ "system" "build" "toplevel" ];
|
411
|
+
description = ''
|
412
|
+
Path to the attribute in machine system config that should be built
|
413
|
+
|
414
|
+
For example, `[ "system" "build" "toplevel" ]` will select attribute
|
415
|
+
`config.system.build.toplevel`.
|
416
|
+
'';
|
417
|
+
};
|
418
|
+
|
419
|
+
buildGenerations = {
|
420
|
+
min = mkOption {
|
421
|
+
type = types.nullOr types.int;
|
422
|
+
default = null;
|
423
|
+
description = ''
|
424
|
+
The minimum number of build generations to be kept on the build
|
425
|
+
machine.
|
426
|
+
'';
|
427
|
+
};
|
428
|
+
|
429
|
+
max = mkOption {
|
430
|
+
type = types.nullOr types.int;
|
431
|
+
default = null;
|
432
|
+
description = ''
|
433
|
+
The maximum number of build generations to be kept on the build
|
434
|
+
machine.
|
435
|
+
'';
|
436
|
+
};
|
437
|
+
|
438
|
+
maxAge = mkOption {
|
439
|
+
type = types.nullOr types.int;
|
440
|
+
default = null;
|
441
|
+
description = ''
|
442
|
+
Delete build generations older than
|
443
|
+
<option>cluster.<name>.carrier.machines.*.buildGenerations.maxAge</option>
|
444
|
+
seconds from the build machine. Old generations are deleted even
|
445
|
+
if <option>cluster.<name>.carrier.machines.*.buildGenerations.max</option> is
|
446
|
+
not reached.
|
447
|
+
'';
|
448
|
+
};
|
449
|
+
};
|
450
|
+
|
451
|
+
hostGenerations = {
|
452
|
+
min = mkOption {
|
453
|
+
type = types.nullOr types.int;
|
454
|
+
default = null;
|
455
|
+
description = ''
|
456
|
+
The minimum number of generations to be kept on the machine.
|
457
|
+
'';
|
458
|
+
};
|
459
|
+
|
460
|
+
max = mkOption {
|
461
|
+
type = types.nullOr types.int;
|
462
|
+
default = null;
|
463
|
+
description = ''
|
464
|
+
The maximum number of generations to be kept on the machine.
|
465
|
+
'';
|
466
|
+
};
|
467
|
+
|
468
|
+
maxAge = mkOption {
|
469
|
+
type = types.nullOr types.int;
|
470
|
+
default = null;
|
471
|
+
description = ''
|
472
|
+
Delete generations older than
|
473
|
+
<option>cluster.<name>.carrier.machines.*.hostGenerations.maxAge</option>
|
474
|
+
seconds from the machine. Old generations are deleted even
|
475
|
+
if <option>cluster.<name>.carrier.machines.*.hostGenerations.max</option> is
|
476
|
+
not reached.
|
477
|
+
'';
|
478
|
+
};
|
479
|
+
};
|
480
|
+
};
|
481
|
+
};
|
482
|
+
|
344
483
|
systemdProperty =
|
345
484
|
{ config, ... }:
|
346
485
|
{
|
@@ -0,0 +1,35 @@
|
|
1
|
+
{ config, pkgs, lib, confMachine, ... }:
|
2
|
+
let
|
3
|
+
inherit (lib) mkIf mkOption types;
|
4
|
+
|
5
|
+
cfg = config.confctl.carrier;
|
6
|
+
|
7
|
+
carrier-env = pkgs.substituteAll {
|
8
|
+
src = ./carrier-env.rb;
|
9
|
+
name = "carrier-env";
|
10
|
+
isExecutable = true;
|
11
|
+
dir = "bin";
|
12
|
+
ruby = pkgs.ruby;
|
13
|
+
onChangeCommands = pkgs.writeScript "carrier-on-change-commands.sh" ''
|
14
|
+
#!${pkgs.bash}/bin/bash
|
15
|
+
${cfg.onChangeCommands}
|
16
|
+
'';
|
17
|
+
};
|
18
|
+
in {
|
19
|
+
options = {
|
20
|
+
confctl.carrier.onChangeCommands = mkOption {
|
21
|
+
type = types.lines;
|
22
|
+
default = "";
|
23
|
+
description = ''
|
24
|
+
Extra commands executed on a carrier machine when carried machine
|
25
|
+
is deployed or removed
|
26
|
+
'';
|
27
|
+
};
|
28
|
+
};
|
29
|
+
|
30
|
+
config = mkIf confMachine.carrier.enable {
|
31
|
+
environment.systemPackages = [
|
32
|
+
carrier-env
|
33
|
+
];
|
34
|
+
};
|
35
|
+
}
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#!@ruby@/bin/ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
class CarrierEnv
|
5
|
+
ON_CHANGE_COMMANDS = '@onChangeCommands@'.freeze
|
6
|
+
|
7
|
+
def self.run(args)
|
8
|
+
env = new
|
9
|
+
env.run(args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@action = nil
|
14
|
+
@profile = nil
|
15
|
+
@generation = nil
|
16
|
+
|
17
|
+
@optparser = OptionParser.new do |parser|
|
18
|
+
parser.banner = "Usage: #{$0} <options>"
|
19
|
+
|
20
|
+
parser.on('-p', '--profile PROFILE', 'Profile path') do |v|
|
21
|
+
@profile = v
|
22
|
+
end
|
23
|
+
|
24
|
+
parser.on('--set GENERATION', 'Set profile to generation') do |v|
|
25
|
+
@action = :set
|
26
|
+
@generation = v
|
27
|
+
end
|
28
|
+
|
29
|
+
parser.on('--delete-generations GENERATIONS', 'Delete generations') do |v|
|
30
|
+
@action = :delete
|
31
|
+
@generation = v
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def run(args)
|
37
|
+
@optparser.parse!(args)
|
38
|
+
|
39
|
+
if args.any?
|
40
|
+
warn 'Too many arguments'
|
41
|
+
puts parser
|
42
|
+
exit(false)
|
43
|
+
elsif @action.nil?
|
44
|
+
warn 'No action specified'
|
45
|
+
exit(false)
|
46
|
+
elsif @profile.nil?
|
47
|
+
warn 'Profile not set'
|
48
|
+
exit(false)
|
49
|
+
end
|
50
|
+
|
51
|
+
send(:"run_#{@action}")
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def run_set
|
57
|
+
nix_env('--set', @generation)
|
58
|
+
on_change_commands
|
59
|
+
end
|
60
|
+
|
61
|
+
def run_delete
|
62
|
+
nix_env('--delete-generations', @generation)
|
63
|
+
on_change_commands
|
64
|
+
end
|
65
|
+
|
66
|
+
def nix_env(*args)
|
67
|
+
system_command('nix-env', '-p', @profile, *args)
|
68
|
+
end
|
69
|
+
|
70
|
+
def on_change_commands
|
71
|
+
system_command(ON_CHANGE_COMMANDS)
|
72
|
+
end
|
73
|
+
|
74
|
+
def system_command(*args)
|
75
|
+
return if Kernel.system(*args)
|
76
|
+
|
77
|
+
raise "#{args.join(' ')} failed"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
CarrierEnv.run(ARGV)
|