Merge pull request #263462 from nikstur/rebuildable-system

Rebuildable system & appliance
This commit is contained in:
Robert Hensing 2023-10-29 08:02:35 +01:00 committed by GitHub
commit 8b385c91c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 160 additions and 39 deletions

View file

@ -0,0 +1,21 @@
# Non Switchable Systems {#sec-non-switchable-system}
In certain systems, most notably image based appliances, updates are handled
outside the system. This means that you do not need to rebuild your
configuration on the system itself anymore.
If you want to build such a system, you can use the `image-based-appliance`
profile:
```nix
{ modulesPath, ... }: {
imports = [ "${modulesPath}/profiles/image-based-appliance.nix" ]
}
```
The most notable deviation of this profile from a standard NixOS configuration
is that after building it, you cannot switch *to* the configuration anymore.
The profile sets `config.system.switch.enable = false;`, which excludes
`switch-to-configuration`, the central script called by `nixos-rebuild`, from
your system. Removing this script makes the image lighter and slightly more
secure.

View file

@ -55,4 +55,5 @@ explained in the next sections.
```{=include=} sections
unit-handling.section.md
activation-script.section.md
non-switchable-systems.section.md
```

View file

@ -345,6 +345,11 @@
## Other Notable Changes {#sec-release-23.11-notable-changes}
- A new option `system.switch.enable` was added. By default, this is option is
enabled. Disabling it makes the system unable to be reconfigured via
`nixos-rebuild`. This is good for image based appliances where updates are
handled outside the image.
- The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration.
- GNOME, Pantheon, Cinnamon module no longer forces Qt applications to use Adwaita style since it was buggy and is no longer maintained upstream (specifically, Cinnamon now defaults to the gtk2 style instead, following the default in Linux Mint). If you still want it, you can add the following options to your configuration but it will probably be eventually removed:

View file

@ -1408,6 +1408,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

View file

@ -0,0 +1,26 @@
# This profile sets up a sytem for image based appliance usage. An appliance is
# installed as an image, cannot be re-built, has no Nix available, and is
# generally not meant for interactive use. Updates to such an appliance are
# handled by updating whole partition images via a tool like systemd-sysupdate.
{ lib, modulesPath, ... }:
{
# Appliances are always "minimal".
imports = [
"${modulesPath}/profiles/minimal.nix"
];
# The system cannot be rebuilt.
nix.enable = false;
system.switch.enable = false;
# The system is static.
users.mutableUsers = false;
# The system avoids interpreters as much as possible to reduce its attack
# surface.
boot.initrd.systemd.enable = lib.mkDefault true;
networking.useNetworkd = lib.mkDefault true;
}

View file

@ -18,6 +18,15 @@ with lib;
documentation.nixos.enable = mkDefault false;
# Perl is a default package.
environment.defaultPackages = mkDefault [ ];
# The lessopen package pulls in Perl.
programs.less.lessopen = mkDefault null;
# This pulls in nixos-containers which depends on Perl.
boot.enableContainers = mkDefault false;
programs.command-not-found.enable = mkDefault false;
services.logrotate.enable = mkDefault false;

View file

@ -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}
'';
};
}

View file

@ -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
''}
'';
};
}

View file

@ -582,6 +582,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 {};

View file

@ -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")
'';
}