From b3c1d8c9aea817c66e8a6384a345390ac36f40eb Mon Sep 17 00:00:00 2001 From: nikstur Date: Sat, 14 Oct 2023 01:29:05 +0200 Subject: [PATCH] nixos: add system.switch.enable flag This flag allows the user to optionally exclude switch-to-confguration.pl from toplevel. This is interesting for appliance images where you don't want to re-build the system. This flag is called `rebuildable` because the standard interface to do this is `nixos-rebuild` which will not work anymore with this change. --- nixos/modules/module-list.nix | 1 + .../system/activation/activatable-system.nix | 65 ++++++++----------- .../system/activation/switchable-system.nix | 55 ++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/non-switchable-system.nix | 15 +++++ 5 files changed, 98 insertions(+), 39 deletions(-) create mode 100644 nixos/modules/system/activation/switchable-system.nix create mode 100644 nixos/tests/non-switchable-system.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 2c06f4931725..496943ad33a2 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1392,6 +1392,7 @@ ./system/activation/activatable-system.nix ./system/activation/activation-script.nix ./system/activation/specialisation.nix + ./system/activation/switchable-system.nix ./system/activation/bootspec.nix ./system/activation/top-level.nix ./system/boot/binfmt.nix diff --git a/nixos/modules/system/activation/activatable-system.nix b/nixos/modules/system/activation/activatable-system.nix index 7f6154794bd8..3d941596747b 100644 --- a/nixos/modules/system/activation/activatable-system.nix +++ b/nixos/modules/system/activation/activatable-system.nix @@ -1,52 +1,16 @@ -{ config, lib, pkgs, ... }: +{ options, config, lib, pkgs, ... }: let inherit (lib) mkOption - optionalString types ; - perlWrapped = pkgs.perl.withPackages (p: with p; [ ConfigIniFiles FileSlurp ]); - systemBuilderArgs = { activationScript = config.system.activationScripts.script; dryActivationScript = config.system.dryActivationScript; }; - systemBuilderCommands = '' - echo "$activationScript" > $out/activate - echo "$dryActivationScript" > $out/dry-activate - substituteInPlace $out/activate --subst-var-by out ''${!toplevelVar} - substituteInPlace $out/dry-activate --subst-var-by out ''${!toplevelVar} - chmod u+x $out/activate $out/dry-activate - unset activationScript dryActivationScript - - mkdir $out/bin - substitute ${./switch-to-configuration.pl} $out/bin/switch-to-configuration \ - --subst-var out \ - --subst-var-by toplevel ''${!toplevelVar} \ - --subst-var-by coreutils "${pkgs.coreutils}" \ - --subst-var-by distroId ${lib.escapeShellArg config.system.nixos.distroId} \ - --subst-var-by installBootLoader ${lib.escapeShellArg config.system.build.installBootLoader} \ - --subst-var-by localeArchive "${config.i18n.glibcLocales}/lib/locale/locale-archive" \ - --subst-var-by perl "${perlWrapped}" \ - --subst-var-by shell "${pkgs.bash}/bin/sh" \ - --subst-var-by su "${pkgs.shadow.su}/bin/su" \ - --subst-var-by systemd "${config.systemd.package}" \ - --subst-var-by utillinux "${pkgs.util-linux}" \ - ; - - chmod +x $out/bin/switch-to-configuration - ${optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) '' - if ! output=$(${perlWrapped}/bin/perl -c $out/bin/switch-to-configuration 2>&1); then - echo "switch-to-configuration syntax is not valid:" - echo "$output" - exit 1 - fi - ''} - ''; - in { options = { @@ -60,6 +24,18 @@ in do, but for image based systems, this may not be needed or not be desirable. ''; }; + system.activatableSystemBuilderCommands = options.system.systemBuilderCommands // { + description = lib.mdDoc '' + Like `system.systemBuilderCommands`, but only for the commands that are + needed *both* when the system is activatable and when it isn't. + + Disclaimer: This option might go away in the future. It might be + superseded by separating switch-to-configuration into a separate script + which will make this option superfluous. See + https://github.com/NixOS/nixpkgs/pull/263462#discussion_r1373104845 for + a discussion. + ''; + }; system.build.separateActivationScript = mkOption { type = types.package; description = '' @@ -71,7 +47,18 @@ in }; }; config = { - system.systemBuilderCommands = lib.mkIf config.system.activatable systemBuilderCommands; + system.activatableSystemBuilderCommands = '' + echo "$activationScript" > $out/activate + echo "$dryActivationScript" > $out/dry-activate + substituteInPlace $out/activate --subst-var-by out ''${!toplevelVar} + substituteInPlace $out/dry-activate --subst-var-by out ''${!toplevelVar} + chmod u+x $out/activate $out/dry-activate + unset activationScript dryActivationScript + ''; + + system.systemBuilderCommands = lib.mkIf + config.system.activatable + config.system.activatableSystemBuilderCommands; system.systemBuilderArgs = lib.mkIf config.system.activatable (systemBuilderArgs // { toplevelVar = "out"; @@ -86,7 +73,7 @@ in }) '' mkdir $out - ${systemBuilderCommands} + ${config.system.activatableSystemBuilderCommands} ''; }; } diff --git a/nixos/modules/system/activation/switchable-system.nix b/nixos/modules/system/activation/switchable-system.nix new file mode 100644 index 000000000000..00bc18e48d1f --- /dev/null +++ b/nixos/modules/system/activation/switchable-system.nix @@ -0,0 +1,55 @@ +{ config, lib, pkgs, ... }: + +let + + perlWrapped = pkgs.perl.withPackages (p: with p; [ ConfigIniFiles FileSlurp ]); + +in + +{ + + options = { + system.switch.enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc '' + Whether to include the capability to switch configurations. + + Disabling this makes the system unable to be reconfigured via `nixos-rebuild`. + + This is good for image based appliances where updates are handled + outside the image. Reducing features makes the image lighter and + slightly more secure. + ''; + }; + }; + + config = lib.mkIf config.system.switch.enable { + system.activatableSystemBuilderCommands = '' + mkdir $out/bin + substitute ${./switch-to-configuration.pl} $out/bin/switch-to-configuration \ + --subst-var out \ + --subst-var-by toplevel ''${!toplevelVar} \ + --subst-var-by coreutils "${pkgs.coreutils}" \ + --subst-var-by distroId ${lib.escapeShellArg config.system.nixos.distroId} \ + --subst-var-by installBootLoader ${lib.escapeShellArg config.system.build.installBootLoader} \ + --subst-var-by localeArchive "${config.i18n.glibcLocales}/lib/locale/locale-archive" \ + --subst-var-by perl "${perlWrapped}" \ + --subst-var-by shell "${pkgs.bash}/bin/sh" \ + --subst-var-by su "${pkgs.shadow.su}/bin/su" \ + --subst-var-by systemd "${config.systemd.package}" \ + --subst-var-by utillinux "${pkgs.util-linux}" \ + ; + + chmod +x $out/bin/switch-to-configuration + ${lib.optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) '' + if ! output=$(${perlWrapped}/bin/perl -c $out/bin/switch-to-configuration 2>&1); then + echo "switch-to-configuration syntax is not valid:" + echo "$output" + exit 1 + fi + ''} + ''; + }; + +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 22371c9fec37..5098b4dfb1e0 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -571,6 +571,7 @@ in { node-red = handleTest ./node-red.nix {}; nomad = handleTest ./nomad.nix {}; non-default-filesystems = handleTest ./non-default-filesystems.nix {}; + non-switchable-system = runTest ./non-switchable-system.nix; noto-fonts = handleTest ./noto-fonts.nix {}; noto-fonts-cjk-qt-default-weight = handleTest ./noto-fonts-cjk-qt-default-weight.nix {}; novacomd = handleTestOn ["x86_64-linux"] ./novacomd.nix {}; diff --git a/nixos/tests/non-switchable-system.nix b/nixos/tests/non-switchable-system.nix new file mode 100644 index 000000000000..54bede75453b --- /dev/null +++ b/nixos/tests/non-switchable-system.nix @@ -0,0 +1,15 @@ +{ lib, ... }: + +{ + name = "non-switchable-system"; + + meta.maintainers = with lib.maintainers; [ nikstur ]; + + nodes.machine = { + system.switch.enable = false; + }; + + testScript = '' + machine.succeed("test ! -e /run/current-system/bin/switch-to-configuration") + ''; +}