nixos/activation/bootspec: module-ify

This does the following:

* turns bootspec into a NixOS module
* validates bootspecs with Cue
* exposes internal knobs
This commit is contained in:
Raito Bezarius 2022-11-30 17:55:41 +01:00 committed by Cole Helbling
parent 9a431a57b1
commit 348ba1b33c
4 changed files with 81 additions and 23 deletions

View file

@ -1241,6 +1241,7 @@
./services/x11/xserver.nix
./system/activation/activation-script.nix
./system/activation/specialisation.nix
./system/activation/bootspec.nix
./system/activation/top-level.nix
./system/boot/binfmt.nix
./system/boot/emergency-mode.nix

View file

@ -0,0 +1,23 @@
#V1: {
init: string
initrd?: string
initrdSecrets?: string
kernel: string
kernelParams: [...string]
label: string
toplevel: string
specialisation?: {
[=~"^"]: #V1
}
extensions?: {...}
}
#SecureBootExtensions: #V1 & {
extensions: {
osRelease: string
}
}
Document: {
v1: #V1
}

View file

@ -3,23 +3,31 @@
# Changes to the structure of the document, or the semantics of the values should go through an RFC.
#
# See: https://github.com/NixOS/rfcs/pull/125
{ config, pkgs, lib, children }:
{ config
, pkgs
, lib
, ...
}:
let
cfg = config.boot.bootspec;
children = lib.mapAttrs (childName: childConfig: childConfig.configuration.system.build.toplevel) config.specialisation;
schemas = {
v1 = rec {
filename = "boot.v1.json";
filename = "boot.json";
json =
pkgs.writeText filename
(builtins.toJSON
{
schemaVersion = 1;
{
v1 = {
kernel = "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
kernelParams = config.boot.kernelParams;
initrd = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
initrdSecrets = "${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets";
label = "NixOS ${config.system.nixos.codeName} ${config.system.nixos.label} (Linux ${config.boot.kernelPackages.kernel.modDirVersion})";
});
inherit (cfg) extensions;
};
});
generator =
let
@ -31,8 +39,8 @@ let
mkdir -p $out/bootspec
${pkgs.jq}/bin/jq '
.toplevel = $toplevel |
.init = $init
.v1.toplevel = $toplevel |
.v1.init = $init
' \
--sort-keys \
--arg toplevel "$out" \
@ -40,17 +48,50 @@ let
< ${json} \
| ${pkgs.jq}/bin/jq \
--sort-keys \
'.specialisation = ($ARGS.named | map_values(. | first))' \
'.v1.specialisation = ($ARGS.named | map_values(. | first | .v1))' \
${lib.concatStringsSep " " specialisationLoader} \
> $out/bootspec/${filename}
'';
validator = pkgs.writeCueValidator ./bootspec.cue {
document = "Document"; # Universal validator for any version as long the schema is correctly set.
};
};
};
in
{
# This will be run as a part of the `systemBuilder` in ./top-level.nix. This
# means `$out` points to the output of `config.system.build.toplevel` and can
# be used for a variety of things (though, for now, it's only used to report
# the path of the `toplevel` itself and the `init` executable).
writer = schemas.v1.generator;
options.boot.bootspec = {
enable = lib.mkEnableOption "Enable generation of RFC-0125 bootspec in $system/bootspec, e.g. /run/current-system/bootspec";
extensions = lib.mkOption {
type = lib.types.attrs;
default = {};
};
# This will be run as a part of the `systemBuilder` in ./top-level.nix. This
# means `$out` points to the output of `config.system.build.toplevel` and can
# be used for a variety of things (though, for now, it's only used to report
# the path of the `toplevel` itself and the `init` executable).
writer = lib.mkOption {
internal = true;
default = schemas.v1.generator;
};
validator = lib.mkOption {
internal = true;
default = schemas.v1.validator;
};
filename = lib.mkOption {
internal = true;
default = schemas.v1.filename;
};
};
config = lib.mkIf (cfg.enable) {
warnings = [
''RFC-0125 is not merged yet, this is a feature preview of bootspec.
Schema is not definitive and features are not stabilized until RFC-0125 is merged.
See:
- https://github.com/NixOS/nixpkgs/pull/172237 to track merge status in nixpkgs.
- https://github.com/NixOS/rfcs/pull/125 to track RFC status.
''
];
};
}

View file

@ -9,14 +9,6 @@ let
"${config.system.boot.loader.kernelFile}";
initrdPath = "${config.system.build.initialRamdisk}/" +
"${config.system.boot.loader.initrdFile}";
bootSpec = import ./bootspec.nix {
inherit
config
pkgs
lib
children;
};
in ''
mkdir $out
@ -88,7 +80,8 @@ let
echo -n "${toString config.system.extraDependencies}" > $out/extra-dependencies
${optionalString (!config.boot.isContainer) ''
${bootSpec.writer}
${config.boot.bootspec.writer}
${config.boot.bootspec.validator} "$out/bootspec/${config.boot.bootspec.filename}"
''}
${config.system.extraSystemBuilderCmds}