confctl 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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;
@@ -321,11 +344,11 @@ let
321
344
  Host FQDN
322
345
  '';
323
346
  apply = v:
324
- if isNull v && !isNull config.name && !isNull config.domain then
347
+ if isNull v && !isNull config.name then
325
348
  concatStringsSep "." (
326
349
  [ config.name ]
327
350
  ++ (optional (!isNull config.location) config.location)
328
- ++ [ config.domain ]
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.&lt;name&gt;.carrier.machines.*.buildGenerations.maxAge</option>
444
+ seconds from the build machine. Old generations are deleted even
445
+ if <option>cluster.&lt;name&gt;.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.&lt;name&gt;.carrier.machines.*.hostGenerations.maxAge</option>
474
+ seconds from the machine. Old generations are deleted even
475
+ if <option>cluster.&lt;name&gt;.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)