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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +1 -1
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +1 -0
  5. data/CHANGELOG.md +30 -1
  6. data/README.md +4 -9
  7. data/confctl.gemspec +14 -14
  8. data/docs/carrier.md +150 -0
  9. data/lib/confctl/cli/app.rb +19 -0
  10. data/lib/confctl/cli/cluster.rb +214 -49
  11. data/lib/confctl/cli/configuration.rb +7 -2
  12. data/lib/confctl/cli/gen_data.rb +19 -1
  13. data/lib/confctl/cli/generation.rb +47 -16
  14. data/lib/confctl/generation/build.rb +42 -1
  15. data/lib/confctl/generation/build_list.rb +10 -0
  16. data/lib/confctl/generation/host.rb +9 -5
  17. data/lib/confctl/generation/host_list.rb +22 -7
  18. data/lib/confctl/generation/unified.rb +5 -0
  19. data/lib/confctl/generation/unified_list.rb +10 -0
  20. data/lib/confctl/git_repo_mirror.rb +2 -2
  21. data/lib/confctl/machine.rb +105 -11
  22. data/lib/confctl/machine_control.rb +10 -2
  23. data/lib/confctl/machine_list.rb +18 -1
  24. data/lib/confctl/machine_status.rb +51 -4
  25. data/lib/confctl/nix.rb +90 -22
  26. data/lib/confctl/nix_copy.rb +5 -5
  27. data/lib/confctl/null_logger.rb +7 -0
  28. data/lib/confctl/swpins/specs/git.rb +1 -1
  29. data/lib/confctl/swpins/specs/git_rev.rb +1 -1
  30. data/lib/confctl/system_command.rb +3 -2
  31. data/lib/confctl/version.rb +1 -1
  32. data/libexec/auto-rollback.rb +106 -0
  33. data/man/man8/confctl-options.nix.8 +165 -1
  34. data/man/man8/confctl-options.nix.8.md +165 -1
  35. data/man/man8/confctl.8 +109 -73
  36. data/man/man8/confctl.8.md +86 -55
  37. data/nix/evaluator.nix +26 -7
  38. data/nix/lib/default.nix +64 -17
  39. data/nix/lib/machine/default.nix +14 -11
  40. data/nix/lib/machine/info.nix +3 -3
  41. data/nix/modules/cluster/default.nix +162 -3
  42. data/nix/modules/confctl/carrier/base.nix +35 -0
  43. data/nix/modules/confctl/carrier/carrier-env.rb +81 -0
  44. data/nix/modules/confctl/carrier/netboot/build-netboot-server.rb +962 -0
  45. data/nix/modules/confctl/carrier/netboot/nixos.nix +185 -0
  46. data/nix/modules/confctl/kexec-netboot/default.nix +36 -0
  47. data/nix/modules/confctl/kexec-netboot/kexec-netboot.8.adoc +62 -0
  48. data/nix/modules/confctl/kexec-netboot/kexec-netboot.rb +455 -0
  49. data/nix/modules/system-list.nix +10 -0
  50. metadata +17 -7
  51. 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 = null;
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;
@@ -163,6 +186,26 @@ let
163
186
  };
164
187
  };
165
188
 
189
+ autoRollback = {
190
+ enable = mkOption {
191
+ type = types.bool;
192
+ default = true;
193
+ description = ''
194
+ Enable automatic rollback in case the machine is unresponsive after
195
+ deploy
196
+ '';
197
+ };
198
+
199
+ timeout = mkOption {
200
+ type = types.int;
201
+ default = 60;
202
+ description = ''
203
+ Number of seconds after which if the machine is unreachable, auto-rollback
204
+ is initiated
205
+ '';
206
+ };
207
+ };
208
+
166
209
  healthChecks = {
167
210
  systemd = {
168
211
  enable = mkOption {
@@ -321,11 +364,11 @@ let
321
364
  Host FQDN
322
365
  '';
323
366
  apply = v:
324
- if isNull v && !isNull config.name && !isNull config.domain then
367
+ if isNull v && !isNull config.name then
325
368
  concatStringsSep "." (
326
369
  [ config.name ]
327
370
  ++ (optional (!isNull config.location) config.location)
328
- ++ [ config.domain ]
371
+ ++ (optional (!isNull config.domain) config.domain)
329
372
  )
330
373
  else
331
374
  v;
@@ -336,8 +379,124 @@ let
336
379
  default = config.fqdn;
337
380
  description = ''
338
381
  Address/host to which the configuration is deployed to
382
+
383
+ Set to null if the machine is not deployable, e.g. when it is only used
384
+ as a carried machine.
385
+ '';
386
+ };
387
+ };
388
+ };
389
+
390
+ carriedMachine =
391
+ { config, ... }:
392
+ {
393
+ options = {
394
+ machine = mkOption {
395
+ type = types.str;
396
+ description = "Machine name";
397
+ };
398
+
399
+ alias = mkOption {
400
+ type = types.nullOr types.str;
401
+ description = "Alias for carried machine name";
402
+ };
403
+
404
+ labels = mkOption {
405
+ type = types.attrs;
406
+ default = {};
407
+ description = ''
408
+ Optional user-defined labels to classify the machine
409
+ '';
410
+ };
411
+
412
+ tags = mkOption {
413
+ type = types.listOf types.str;
414
+ default = [];
415
+ description = ''
416
+ Optional user-defined tags to classify the machine
417
+ '';
418
+ };
419
+
420
+ extraModules = mkOption {
421
+ type = types.listOf types.path;
422
+ default = [];
423
+ description = ''
424
+ A list of additional NixOS modules to be imported for this machine
425
+ '';
426
+ };
427
+
428
+ buildAttribute = mkOption {
429
+ type = types.listOf types.str;
430
+ default = [ "system" "build" "toplevel" ];
431
+ description = ''
432
+ Path to the attribute in machine system config that should be built
433
+
434
+ For example, `[ "system" "build" "toplevel" ]` will select attribute
435
+ `config.system.build.toplevel`.
339
436
  '';
340
437
  };
438
+
439
+ buildGenerations = {
440
+ min = mkOption {
441
+ type = types.nullOr types.int;
442
+ default = null;
443
+ description = ''
444
+ The minimum number of build generations to be kept on the build
445
+ machine.
446
+ '';
447
+ };
448
+
449
+ max = mkOption {
450
+ type = types.nullOr types.int;
451
+ default = null;
452
+ description = ''
453
+ The maximum number of build generations to be kept on the build
454
+ machine.
455
+ '';
456
+ };
457
+
458
+ maxAge = mkOption {
459
+ type = types.nullOr types.int;
460
+ default = null;
461
+ description = ''
462
+ Delete build generations older than
463
+ <option>cluster.&lt;name&gt;.carrier.machines.*.buildGenerations.maxAge</option>
464
+ seconds from the build machine. Old generations are deleted even
465
+ if <option>cluster.&lt;name&gt;.carrier.machines.*.buildGenerations.max</option> is
466
+ not reached.
467
+ '';
468
+ };
469
+ };
470
+
471
+ hostGenerations = {
472
+ min = mkOption {
473
+ type = types.nullOr types.int;
474
+ default = null;
475
+ description = ''
476
+ The minimum number of generations to be kept on the machine.
477
+ '';
478
+ };
479
+
480
+ max = mkOption {
481
+ type = types.nullOr types.int;
482
+ default = null;
483
+ description = ''
484
+ The maximum number of generations to be kept on the machine.
485
+ '';
486
+ };
487
+
488
+ maxAge = mkOption {
489
+ type = types.nullOr types.int;
490
+ default = null;
491
+ description = ''
492
+ Delete generations older than
493
+ <option>cluster.&lt;name&gt;.carrier.machines.*.hostGenerations.maxAge</option>
494
+ seconds from the machine. Old generations are deleted even
495
+ if <option>cluster.&lt;name&gt;.carrier.machines.*.hostGenerations.max</option> is
496
+ not reached.
497
+ '';
498
+ };
499
+ };
341
500
  };
342
501
  };
343
502
 
@@ -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)