confctl 2.2.3 → 3.0.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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/.git-hooks/pre_commit/nixfmt.rb +13 -0
  3. data/.github/workflows/rspec.yml +64 -0
  4. data/.github/workflows/rubocop.yml +27 -0
  5. data/.github/workflows/tests.yml +139 -0
  6. data/.gitignore +12 -7
  7. data/.overcommit.yml +2 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +8 -1
  10. data/AGENTS.md +42 -0
  11. data/CHANGELOG.md +54 -0
  12. data/Gemfile +3 -2
  13. data/Gemfile.lock +198 -0
  14. data/README.md +166 -58
  15. data/Rakefile +5 -0
  16. data/confctl.gemspec +20 -2
  17. data/docs/carrier.md +3 -3
  18. data/docs/flake-inputs.md +159 -0
  19. data/docs/swpins-to-flakes.md +325 -0
  20. data/example/cluster/module-list.nix +2 -1
  21. data/example/cluster/nixos-machine/config.nix +12 -2
  22. data/example/cluster/nixos-machine/hardware.nix +6 -1
  23. data/example/cluster/vpsadminos-container/config.nix +6 -1
  24. data/example/cluster/vpsadminos-container/module.nix +4 -1
  25. data/example/cluster/vpsadminos-machine/config.nix +6 -1
  26. data/example/cluster/vpsadminos-machine/hardware.nix +6 -1
  27. data/example/cluster/vpsadminos-machine/module.nix +5 -2
  28. data/example/cluster/vpsfreecz-vps/config.nix +6 -1
  29. data/example/cluster/vpsfreecz-vps/module.nix +4 -1
  30. data/example/configs/swpins.nix +8 -3
  31. data/example/environments/base.nix +6 -1
  32. data/example/swpins/core.json +35 -0
  33. data/example-flake/.gitignore +2 -0
  34. data/example-flake/README.md +38 -0
  35. data/example-flake/cluster/cluster.nix +5 -0
  36. data/example-flake/cluster/module-list.nix +4 -0
  37. data/example-flake/cluster/nested/nixos-machine/config.nix +25 -0
  38. data/example-flake/cluster/nested/nixos-machine/hardware.nix +9 -0
  39. data/example-flake/cluster/nested/nixos-machine/module.nix +8 -0
  40. data/example-flake/cluster/nixos-machine/config.nix +25 -0
  41. data/example-flake/cluster/nixos-machine/hardware.nix +9 -0
  42. data/example-flake/cluster/nixos-machine/module.nix +8 -0
  43. data/example-flake/cluster/vpsadminos-container/config.nix +28 -0
  44. data/example-flake/cluster/vpsadminos-container/module.nix +8 -0
  45. data/example-flake/cluster/vpsadminos-machine/config.nix +27 -0
  46. data/example-flake/cluster/vpsadminos-machine/hardware.nix +9 -0
  47. data/example-flake/cluster/vpsadminos-machine/module.nix +8 -0
  48. data/example-flake/cluster/vpsfreecz-vps/config.nix +31 -0
  49. data/example-flake/cluster/vpsfreecz-vps/module.nix +8 -0
  50. data/example-flake/configs/confctl.nix +10 -0
  51. data/example-flake/data/default.nix +5 -0
  52. data/example-flake/data/ssh-keys.nix +7 -0
  53. data/example-flake/environments/base.nix +18 -0
  54. data/example-flake/flake.lock +75 -0
  55. data/example-flake/flake.nix +36 -0
  56. data/example-flake/modules/module-list.nix +13 -0
  57. data/example-flake/shell.nix +11 -0
  58. data/flake.lock +159 -0
  59. data/flake.nix +189 -0
  60. data/gemset.nix +1022 -0
  61. data/lib/confctl/cli/app.rb +145 -0
  62. data/lib/confctl/cli/attr_filters.rb +1 -1
  63. data/lib/confctl/cli/cluster.rb +681 -108
  64. data/lib/confctl/cli/command.rb +24 -2
  65. data/lib/confctl/cli/configuration.rb +171 -106
  66. data/lib/confctl/cli/generation.rb +65 -1
  67. data/lib/confctl/cli/inputs/channels.rb +190 -0
  68. data/lib/confctl/cli/inputs/machines.rb +83 -0
  69. data/lib/confctl/cli/inputs/root.rb +101 -0
  70. data/lib/confctl/cli/inputs.rb +5 -0
  71. data/lib/confctl/cli/log_view.rb +21 -10
  72. data/lib/confctl/cli/migrate/swpins_to_flakes.rb +866 -0
  73. data/lib/confctl/cli/migrate.rb +5 -0
  74. data/lib/confctl/cli/output_formatter.rb +5 -5
  75. data/lib/confctl/cli/swpins/base.rb +9 -0
  76. data/lib/confctl/cli/swpins/channel.rb +2 -5
  77. data/lib/confctl/cli/swpins/cluster.rb +2 -5
  78. data/lib/confctl/cli/swpins/core.rb +2 -5
  79. data/lib/confctl/config_type.rb +7 -0
  80. data/lib/confctl/flake_lock.rb +78 -0
  81. data/lib/confctl/flake_lock_diff.rb +36 -0
  82. data/lib/confctl/generation/build.rb +131 -24
  83. data/lib/confctl/generation/build_list.rb +4 -3
  84. data/lib/confctl/generation/unified.rb +14 -1
  85. data/lib/confctl/git_repo_mirror.rb +2 -2
  86. data/lib/confctl/health_checks/run_command.rb +3 -2
  87. data/lib/confctl/health_checks/systemd/properties.rb +1 -1
  88. data/lib/confctl/health_checks/systemd/property_list.rb +2 -2
  89. data/lib/confctl/inputs/commit_message.rb +125 -0
  90. data/lib/confctl/inputs/git_commit.rb +17 -0
  91. data/lib/confctl/inputs/nix_output_guard.rb +37 -0
  92. data/lib/confctl/inputs/setter.rb +179 -0
  93. data/lib/confctl/inputs/updater.rb +76 -0
  94. data/lib/confctl/inputs.rb +5 -0
  95. data/lib/confctl/inputs_info.rb +50 -0
  96. data/lib/confctl/line_buffer.rb +1 -1
  97. data/lib/confctl/machine.rb +18 -3
  98. data/lib/confctl/machine_control.rb +8 -2
  99. data/lib/confctl/machine_list.rb +2 -2
  100. data/lib/confctl/machine_status.rb +63 -20
  101. data/lib/confctl/nix/args.rb +48 -0
  102. data/lib/confctl/nix.rb +30 -437
  103. data/lib/confctl/nix_build_flake.rb +95 -0
  104. data/lib/confctl/nix_copy.rb +14 -2
  105. data/lib/confctl/nix_flake.rb +449 -0
  106. data/lib/confctl/nix_format.rb +3 -3
  107. data/lib/confctl/nix_legacy.rb +467 -0
  108. data/lib/confctl/swpins/change_set.rb +24 -2
  109. data/lib/confctl/swpins/specs/base.rb +2 -2
  110. data/lib/confctl/ui.rb +19 -0
  111. data/lib/confctl/version.rb +1 -1
  112. data/man/index.html +11 -0
  113. data/man/man8/confctl-options.nix.8.html +113 -0
  114. data/man/man8/confctl.8 +152 -21
  115. data/man/man8/confctl.8.html +355 -0
  116. data/man/man8/confctl.8.md +148 -17
  117. data/man/style.css +301 -0
  118. data/nix/evaluator.nix +94 -69
  119. data/nix/flake/mk-confctl-devshell.nix +85 -0
  120. data/nix/flake/mk-confctl-outputs.nix +522 -0
  121. data/nix/flake/mk-config-devshell.nix +168 -0
  122. data/nix/lib/default.nix +118 -65
  123. data/nix/lib/machine/default.nix +65 -45
  124. data/nix/lib/machine/info.nix +16 -5
  125. data/nix/lib/swpins/eval.nix +42 -29
  126. data/nix/lib/swpins/options.nix +6 -2
  127. data/nix/machines.nix +23 -15
  128. data/nix/modules/cluster/default.nix +104 -41
  129. data/nix/modules/confctl/carrier/base.nix +11 -4
  130. data/nix/modules/confctl/carrier/carrier-env.rb +2 -2
  131. data/nix/modules/confctl/carrier/netboot/build-netboot-server.rb +50 -13
  132. data/nix/modules/confctl/carrier/netboot/nixos.nix +56 -24
  133. data/nix/modules/confctl/configuration-info.nix +17 -0
  134. data/nix/modules/confctl/generations.nix +2 -2
  135. data/nix/modules/confctl/host.nix +13 -0
  136. data/nix/modules/confctl/inputs-info.nix +21 -0
  137. data/nix/modules/confctl/kexec-netboot/default.nix +13 -6
  138. data/nix/modules/confctl/kexec-netboot/kexec-netboot.8.adoc +3 -0
  139. data/nix/modules/confctl/kexec-netboot/kexec-netboot.rb +25 -16
  140. data/nix/modules/confctl/nix.nix +31 -1
  141. data/nix/modules/confctl/swpins.nix +13 -6
  142. data/nix/modules/module-list.nix +4 -2
  143. data/nix/modules/system-list.nix +4 -1
  144. data/nix/package.nix +37 -0
  145. data/shell.nix +39 -8
  146. data/skills/confctl-configuration-update/SKILL.md +228 -0
  147. data/skills/confctl-configuration-update/agents/openai.yaml +4 -0
  148. data/skills/confctl-release/SKILL.md +102 -0
  149. data/skills/confctl-release/agents/openai.yaml +4 -0
  150. data/spec/confctl/cli/cluster_health_check_spec.rb +43 -0
  151. data/spec/confctl/cli/cluster_skip_current_deploy_spec.rb +157 -0
  152. data/spec/confctl/cli/cluster_status_flake_spec.rb +83 -0
  153. data/spec/confctl/cli/inputs_set_output_spec.rb +70 -0
  154. data/spec/confctl/configuration_spec.rb +45 -0
  155. data/spec/confctl/inputs_spec.rb +104 -0
  156. data/spec/confctl/machine_control_spec.rb +112 -0
  157. data/spec/confctl/machine_list_spec.rb +47 -0
  158. data/spec/confctl/nix_flake_spec.rb +41 -0
  159. data/spec/confctl/swpins_spec.rb +106 -0
  160. data/spec/generation/build_modes_spec.rb +132 -0
  161. data/spec/inputs/commit_message_spec.rb +205 -0
  162. data/spec/inputs/nix_cached_fallback_spec.rb +50 -0
  163. data/spec/inputs/nix_output_guard_spec.rb +45 -0
  164. data/spec/spec_helper.rb +12 -0
  165. data/spec/support/cli_helper.rb +57 -0
  166. data/test-runner.sh +7 -0
  167. data/tests/all-tests.nix +30 -0
  168. data/tests/make-test.nix +15 -0
  169. data/tests/runner/extensions/confctl_helpers.rb +238 -0
  170. data/tests/runner/extensions/hostfwd_ports.rb +41 -0
  171. data/tests/suite/auto_rollback.nix +344 -0
  172. data/tests/suite/carrier/deploy.nix +751 -0
  173. data/tests/suite/carrier/netboot.nix +849 -0
  174. data/tests/suite/deploy/base.nix +806 -0
  175. data/tests/suite/deploy/flakes.nix +1 -0
  176. data/tests/suite/deploy/swpins.nix +1 -0
  177. metadata +104 -4
  178. data/nix/modules/confctl/overlays.nix +0 -15
@@ -1,17 +1,31 @@
1
- { config, lib, confLib, ... }@args:
1
+ {
2
+ config,
3
+ lib,
4
+ confLib,
5
+ ...
6
+ }@args:
2
7
  with lib;
3
8
  let
4
9
  machine =
5
- { config, ...}:
10
+ { config, ... }:
6
11
  {
7
12
  options = {
8
13
  managed = mkOption {
9
14
  type = types.nullOr types.bool;
10
15
  default = null;
11
- apply = v:
12
- if !isNull v then v
13
- else if elem config.spin [ "nixos" "vpsadminos" ] then true
14
- else false;
16
+ apply =
17
+ v:
18
+ if !isNull v then
19
+ v
20
+ else if
21
+ elem config.spin [
22
+ "nixos"
23
+ "vpsadminos"
24
+ ]
25
+ then
26
+ true
27
+ else
28
+ false;
15
29
  description = ''
16
30
  Determines whether the machine is managed using confctl or not
17
31
 
@@ -20,23 +34,30 @@ let
20
34
  };
21
35
 
22
36
  spin = mkOption {
23
- type = types.enum [ "openvz" "nixos" "vpsadminos" "other" ];
37
+ type = types.enum [
38
+ "openvz"
39
+ "nixos"
40
+ "vpsadminos"
41
+ "other"
42
+ ];
24
43
  description = "OS type";
25
44
  };
26
45
 
27
46
  swpins = {
28
47
  channels = mkOption {
29
48
  type = types.listOf types.str;
30
- default = [];
49
+ default = [ ];
31
50
  description = ''
32
51
  List of channels from <option>confctl.swpins.channels</option>
33
52
  to use on this machine
53
+
54
+ This option is legacy in flake mode, prefer <option>cluster.&lt;name&gt;.inputs.channels</option>.
34
55
  '';
35
56
  };
36
57
 
37
58
  pins = mkOption {
38
59
  type = types.attrsOf (types.submodule swpinOptions.specModule);
39
- default = {};
60
+ default = { };
40
61
  description = ''
41
62
  List of swpins for this machine, which can supplement or
42
63
  override swpins from configured channels
@@ -44,9 +65,32 @@ let
44
65
  };
45
66
  };
46
67
 
68
+ inputs = {
69
+ channels = mkOption {
70
+ type = types.listOf types.str;
71
+ default = [ ];
72
+ description = ''
73
+ List of flake pin channels to use on this machine.
74
+
75
+ In flake mode, this selects entries from the `channels` mapping
76
+ passed to `mkConfctlOutputs` (e.g. "production", "staging", "os-staging").
77
+
78
+ This replaces legacy `swpins.channels`.
79
+ '';
80
+ };
81
+
82
+ overrides = mkOption {
83
+ type = types.attrsOf types.str;
84
+ default = { };
85
+ description = ''
86
+ Override role -> flake input mapping for this machine
87
+ '';
88
+ };
89
+ };
90
+
47
91
  addresses = mkOption {
48
92
  type = types.nullOr (types.submodule addresses);
49
- default = {};
93
+ default = { };
50
94
  description = ''
51
95
  IP addresses
52
96
  '';
@@ -56,7 +100,7 @@ let
56
100
  enable = mkEnableOption "Include this system on pxe servers";
57
101
  macs = mkOption {
58
102
  type = types.listOf types.str;
59
- default = [];
103
+ default = [ ];
60
104
  description = ''
61
105
  List of MAC addresses for iPXE node auto-detection
62
106
  '';
@@ -65,7 +109,11 @@ let
65
109
 
66
110
  buildAttribute = mkOption {
67
111
  type = types.listOf types.str;
68
- default = [ "system" "build" "toplevel" ];
112
+ default = [
113
+ "system"
114
+ "build"
115
+ "toplevel"
116
+ ];
69
117
  description = ''
70
118
  Path to the attribute in machine system config that should be built
71
119
 
@@ -79,7 +127,7 @@ let
79
127
 
80
128
  machines = mkOption {
81
129
  type = types.listOf (types.submodule carriedMachine);
82
- default = [];
130
+ default = [ ];
83
131
  description = ''
84
132
  List of carried machines
85
133
  '';
@@ -93,7 +141,7 @@ let
93
141
 
94
142
  labels = mkOption {
95
143
  type = types.attrs;
96
- default = {};
144
+ default = { };
97
145
  description = ''
98
146
  Optional user-defined labels to classify the machine
99
147
  '';
@@ -101,7 +149,7 @@ let
101
149
 
102
150
  tags = mkOption {
103
151
  type = types.listOf types.str;
104
- default = [];
152
+ default = [ ];
105
153
  description = ''
106
154
  Optional user-defined tags to classify the machine
107
155
  '';
@@ -110,7 +158,7 @@ let
110
158
  nix = {
111
159
  nixPath = mkOption {
112
160
  type = types.listOf types.str;
113
- default = [];
161
+ default = [ ];
114
162
  description = ''
115
163
  List of extra paths added to environment variable
116
164
  <literal>NIX_PATH</literal> for <literal>nix-build</literal>
@@ -219,7 +267,10 @@ let
219
267
  systemProperties = mkOption {
220
268
  type = types.listOf (types.submodule systemdProperty);
221
269
  default = [
222
- { property = "SystemState"; value = "running"; }
270
+ {
271
+ property = "SystemState";
272
+ value = "running";
273
+ }
223
274
  ];
224
275
  description = ''
225
276
  Check systemd manager properties reported by systemctl show
@@ -228,7 +279,7 @@ let
228
279
 
229
280
  unitProperties = mkOption {
230
281
  type = types.attrsOf (types.listOf (types.submodule systemdProperty));
231
- default = {};
282
+ default = { };
232
283
  example = literalExpression ''
233
284
  {
234
285
  "firewall.service" = [
@@ -244,7 +295,7 @@ let
244
295
 
245
296
  builderCommands = mkOption {
246
297
  type = types.listOf (types.submodule checkCommand);
247
- default = [];
298
+ default = [ ];
248
299
  example = literalExpression ''
249
300
  [
250
301
  { description = "ping"; command = [ "ping" "-c1" "{host.fqdn}" ]; }
@@ -257,7 +308,7 @@ let
257
308
 
258
309
  machineCommands = mkOption {
259
310
  type = types.listOf (types.submodule checkCommand);
260
- default = [];
311
+ default = [ ];
261
312
  example = literalExpression ''
262
313
  [
263
314
  { description = "curl"; command = [ "curl" "-s" "http://localhost:80" ]; }
@@ -282,9 +333,9 @@ let
282
333
  primary = mkOption {
283
334
  type = types.nullOr (types.submodule (confLib.mkOptions.addresses 4));
284
335
  default =
285
- if config.v4 != [] then
336
+ if config.v4 != [ ] then
286
337
  head config.v4
287
- else if config.v6 != [] then
338
+ else if config.v6 != [ ] then
288
339
  head config.v6
289
340
  else
290
341
  null;
@@ -297,7 +348,7 @@ let
297
348
 
298
349
  v4 = mkOption {
299
350
  type = types.listOf (types.submodule (confLib.mkOptions.addresses 4));
300
- default = [];
351
+ default = [ ];
301
352
  description = ''
302
353
  List of IPv4 addresses this machine responds to
303
354
  '';
@@ -305,7 +356,7 @@ let
305
356
 
306
357
  v6 = mkOption {
307
358
  type = types.listOf (types.submodule (confLib.mkOptions.addresses 6));
308
- default = [];
359
+ default = [ ];
309
360
  description = ''
310
361
  List of IPv6 addresses this machine responds to
311
362
  '';
@@ -321,7 +372,7 @@ let
321
372
  type = types.nullOr types.str;
322
373
  default = null;
323
374
  description = ''
324
- Host name
375
+ Host name
325
376
  '';
326
377
  };
327
378
 
@@ -347,12 +398,10 @@ let
347
398
  description = ''
348
399
  Domain including location, i.e. FQDN without host name
349
400
  '';
350
- apply = v:
401
+ apply =
402
+ v:
351
403
  if isNull v && !isNull config.domain then
352
- concatStringsSep "." (
353
- (optional (!isNull config.location) config.location)
354
- ++ [ config.domain ]
355
- )
404
+ concatStringsSep "." ((optional (!isNull config.location) config.location) ++ [ config.domain ])
356
405
  else
357
406
  v;
358
407
  };
@@ -363,7 +412,8 @@ let
363
412
  description = ''
364
413
  Host FQDN
365
414
  '';
366
- apply = v:
415
+ apply =
416
+ v:
367
417
  if isNull v && !isNull config.name then
368
418
  concatStringsSep "." (
369
419
  [ config.name ]
@@ -384,6 +434,14 @@ let
384
434
  as a carried machine.
385
435
  '';
386
436
  };
437
+
438
+ port = mkOption {
439
+ type = types.int;
440
+ default = 22;
441
+ description = ''
442
+ SSH port used to connect to this machine.
443
+ '';
444
+ };
387
445
  };
388
446
  };
389
447
 
@@ -403,7 +461,7 @@ let
403
461
 
404
462
  labels = mkOption {
405
463
  type = types.attrs;
406
- default = {};
464
+ default = { };
407
465
  description = ''
408
466
  Optional user-defined labels to classify the machine
409
467
  '';
@@ -411,7 +469,7 @@ let
411
469
 
412
470
  tags = mkOption {
413
471
  type = types.listOf types.str;
414
- default = [];
472
+ default = [ ];
415
473
  description = ''
416
474
  Optional user-defined tags to classify the machine
417
475
  '';
@@ -419,7 +477,7 @@ let
419
477
 
420
478
  extraModules = mkOption {
421
479
  type = types.listOf types.path;
422
- default = [];
480
+ default = [ ];
423
481
  description = ''
424
482
  A list of additional NixOS modules to be imported for this machine
425
483
  '';
@@ -427,7 +485,11 @@ let
427
485
 
428
486
  buildAttribute = mkOption {
429
487
  type = types.listOf types.str;
430
- default = [ "system" "build" "toplevel" ];
488
+ default = [
489
+ "system"
490
+ "build"
491
+ "toplevel"
492
+ ];
431
493
  description = ''
432
494
  Path to the attribute in machine system config that should be built
433
495
 
@@ -564,13 +626,13 @@ let
564
626
 
565
627
  include = mkOption {
566
628
  type = types.listOf types.str;
567
- default = [];
629
+ default = [ ];
568
630
  description = "Strings that must be included in standard output";
569
631
  };
570
632
 
571
633
  exclude = mkOption {
572
634
  type = types.listOf types.str;
573
- default = [];
635
+ default = [ ];
574
636
  description = "Strings that must not be included in standard output";
575
637
  };
576
638
  };
@@ -584,13 +646,13 @@ let
584
646
 
585
647
  include = mkOption {
586
648
  type = types.listOf types.str;
587
- default = [];
649
+ default = [ ];
588
650
  description = "String that must be included in standard error";
589
651
  };
590
652
 
591
653
  exclude = mkOption {
592
654
  type = types.listOf types.str;
593
- default = [];
655
+ default = [ ];
594
656
  description = "String that must not be included in standard error";
595
657
  };
596
658
  };
@@ -608,11 +670,12 @@ let
608
670
  };
609
671
  };
610
672
  };
611
- in {
673
+ in
674
+ {
612
675
  options = {
613
676
  cluster = mkOption {
614
677
  type = types.attrsOf (types.submodule machine);
615
- default = {};
678
+ default = { };
616
679
  };
617
680
  };
618
681
  }
@@ -1,10 +1,16 @@
1
- { config, pkgs, lib, confMachine, ... }:
1
+ {
2
+ config,
3
+ pkgs,
4
+ lib,
5
+ confMachine,
6
+ ...
7
+ }:
2
8
  let
3
9
  inherit (lib) mkIf mkOption types;
4
10
 
5
11
  cfg = config.confctl.carrier;
6
12
 
7
- carrier-env = pkgs.confReplaceVarsWith {
13
+ carrier-env = pkgs.replaceVarsWith {
8
14
  src = ./carrier-env.rb;
9
15
  name = "carrier-env";
10
16
  isExecutable = true;
@@ -17,7 +23,8 @@ let
17
23
  '';
18
24
  };
19
25
  };
20
- in {
26
+ in
27
+ {
21
28
  options = {
22
29
  confctl.carrier.onChangeCommands = mkOption {
23
30
  type = types.lines;
@@ -34,4 +41,4 @@ in {
34
41
  carrier-env
35
42
  ];
36
43
  };
37
- }
44
+ }
@@ -63,8 +63,8 @@ class CarrierEnv
63
63
  on_change_commands
64
64
  end
65
65
 
66
- def nix_env(*args)
67
- system_command('nix-env', '-p', @profile, *args)
66
+ def nix_env(*)
67
+ system_command('nix-env', '-p', @profile, *)
68
68
  end
69
69
 
70
70
  def on_change_commands
@@ -128,7 +128,7 @@ class NetbootBuilder
128
128
  puts m.fqdn
129
129
 
130
130
  m.generations.each do |g|
131
- puts " - #{g.time_s} - #{g.version}#{g.current ? ' (current)' : ''}"
131
+ puts " - #{g.time_s} - #{g.version}#{' (current)' if g.current}"
132
132
  end
133
133
 
134
134
  puts
@@ -434,14 +434,14 @@ class TftpBuilder < RootBuilder
434
434
  MENU LABEL <%= m.label %>
435
435
  LINUX boot/<%= m.fqdn %>/<%= m.current.generation %>/bzImage
436
436
  INITRD boot/<%= m.fqdn %>/<%= m.current.generation %>/initrd
437
- APPEND init=<%= m.current.toplevel %>/init loglevel=7
437
+ APPEND <%= m.current.pxe_kernel_params.join(' ') %>
438
438
 
439
439
  <% m.generations[1..].each do |g| -%>
440
440
  LABEL <%= m.fqdn %>-<%= g.generation %>
441
441
  MENU LABEL Gen <%= g.generation %> - <%= g.time_s %> - <%= g.shortrev %>
442
442
  LINUX boot/<%= m.fqdn %>/<%= g.generation %>/bzImage
443
443
  INITRD boot/<%= m.fqdn %>/<%= g.generation %>/initrd
444
- APPEND init=<%= g.toplevel %>/init loglevel=7
444
+ APPEND <%= g.pxe_kernel_params.join(' ') %>
445
445
 
446
446
  <% end -%>
447
447
  <% if enable_memtest -%>
@@ -466,6 +466,20 @@ class TftpBuilder < RootBuilder
466
466
  },
467
467
  "pxeserver/machines/#{machine.fqdn}/menu.cfg"
468
468
  )
469
+
470
+ tpl = <<~ERB
471
+ DEFAULT <%= m.fqdn %>
472
+ PROMPT 0
473
+ TIMEOUT 50
474
+
475
+ LABEL <%= m.fqdn %>
476
+ MENU LABEL <%= m.label %>
477
+ LINUX boot/<%= m.fqdn %>/<%= m.current.generation %>/bzImage
478
+ INITRD boot/<%= m.fqdn %>/<%= m.current.generation %>/initrd
479
+ APPEND <%= m.current.pxe_kernel_params.join(' ') %>
480
+ ERB
481
+
482
+ render_to(tpl, { m: machine }, "pxeserver/machines/#{machine.fqdn}/auto.cfg")
469
483
  end
470
484
 
471
485
  def render_machine_vpsadminos(machine)
@@ -694,7 +708,7 @@ class Machine
694
708
  nil
695
709
  end
696
710
 
697
- def to_json(*args)
711
+ def to_json(*)
698
712
  {
699
713
  url:,
700
714
  name:,
@@ -702,7 +716,7 @@ class Machine
702
716
  fqdn:,
703
717
  label:,
704
718
  generations:
705
- }.to_json(*args)
719
+ }.to_json(*)
706
720
  end
707
721
 
708
722
  protected
@@ -827,13 +841,20 @@ class Generation
827
841
  @url = File.join(machine.url, generation.to_s)
828
842
  @boot_files = find_boot_files
829
843
  @variants = Variant.for_machine(machine)
844
+ @kernel_params.reject! { |v| v.start_with?('httproot=') }
845
+ ensure_nixos_init_param
830
846
 
831
- return if machine.spin != 'vpsadminos'
847
+ httproot =
848
+ if machine.spin == 'vpsadminos'
849
+ boot_files['root.squashfs']&.url
850
+ else
851
+ boot_files['initrd']&.url || boot_files['bzImage']&.url
852
+ end
832
853
 
833
- @kernel_params.insert(0, "httproot=#{boot_files['root.squashfs'].url}")
854
+ @kernel_params.insert(0, "httproot=#{httproot}") if httproot
834
855
  end
835
856
 
836
- def to_json(*args)
857
+ def to_json(*)
837
858
  {
838
859
  url:,
839
860
  store_path:,
@@ -851,11 +872,27 @@ class Generation
851
872
  boot_files:,
852
873
  variants:,
853
874
  swpins_info: json['swpins-info']
854
- }.to_json(*args)
875
+ }.to_json(*)
876
+ end
877
+
878
+ def pxe_kernel_params
879
+ return kernel_params if kernel_params.any?
880
+
881
+ [
882
+ "init=#{toplevel}/init",
883
+ 'loglevel=7'
884
+ ]
855
885
  end
856
886
 
857
887
  protected
858
888
 
889
+ def ensure_nixos_init_param
890
+ return unless machine.spin == 'nixos'
891
+ return if @kernel_params.any? { |v| v.start_with?('init=') }
892
+
893
+ @kernel_params.unshift("init=#{toplevel}/init")
894
+ end
895
+
859
896
  def extract_kernel_version
860
897
  link = File.readlink(File.join(toplevel, 'kernel'))
861
898
  return unless %r{\A/nix/store/[^-]+-linux-([^/]+)} =~ link
@@ -890,8 +927,8 @@ class BootFile
890
927
  @url = url
891
928
  end
892
929
 
893
- def to_json(*args)
894
- url.to_json(*args)
930
+ def to_json(*)
931
+ url.to_json(*)
895
932
  end
896
933
  end
897
934
 
@@ -947,12 +984,12 @@ class Variant
947
984
  @kernel_params = kernel_params
948
985
  end
949
986
 
950
- def to_json(*args)
987
+ def to_json(*)
951
988
  {
952
989
  name:,
953
990
  label:,
954
991
  kernel_params:
955
- }.to_json(*args)
992
+ }.to_json(*)
956
993
  end
957
994
  end
958
995
 
@@ -1,7 +1,21 @@
1
- { config, lib, pkgs, confMachine, ... }:
1
+ {
2
+ config,
3
+ lib,
4
+ pkgs,
5
+ confMachine,
6
+ ...
7
+ }:
2
8
  let
3
- inherit (lib) concatStringsSep flip mkOption mkEnableOption mkIf
4
- optional optionalString types;
9
+ inherit (lib)
10
+ concatStringsSep
11
+ flip
12
+ mkOption
13
+ mkEnableOption
14
+ mkIf
15
+ optional
16
+ optionalString
17
+ types
18
+ ;
5
19
 
6
20
  concatNl = concatStringsSep "\n";
7
21
 
@@ -46,13 +60,16 @@ let
46
60
  httpUrl = "http://${cfg.host}";
47
61
  memtest =
48
62
  if cfg.memtest86.enable then
49
- { package = pkgs.memtest86plus; params = cfg.memtest86.params; }
63
+ {
64
+ package = pkgs.memtest86plus;
65
+ params = cfg.memtest86.params;
66
+ }
50
67
  else
51
68
  null;
52
69
  isoImages = cfg.isoImages;
53
70
  };
54
71
 
55
- builder = pkgs.confReplaceVarsWith {
72
+ builder = pkgs.replaceVarsWith {
56
73
  src = ./build-netboot-server.rb;
57
74
  name = "build-netboot-server";
58
75
  dir = "bin";
@@ -62,7 +79,8 @@ let
62
79
  jsonConfig = pkgs.writeText "netboot-server.json" builderConfig;
63
80
  };
64
81
  };
65
- in {
82
+ in
83
+ {
66
84
  options = {
67
85
  confctl.carrier.netboot = {
68
86
  enable = mkEnableOption ''
@@ -89,7 +107,7 @@ in {
89
107
 
90
108
  params = mkOption {
91
109
  type = types.listOf types.str;
92
- default = [];
110
+ default = [ ];
93
111
  example = [ "console=ttyS0,115200" ];
94
112
  description = "See {option}`boot.loader.grub.memtest86.params`";
95
113
  };
@@ -97,7 +115,7 @@ in {
97
115
 
98
116
  isoImages = mkOption {
99
117
  type = types.listOf (types.submodule isoImage);
100
- default = [];
118
+ default = [ ];
101
119
  description = "A list of ISO images to be included in boot menu";
102
120
  };
103
121
 
@@ -107,7 +125,7 @@ in {
107
125
  Allow HTTP access for these IP ranges, if not specified
108
126
  access is not restricted.
109
127
  '';
110
- default = [];
128
+ default = [ ];
111
129
  example = "10.0.0.0/24";
112
130
  };
113
131
 
@@ -135,13 +153,21 @@ in {
135
153
  environment.systemPackages = [ builder ];
136
154
 
137
155
  networking.firewall = {
138
- extraCommands = mkIf (cfg.allowedIPv4Ranges != []) (concatNl (map (net: ''
139
- # Allow access from ${net} for netboot
140
- iptables -A nixos-fw -p udp -s ${net} ${optionalString (!isNull cfg.tftp.bindAddress) "-d ${cfg.tftp.bindAddress}"} --dport 68 -j nixos-fw-accept
141
- iptables -A nixos-fw -p udp -s ${net} ${optionalString (!isNull cfg.tftp.bindAddress) "-d ${cfg.tftp.bindAddress}"} --dport 69 -j nixos-fw-accept
142
- iptables -A nixos-fw -p tcp -s ${net} --dport 80 -j nixos-fw-accept
143
- ${optionalString cfg.enableACME "iptables -A nixos-fw -p tcp -s ${net} --dport 443 -j nixos-fw-accept"}
144
- '') cfg.allowedIPv4Ranges));
156
+ extraCommands = mkIf (cfg.allowedIPv4Ranges != [ ]) (
157
+ concatNl (
158
+ map (net: ''
159
+ # Allow access from ${net} for netboot
160
+ iptables -A nixos-fw -p udp -s ${net} ${
161
+ optionalString (!isNull cfg.tftp.bindAddress) "-d ${cfg.tftp.bindAddress}"
162
+ } --dport 68 -j nixos-fw-accept
163
+ iptables -A nixos-fw -p udp -s ${net} ${
164
+ optionalString (!isNull cfg.tftp.bindAddress) "-d ${cfg.tftp.bindAddress}"
165
+ } --dport 69 -j nixos-fw-accept
166
+ iptables -A nixos-fw -p tcp -s ${net} --dport 80 -j nixos-fw-accept
167
+ ${optionalString cfg.enableACME "iptables -A nixos-fw -p tcp -s ${net} --dport 443 -j nixos-fw-accept"}
168
+ '') cfg.allowedIPv4Ranges
169
+ )
170
+ );
145
171
  };
146
172
 
147
173
  systemd.services.netboot-atftpd = {
@@ -149,12 +175,18 @@ in {
149
175
  after = [ "network.target" ];
150
176
  wantedBy = [ "multi-user.target" ];
151
177
  # runs as nobody
152
- serviceConfig.ExecStart = toString ([
153
- "${pkgs.atftp}/sbin/atftpd"
154
- "--daemon"
155
- "--no-fork"
156
- ] ++ (optional (!isNull cfg.tftp.bindAddress) [ "--bind-address" cfg.tftp.bindAddress ])
157
- ++ [ tftpRoot ]);
178
+ serviceConfig.ExecStart = toString (
179
+ [
180
+ "${pkgs.atftp}/sbin/atftpd"
181
+ "--daemon"
182
+ "--no-fork"
183
+ ]
184
+ ++ (optional (!isNull cfg.tftp.bindAddress) [
185
+ "--bind-address"
186
+ cfg.tftp.bindAddress
187
+ ])
188
+ ++ [ tftpRoot ]
189
+ );
158
190
  };
159
191
 
160
192
  services.nginx = {
@@ -173,7 +205,7 @@ in {
173
205
  "/" = {
174
206
  extraConfig = ''
175
207
  autoindex on;
176
- ${optionalString (cfg.allowedIPv4Ranges != []) ''
208
+ ${optionalString (cfg.allowedIPv4Ranges != [ ]) ''
177
209
  ${concatNl (flip map cfg.allowedIPv4Ranges (range: "allow ${range};"))}
178
210
  deny all;
179
211
  ''}
@@ -184,4 +216,4 @@ in {
184
216
  };
185
217
  };
186
218
  };
187
- }
219
+ }