From 4aa1d3a39556c1e586819e69ebc2b21867563243 Mon Sep 17 00:00:00 2001 From: Luke Granger-Brown Date: Sun, 31 Oct 2021 11:20:04 +0000 Subject: [PATCH] 3p/nixpkgs: pull PR #108338 --- ...ot-create-boot-entries-for-specialis.patch | 204 ++++++++++++++++++ third_party/nixpkgs/patches/series | 1 + 2 files changed, 205 insertions(+) create mode 100644 third_party/nixpkgs/patches/0001-nixos-systemd-boot-create-boot-entries-for-specialis.patch diff --git a/third_party/nixpkgs/patches/0001-nixos-systemd-boot-create-boot-entries-for-specialis.patch b/third_party/nixpkgs/patches/0001-nixos-systemd-boot-create-boot-entries-for-specialis.patch new file mode 100644 index 0000000000..025c67a573 --- /dev/null +++ b/third_party/nixpkgs/patches/0001-nixos-systemd-boot-create-boot-entries-for-specialis.patch @@ -0,0 +1,204 @@ +From 13fad0f81b2bd50fd421bd5856a35f1f7c032257 Mon Sep 17 00:00:00 2001 +From: Luke Granger-Brown +Date: Sun, 3 Jan 2021 18:29:34 +0000 +Subject: [PATCH] nixos/systemd-boot: create boot entries for specialisations + +Some specialisations (such as those which affect various boot-time +attributes) cannot be switched to at runtime. This allows picking the +specialisation at boot time. +--- + .../systemd-boot/systemd-boot-builder.py | 73 +++++++++++++------ + nixos/tests/systemd-boot.nix | 23 ++++++ + 2 files changed, 73 insertions(+), 23 deletions(-) + +diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +index 6c26b4e0f87..c38bef9d6d4 100644 +--- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py ++++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +@@ -17,19 +17,28 @@ import glob + import os.path + from typing import Tuple, List, Optional + ++SystemIdentifier = Tuple[Optional[str], int, Optional[str]] ++ + + def copy_if_not_exists(source: str, dest: str) -> None: + if not os.path.exists(dest): + shutil.copyfile(source, dest) + + +-def system_dir(profile: Optional[str], generation: int) -> str: ++def generation_dir(profile: Optional[str], generation: int) -> str: + if profile: + return "/nix/var/nix/profiles/system-profiles/%s-%d-link" % (profile, generation) + else: + return "/nix/var/nix/profiles/system-%d-link" % (generation) + +-BOOT_ENTRY = """title NixOS{profile} ++def system_dir(profile: Optional[str], generation: int, specialisation: Optional[str]) -> str: ++ d = generation_dir(profile, generation) ++ if specialisation: ++ return os.path.join(d, "specialisation", specialisation) ++ else: ++ return d ++ ++BOOT_ENTRY = """title NixOS{profile}{specialisation} + version Generation {generation} {description} + linux {kernel} + initrd {initrd} +@@ -46,26 +55,34 @@ efi /efi/memtest86/BOOTX64.efi + """ + + +-def write_loader_conf(profile: Optional[str], generation: int) -> None: ++def generation_conf_filename(profile: Optional[str], generation: int, specialisation: Optional[str]) -> str: ++ pieces = [ ++ "nixos", ++ profile or None, ++ "generation", ++ str(generation), ++ f"specialisation-{specialisation}" if specialisation else None, ++ ] ++ return "-".join(p for p in pieces if p) + ".conf" ++ ++ ++def write_loader_conf(profile: Optional[str], generation: int, specialisation: Optional[str]) -> None: + with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f: + if "@timeout@" != "": + f.write("timeout @timeout@\n") +- if profile: +- f.write("default nixos-%s-generation-%d.conf\n" % (profile, generation)) +- else: +- f.write("default nixos-generation-%d.conf\n" % (generation)) ++ f.write("default %s\n" % generation_conf_filename(profile, generation, specialisation)) + if not @editor@: + f.write("editor 0\n"); + f.write("console-mode @consoleMode@\n"); + os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf") + + +-def profile_path(profile: Optional[str], generation: int, name: str) -> str: +- return os.path.realpath("%s/%s" % (system_dir(profile, generation), name)) ++def profile_path(profile: Optional[str], generation: int, specialisation: Optional[str], name: str) -> str: ++ return os.path.realpath("%s/%s" % (system_dir(profile, generation, specialisation), name)) + + +-def copy_from_profile(profile: Optional[str], generation: int, name: str, dry_run: bool = False) -> str: +- store_file_path = profile_path(profile, generation, name) ++def copy_from_profile(profile: Optional[str], generation: int, specialisation: Optional[str], name: str, dry_run: bool = False) -> str: ++ store_file_path = profile_path(profile, generation, specialisation, name) + suffix = os.path.basename(store_file_path) + store_dir = os.path.basename(os.path.dirname(store_file_path)) + efi_file_path = "/efi/nixos/%s-%s.efi" % (store_dir, suffix) +@@ -95,19 +112,17 @@ def describe_generation(generation_dir: str) -> str: + return description + + +-def write_entry(profile: Optional[str], generation: int, machine_id: str) -> None: +- kernel = copy_from_profile(profile, generation, "kernel") +- initrd = copy_from_profile(profile, generation, "initrd") ++def write_entry(profile: Optional[str], generation: int, specialisation: Optional[str], machine_id: str) -> None: ++ kernel = copy_from_profile(profile, generation, specialisation, "kernel") ++ initrd = copy_from_profile(profile, generation, specialisation, "initrd") + try: +- append_initrd_secrets = profile_path(profile, generation, "append-initrd-secrets") ++ append_initrd_secrets = profile_path(profile, generation, specialisation, "append-initrd-secrets") + subprocess.check_call([append_initrd_secrets, "@efiSysMountPoint@%s" % (initrd)]) + except FileNotFoundError: + pass +- if profile: +- entry_file = "@efiSysMountPoint@/loader/entries/nixos-%s-generation-%d.conf" % (profile, generation) +- else: +- entry_file = "@efiSysMountPoint@/loader/entries/nixos-generation-%d.conf" % (generation) +- generation_dir = os.readlink(system_dir(profile, generation)) ++ entry_file = "@efiSysMountPoint@/loader/entries/%s" % ( ++ generation_conf_filename(profile, generation, specialisation)) ++ generation_dir = os.readlink(system_dir(profile, generation, specialisation)) + tmp_path = "%s.tmp" % (entry_file) + kernel_params = "init=%s/init " % generation_dir + +@@ -115,6 +130,7 @@ def write_entry(profile: Optional[str], generation: int, machine_id: str) -> Non + kernel_params = kernel_params + params_file.read() + with open(tmp_path, 'w') as f: + f.write(BOOT_ENTRY.format(profile=" [" + profile + "]" if profile else "", ++ specialisation=" (%s)" % specialisation if specialisation else "", + generation=generation, + kernel=kernel, + initrd=initrd, +@@ -133,7 +149,7 @@ def mkdir_p(path: str) -> None: + raise + + +-def get_generations(profile: Optional[str] = None) -> List[Tuple[Optional[str], int]]: ++def get_generations(profile: Optional[str] = None) -> List[SystemIdentifier]: + gen_list = subprocess.check_output([ + "@nix@/bin/nix-env", + "--list-generations", +@@ -145,10 +161,19 @@ def get_generations(profile: Optional[str] = None) -> List[Tuple[Optional[str], + gen_lines.pop() + + configurationLimit = @configurationLimit@ +- return [ (profile, int(line.split()[0])) for line in gen_lines ][-configurationLimit:] ++ configurations: List[SystemIdentifier] = [ (profile, int(line.split()[0]), None) for line in gen_lines ] ++ return configurations[-configurationLimit:] ++ ++ ++def get_specialisations(profile: Optional[str], generation: int, _: Optional[str]) -> List[SystemIdentifier]: ++ specialisations_dir = os.path.join( ++ system_dir(profile, generation, None), "specialisation") ++ if not os.path.exists(specialisations_dir): ++ return [] ++ return [(profile, generation, spec) for spec in os.listdir(specialisations_dir)] + + +-def remove_old_entries(gens: List[Tuple[Optional[str], int]]) -> None: ++def remove_old_entries(gens: List[SystemIdentifier]) -> None: + rex_profile = re.compile("^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$") + rex_generation = re.compile("^@efiSysMountPoint@/loader/entries/nixos.*-generation-(.*)\.conf$") + known_paths = [] +@@ -243,6 +268,8 @@ def main() -> None: + for gen in gens: + try: + write_entry(*gen, machine_id) ++ for specialisation in get_specialisations(*gen): ++ write_entry(*specialisation, machine_id) + if os.readlink(system_dir(*gen)) == args.default_config: + write_loader_conf(*gen) + except OSError as e: +diff --git a/nixos/tests/systemd-boot.nix b/nixos/tests/systemd-boot.nix +index 3c93cb82d64..ae3727afaf6 100644 +--- a/nixos/tests/systemd-boot.nix ++++ b/nixos/tests/systemd-boot.nix +@@ -39,6 +39,29 @@ in + ''; + }; + ++ # Check that specialisations create corresponding boot entries. ++ specialisation = makeTest { ++ name = "systemd-boot-specialisation"; ++ meta.maintainers = with pkgs.stdenv.lib.maintainers; [ lukegb ]; ++ ++ machine = { pkgs, lib, ... }: { ++ imports = [ common ]; ++ specialisation.something.configuration = {}; ++ }; ++ ++ testScript = '' ++ machine.start() ++ machine.wait_for_unit("multi-user.target") ++ ++ machine.succeed( ++ "test -e /boot/loader/entries/nixos-generation-1-specialisation-something.conf" ++ ) ++ machine.succeed( ++ "grep -q 'title NixOS (something)' /boot/loader/entries/nixos-generation-1-specialisation-something.conf" ++ ) ++ ''; ++ }; ++ + # Boot without having created an EFI entry--instead using default "/EFI/BOOT/BOOTX64.EFI" + fallback = makeTest { + name = "systemd-boot-fallback"; +-- +2.33.0 + diff --git a/third_party/nixpkgs/patches/series b/third_party/nixpkgs/patches/series index 324117f1f0..14e579c7a6 100644 --- a/third_party/nixpkgs/patches/series +++ b/third_party/nixpkgs/patches/series @@ -1,2 +1,3 @@ patch-cherrypy.patch pomerium-fix.patch +0001-nixos-systemd-boot-create-boot-entries-for-specialis.patch