Merge pull request #172237 from DeterminateSystems/bootspec-rfc
Support external bootloader backends (RFC-0125)
This commit is contained in:
commit
668a2b2f33
14 changed files with 536 additions and 0 deletions
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
@ -78,6 +78,8 @@
|
||||||
/nixos/doc/manual/man-nixos-option.xml @nbp
|
/nixos/doc/manual/man-nixos-option.xml @nbp
|
||||||
/nixos/modules/installer/tools/nixos-option.sh @nbp
|
/nixos/modules/installer/tools/nixos-option.sh @nbp
|
||||||
/nixos/modules/system @dasJ
|
/nixos/modules/system @dasJ
|
||||||
|
/nixos/modules/system/activation/bootspec.nix @grahamc @cole-h @raitobezarius
|
||||||
|
/nixos/modules/system/activation/bootspec.cue @grahamc @cole-h @raitobezarius
|
||||||
|
|
||||||
# NixOS integration test driver
|
# NixOS integration test driver
|
||||||
/nixos/lib/test-driver @tfc
|
/nixos/lib/test-driver @tfc
|
||||||
|
|
36
nixos/doc/manual/development/bootspec.chapter.md
Normal file
36
nixos/doc/manual/development/bootspec.chapter.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# Experimental feature: Bootspec {#sec-experimental-bootspec}
|
||||||
|
|
||||||
|
Bootspec is a experimental feature, introduced in the [RFC-0125 proposal](https://github.com/NixOS/rfcs/pull/125), the reference implementation can be found [there](https://github.com/NixOS/nixpkgs/pull/172237) in order to standardize bootloader support
|
||||||
|
and advanced boot workflows such as SecureBoot and potentially more.
|
||||||
|
|
||||||
|
You can enable the creation of bootspec documents through [`boot.bootspec.enable = true`](options.html#opt-boot.bootspec.enable), which will prompt a warning until [RFC-0125](https://github.com/NixOS/rfcs/pull/125) is officially merged.
|
||||||
|
|
||||||
|
## Schema {#sec-experimental-bootspec-schema}
|
||||||
|
|
||||||
|
The bootspec schema is versioned and validated against [a CUE schema file](https://cuelang.org/) which should considered as the source of truth for your applications.
|
||||||
|
|
||||||
|
You will find the current version [here](../../../modules/system/activation/bootspec.cue).
|
||||||
|
|
||||||
|
## Extensions mechanism {#sec-experimental-bootspec-extensions}
|
||||||
|
|
||||||
|
Bootspec cannot account for all usecases.
|
||||||
|
|
||||||
|
For this purpose, Bootspec offers a generic extension facility [`boot.bootspec.extensions`](options.html#opt-boot.bootspec.extensions) which can be used to inject any data needed for your usecases.
|
||||||
|
|
||||||
|
An example for SecureBoot is to get the Nix store path to `/etc/os-release` in order to bake it into a unified kernel image:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ config, lib, ... }: {
|
||||||
|
boot.bootspec.extensions = {
|
||||||
|
"org.secureboot.osRelease" = config.environment.etc."os-release".source;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To reduce incompatibility and prevent names from clashing between applications, it is **highly recommended** to use a unique namespace for your extensions.
|
||||||
|
|
||||||
|
## External bootloaders {#sec-experimental-bootspec-external-bootloaders}
|
||||||
|
|
||||||
|
It is possible to enable your own bootloader through [`boot.loader.external.installHook`](options.html#opt-boot.loader.external.installHook) which can wrap an existing bootloader.
|
||||||
|
|
||||||
|
Currently, there is no good story to compose existing bootloaders to enrich their features, e.g. SecureBoot, etc. It will be necessary to reimplement or reuse existing parts.
|
|
@ -12,6 +12,7 @@
|
||||||
<xi:include href="../from_md/development/sources.chapter.xml" />
|
<xi:include href="../from_md/development/sources.chapter.xml" />
|
||||||
<xi:include href="../from_md/development/writing-modules.chapter.xml" />
|
<xi:include href="../from_md/development/writing-modules.chapter.xml" />
|
||||||
<xi:include href="../from_md/development/building-parts.chapter.xml" />
|
<xi:include href="../from_md/development/building-parts.chapter.xml" />
|
||||||
|
<xi:include href="../from_md/development/bootspec.chapter.xml" />
|
||||||
<xi:include href="../from_md/development/what-happens-during-a-system-switch.chapter.xml" />
|
<xi:include href="../from_md/development/what-happens-during-a-system-switch.chapter.xml" />
|
||||||
<xi:include href="../from_md/development/writing-documentation.chapter.xml" />
|
<xi:include href="../from_md/development/writing-documentation.chapter.xml" />
|
||||||
<xi:include href="../from_md/development/nixos-tests.chapter.xml" />
|
<xi:include href="../from_md/development/nixos-tests.chapter.xml" />
|
||||||
|
|
73
nixos/doc/manual/from_md/development/bootspec.chapter.xml
Normal file
73
nixos/doc/manual/from_md/development/bootspec.chapter.xml
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-experimental-bootspec">
|
||||||
|
<title>Experimental feature: Bootspec</title>
|
||||||
|
<para>
|
||||||
|
Bootspec is a experimental feature, introduced in the
|
||||||
|
<link xlink:href="https://github.com/NixOS/rfcs/pull/125">RFC-0125
|
||||||
|
proposal</link>, the reference implementation can be found
|
||||||
|
<link xlink:href="https://github.com/NixOS/nixpkgs/pull/172237">there</link>
|
||||||
|
in order to standardize bootloader support and advanced boot
|
||||||
|
workflows such as SecureBoot and potentially more.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
You can enable the creation of bootspec documents through
|
||||||
|
<link xlink:href="options.html#opt-boot.bootspec.enable"><literal>boot.bootspec.enable = true</literal></link>,
|
||||||
|
which will prompt a warning until
|
||||||
|
<link xlink:href="https://github.com/NixOS/rfcs/pull/125">RFC-0125</link>
|
||||||
|
is officially merged.
|
||||||
|
</para>
|
||||||
|
<section xml:id="sec-experimental-bootspec-schema">
|
||||||
|
<title>Schema</title>
|
||||||
|
<para>
|
||||||
|
The bootspec schema is versioned and validated against
|
||||||
|
<link xlink:href="https://cuelang.org/">a CUE schema file</link>
|
||||||
|
which should considered as the source of truth for your
|
||||||
|
applications.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
You will find the current version
|
||||||
|
<link xlink:href="../../../modules/system/activation/bootspec.cue">here</link>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
<section xml:id="sec-experimental-bootspec-extensions">
|
||||||
|
<title>Extensions mechanism</title>
|
||||||
|
<para>
|
||||||
|
Bootspec cannot account for all usecases.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
For this purpose, Bootspec offers a generic extension facility
|
||||||
|
<link xlink:href="options.html#opt-boot.bootspec.extensions"><literal>boot.bootspec.extensions</literal></link>
|
||||||
|
which can be used to inject any data needed for your usecases.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
An example for SecureBoot is to get the Nix store path to
|
||||||
|
<literal>/etc/os-release</literal> in order to bake it into a
|
||||||
|
unified kernel image:
|
||||||
|
</para>
|
||||||
|
<programlisting language="bash">
|
||||||
|
{ config, lib, ... }: {
|
||||||
|
boot.bootspec.extensions = {
|
||||||
|
"org.secureboot.osRelease" = config.environment.etc."os-release".source;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
To reduce incompatibility and prevent names from clashing between
|
||||||
|
applications, it is <emphasis role="strong">highly
|
||||||
|
recommended</emphasis> to use a unique namespace for your
|
||||||
|
extensions.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
<section xml:id="sec-experimental-bootspec-external-bootloaders">
|
||||||
|
<title>External bootloaders</title>
|
||||||
|
<para>
|
||||||
|
It is possible to enable your own bootloader through
|
||||||
|
<link xlink:href="options.html#opt-boot.loader.external.installHook"><literal>boot.loader.external.installHook</literal></link>
|
||||||
|
which can wrap an existing bootloader.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Currently, there is no good story to compose existing bootloaders
|
||||||
|
to enrich their features, e.g. SecureBoot, etc. It will be
|
||||||
|
necessary to reimplement or reuse existing parts.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</chapter>
|
|
@ -1246,6 +1246,7 @@
|
||||||
./services/x11/xserver.nix
|
./services/x11/xserver.nix
|
||||||
./system/activation/activation-script.nix
|
./system/activation/activation-script.nix
|
||||||
./system/activation/specialisation.nix
|
./system/activation/specialisation.nix
|
||||||
|
./system/activation/bootspec.nix
|
||||||
./system/activation/top-level.nix
|
./system/activation/top-level.nix
|
||||||
./system/boot/binfmt.nix
|
./system/boot/binfmt.nix
|
||||||
./system/boot/emergency-mode.nix
|
./system/boot/emergency-mode.nix
|
||||||
|
@ -1261,6 +1262,7 @@
|
||||||
./system/boot/loader/grub/grub.nix
|
./system/boot/loader/grub/grub.nix
|
||||||
./system/boot/loader/grub/ipxe.nix
|
./system/boot/loader/grub/ipxe.nix
|
||||||
./system/boot/loader/grub/memtest.nix
|
./system/boot/loader/grub/memtest.nix
|
||||||
|
./system/boot/loader/external/external.nix
|
||||||
./system/boot/loader/init-script/init-script.nix
|
./system/boot/loader/init-script/init-script.nix
|
||||||
./system/boot/loader/loader.nix
|
./system/boot/loader/loader.nix
|
||||||
./system/boot/loader/raspberrypi/raspberrypi.nix
|
./system/boot/loader/raspberrypi/raspberrypi.nix
|
||||||
|
|
17
nixos/modules/system/activation/bootspec.cue
Normal file
17
nixos/modules/system/activation/bootspec.cue
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#V1: {
|
||||||
|
init: string
|
||||||
|
initrd?: string
|
||||||
|
initrdSecrets?: string
|
||||||
|
kernel: string
|
||||||
|
kernelParams: [...string]
|
||||||
|
label: string
|
||||||
|
toplevel: string
|
||||||
|
specialisation?: {
|
||||||
|
[=~"^"]: #V1
|
||||||
|
}
|
||||||
|
extensions?: {...}
|
||||||
|
}
|
||||||
|
|
||||||
|
Document: {
|
||||||
|
v1: #V1
|
||||||
|
}
|
124
nixos/modules/system/activation/bootspec.nix
Normal file
124
nixos/modules/system/activation/bootspec.nix
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
# Note that these schemas are defined by RFC-0125.
|
||||||
|
# This document is considered a stable API, and is depended upon by external tooling.
|
||||||
|
# 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
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.boot.bootspec;
|
||||||
|
children = lib.mapAttrs (childName: childConfig: childConfig.configuration.system.build.toplevel) config.specialisation;
|
||||||
|
schemas = {
|
||||||
|
v1 = rec {
|
||||||
|
filename = "boot.json";
|
||||||
|
json =
|
||||||
|
pkgs.writeText filename
|
||||||
|
(builtins.toJSON
|
||||||
|
{
|
||||||
|
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
|
||||||
|
# NOTE: Be careful to not introduce excess newlines at the end of the
|
||||||
|
# injectors, as that may affect the pipes and redirects.
|
||||||
|
|
||||||
|
# Inject toplevel and init into the bootspec.
|
||||||
|
# This can only be done here because we *cannot* depend on $out
|
||||||
|
# referring to the toplevel, except by living in the toplevel itself.
|
||||||
|
toplevelInjector = lib.escapeShellArgs [
|
||||||
|
"${pkgs.jq}/bin/jq"
|
||||||
|
''
|
||||||
|
.v1.toplevel = $toplevel |
|
||||||
|
.v1.init = $init
|
||||||
|
''
|
||||||
|
"--sort-keys"
|
||||||
|
"--arg" "toplevel" "${placeholder "out"}"
|
||||||
|
"--arg" "init" "${placeholder "out"}/init"
|
||||||
|
] + " < ${json}";
|
||||||
|
|
||||||
|
# We slurp all specialisations and inject them as values, such that
|
||||||
|
# `.specialisations.${name}` embeds the specialisation's bootspec
|
||||||
|
# document.
|
||||||
|
specialisationInjector =
|
||||||
|
let
|
||||||
|
specialisationLoader = (lib.mapAttrsToList
|
||||||
|
(childName: childToplevel: lib.escapeShellArgs [ "--slurpfile" childName "${childToplevel}/bootspec/${filename}" ])
|
||||||
|
children);
|
||||||
|
in
|
||||||
|
lib.escapeShellArgs [
|
||||||
|
"${pkgs.jq}/bin/jq"
|
||||||
|
"--sort-keys"
|
||||||
|
".v1.specialisation = ($ARGS.named | map_values(. | first | .v1))"
|
||||||
|
] + " ${lib.concatStringsSep " " specialisationLoader}";
|
||||||
|
in
|
||||||
|
''
|
||||||
|
mkdir -p $out/bootspec
|
||||||
|
|
||||||
|
${toplevelInjector} | ${specialisationInjector} > $out/bootspec/${filename}
|
||||||
|
'';
|
||||||
|
|
||||||
|
validator = pkgs.writeCueValidator ./bootspec.cue {
|
||||||
|
document = "Document"; # Universal validator for any version as long the schema is correctly set.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.boot.bootspec = {
|
||||||
|
enable = lib.mkEnableOption (lib.mdDoc "Enable generation of RFC-0125 bootspec in $system/bootspec, e.g. /run/current-system/bootspec");
|
||||||
|
|
||||||
|
extensions = lib.mkOption {
|
||||||
|
type = lib.types.attrs;
|
||||||
|
default = { };
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
User-defined data that extends the bootspec document.
|
||||||
|
|
||||||
|
To reduce incompatibility and prevent names from clashing
|
||||||
|
between applications, it is **highly recommended** to use a
|
||||||
|
unique namespace for your extensions.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
The schema is not definitive and features are not guaranteed to be stable 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.
|
||||||
|
''
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
|
@ -79,6 +79,11 @@ let
|
||||||
|
|
||||||
echo -n "$extraDependencies" > $out/extra-dependencies
|
echo -n "$extraDependencies" > $out/extra-dependencies
|
||||||
|
|
||||||
|
${optionalString (!config.boot.isContainer && config.boot.bootspec.enable) ''
|
||||||
|
${config.boot.bootspec.writer}
|
||||||
|
${config.boot.bootspec.validator} "$out/bootspec/${config.boot.bootspec.filename}"
|
||||||
|
''}
|
||||||
|
|
||||||
${config.system.extraSystemBuilderCmds}
|
${config.system.extraSystemBuilderCmds}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|
26
nixos/modules/system/boot/loader/external/external.md
vendored
Normal file
26
nixos/modules/system/boot/loader/external/external.md
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# External Bootloader Backends {#sec-bootloader-external}
|
||||||
|
|
||||||
|
NixOS has support for several bootloader backends by default: systemd-boot, grub, uboot, etc.
|
||||||
|
The built-in bootloader backend support is generic and supports most use cases.
|
||||||
|
Some users may prefer to create advanced workflows around managing the bootloader and bootable entries.
|
||||||
|
|
||||||
|
You can replace the built-in bootloader support with your own tooling using the "external" bootloader option.
|
||||||
|
|
||||||
|
Imagine you have created a new package called FooBoot.
|
||||||
|
FooBoot provides a program at `${pkgs.fooboot}/bin/fooboot-install` which takes the system closure's path as its only argument and configures the system's bootloader.
|
||||||
|
|
||||||
|
You can enable FooBoot like this:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ pkgs, ... }: {
|
||||||
|
boot.loader.external = {
|
||||||
|
enable = true;
|
||||||
|
installHook = "${pkgs.fooboot}/bin/fooboot-install";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Developing Custom Bootloader Backends
|
||||||
|
|
||||||
|
Bootloaders should use [RFC-0125](https://github.com/NixOS/rfcs/pull/125)'s Bootspec format and synthesis tools to identify the key properties for bootable system generations.
|
||||||
|
|
38
nixos/modules/system/boot/loader/external/external.nix
vendored
Normal file
38
nixos/modules/system/boot/loader/external/external.nix
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.boot.loader.external;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
meta = {
|
||||||
|
maintainers = with maintainers; [ cole-h grahamc raitobezarius ];
|
||||||
|
# Don't edit the docbook xml directly, edit the md and generate it:
|
||||||
|
# `pandoc external.md -t docbook --top-level-division=chapter --extract-media=media -f markdown+smart > external.xml`
|
||||||
|
doc = ./external.xml;
|
||||||
|
};
|
||||||
|
|
||||||
|
options.boot.loader.external = {
|
||||||
|
enable = mkEnableOption (lib.mdDoc "use an external tool to install your bootloader");
|
||||||
|
|
||||||
|
installHook = mkOption {
|
||||||
|
type = with types; path;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
The full path to a program of your choosing which performs the bootloader installation process.
|
||||||
|
|
||||||
|
The program will be called with an argument pointing to the output of the system's toplevel.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
boot.loader = {
|
||||||
|
grub.enable = mkDefault false;
|
||||||
|
systemd-boot.enable = mkDefault false;
|
||||||
|
supportsInitrdSecrets = mkDefault false;
|
||||||
|
};
|
||||||
|
|
||||||
|
system.build.installBootLoader = cfg.installHook;
|
||||||
|
};
|
||||||
|
}
|
41
nixos/modules/system/boot/loader/external/external.xml
vendored
Normal file
41
nixos/modules/system/boot/loader/external/external.xml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-bootloader-external">
|
||||||
|
<title>External Bootloader Backends</title>
|
||||||
|
<para>
|
||||||
|
NixOS has support for several bootloader backends by default:
|
||||||
|
systemd-boot, grub, uboot, etc. The built-in bootloader backend
|
||||||
|
support is generic and supports most use cases. Some users may
|
||||||
|
prefer to create advanced workflows around managing the bootloader
|
||||||
|
and bootable entries.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
You can replace the built-in bootloader support with your own
|
||||||
|
tooling using the <quote>external</quote> bootloader option.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Imagine you have created a new package called FooBoot. FooBoot
|
||||||
|
provides a program at
|
||||||
|
<literal>${pkgs.fooboot}/bin/fooboot-install</literal> which takes
|
||||||
|
the system closure’s path as its only argument and configures the
|
||||||
|
system’s bootloader.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
You can enable FooBoot like this:
|
||||||
|
</para>
|
||||||
|
<programlisting language="nix">
|
||||||
|
{ pkgs, ... }: {
|
||||||
|
boot.loader.external = {
|
||||||
|
enable = true;
|
||||||
|
installHook = "${pkgs.fooboot}/bin/fooboot-install";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<section xml:id="developing-custom-bootloader-backends">
|
||||||
|
<title>Developing Custom Bootloader Backends</title>
|
||||||
|
<para>
|
||||||
|
Bootloaders should use
|
||||||
|
<link xlink:href="https://github.com/NixOS/rfcs/pull/125">RFC-0125</link>’s
|
||||||
|
Bootspec format and synthesis tools to identify the key properties
|
||||||
|
for bootable system generations.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</chapter>
|
144
nixos/tests/bootspec.nix
Normal file
144
nixos/tests/bootspec.nix
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
{ system ? builtins.currentSystem,
|
||||||
|
config ? {},
|
||||||
|
pkgs ? import ../.. { inherit system config; }
|
||||||
|
}:
|
||||||
|
|
||||||
|
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||||
|
with pkgs.lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
baseline = {
|
||||||
|
virtualisation.useBootLoader = true;
|
||||||
|
};
|
||||||
|
grub = {
|
||||||
|
boot.loader.grub.enable = true;
|
||||||
|
};
|
||||||
|
systemd-boot = {
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
};
|
||||||
|
uefi = {
|
||||||
|
virtualisation.useEFIBoot = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
boot.loader.grub.efiSupport = true;
|
||||||
|
environment.systemPackages = [ pkgs.efibootmgr ];
|
||||||
|
};
|
||||||
|
standard = {
|
||||||
|
boot.bootspec.enable = true;
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
baseline
|
||||||
|
systemd-boot
|
||||||
|
uefi
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
basic = makeTest {
|
||||||
|
name = "systemd-boot-with-bootspec";
|
||||||
|
meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ];
|
||||||
|
|
||||||
|
nodes.machine = standard;
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
machine.succeed("test -e /run/current-system/bootspec/boot.json")
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
grub = makeTest {
|
||||||
|
name = "grub-with-bootspec";
|
||||||
|
meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ];
|
||||||
|
|
||||||
|
nodes.machine = {
|
||||||
|
boot.bootspec.enable = true;
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
baseline
|
||||||
|
grub
|
||||||
|
uefi
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
machine.succeed("test -e /run/current-system/bootspec/boot.json")
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
legacy-boot = makeTest {
|
||||||
|
name = "legacy-boot-with-bootspec";
|
||||||
|
meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ];
|
||||||
|
|
||||||
|
nodes.machine = {
|
||||||
|
boot.bootspec.enable = true;
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
baseline
|
||||||
|
grub
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
machine.succeed("test -e /run/current-system/bootspec/boot.json")
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Check that specialisations create corresponding entries in bootspec.
|
||||||
|
specialisation = makeTest {
|
||||||
|
name = "bootspec-with-specialisation";
|
||||||
|
meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ];
|
||||||
|
|
||||||
|
nodes.machine = {
|
||||||
|
imports = [ standard ];
|
||||||
|
environment.systemPackages = [ pkgs.jq ];
|
||||||
|
specialisation.something.configuration = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
import json
|
||||||
|
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
machine.succeed("test -e /run/current-system/bootspec/boot.json")
|
||||||
|
machine.succeed("test -e /run/current-system/specialisation/something/bootspec/boot.json")
|
||||||
|
|
||||||
|
sp_in_parent = json.loads(machine.succeed("jq -r '.v1.specialisation.something' /run/current-system/bootspec/boot.json"))
|
||||||
|
sp_in_fs = json.loads(machine.succeed("cat /run/current-system/specialisation/something/bootspec/boot.json"))
|
||||||
|
|
||||||
|
assert sp_in_parent == sp_in_fs['v1'], "Bootspecs of the same specialisation are different!"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Check that extensions are propagated.
|
||||||
|
extensions = makeTest {
|
||||||
|
name = "bootspec-with-extensions";
|
||||||
|
meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ];
|
||||||
|
|
||||||
|
nodes.machine = { config, ... }: {
|
||||||
|
imports = [ standard ];
|
||||||
|
environment.systemPackages = [ pkgs.jq ];
|
||||||
|
boot.bootspec.extensions = {
|
||||||
|
osRelease = config.environment.etc."os-release".source;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
current_os_release = machine.succeed("cat /etc/os-release")
|
||||||
|
bootspec_os_release = machine.succeed("cat $(jq -r '.v1.extensions.osRelease' /run/current-system/bootspec/boot.json)")
|
||||||
|
|
||||||
|
assert current_os_release == bootspec_os_release, "Filename referenced by extension has unexpected contents"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
25
pkgs/tools/misc/bootspec/default.nix
Normal file
25
pkgs/tools/misc/bootspec/default.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{ lib
|
||||||
|
, rustPlatform
|
||||||
|
, fetchFromGitHub
|
||||||
|
}:
|
||||||
|
rustPlatform.buildRustPackage rec {
|
||||||
|
pname = "bootspec";
|
||||||
|
version = "unstable-2022-12-05";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "DeterminateSystems";
|
||||||
|
repo = pname;
|
||||||
|
rev = "67a617ab6b99211daa92e748d27ead3f78127cf8";
|
||||||
|
hash = "sha256-GX6Tzs/ClTUV9OXLvPFw6uBhrpCWSMI+PfrViyFEIxs=";
|
||||||
|
};
|
||||||
|
|
||||||
|
cargoHash = "sha256-N/hbfjsuvwCc0mxOpeVVcTxb5cA024lyLSEpVcrS7kA=";
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Implementation of RFC-0125's datatype and synthesis tooling";
|
||||||
|
homepage = "https://github.com/DeterminateSystems/bootspec";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = teams.determinatesystems.members;
|
||||||
|
platforms = platforms.unix;
|
||||||
|
};
|
||||||
|
}
|
|
@ -2705,6 +2705,8 @@ with pkgs;
|
||||||
|
|
||||||
brewtarget = libsForQt5.callPackage ../applications/misc/brewtarget { } ;
|
brewtarget = libsForQt5.callPackage ../applications/misc/brewtarget { } ;
|
||||||
|
|
||||||
|
bootspec = callPackage ../tools/misc/bootspec { };
|
||||||
|
|
||||||
# Derivation's result is not used by nixpkgs. Useful for validation for
|
# Derivation's result is not used by nixpkgs. Useful for validation for
|
||||||
# regressions of bootstrapTools on hydra and on ofborg. Example:
|
# regressions of bootstrapTools on hydra and on ofborg. Example:
|
||||||
# pkgsCross.aarch64-multiplatform.freshBootstrapTools.build
|
# pkgsCross.aarch64-multiplatform.freshBootstrapTools.build
|
||||||
|
|
Loading…
Reference in a new issue