diff options
Diffstat (limited to 'nixos')
19 files changed, 327 insertions, 53 deletions
diff --git a/nixos/lib/systemd-unit-options.nix b/nixos/lib/systemd-unit-options.nix index 44f26572a23ba..9c7cb34f14b57 100644 --- a/nixos/lib/systemd-unit-options.nix +++ b/nixos/lib/systemd-unit-options.nix @@ -324,7 +324,11 @@ in rec { scriptArgs = mkOption { type = types.str; default = ""; - description = lib.mdDoc "Arguments passed to the main process script."; + example = "%i"; + description = lib.mdDoc '' + Arguments passed to the main process script. + Can contain specifiers (`%` placeholders expanded by systemd, see {manpage}`systemd.unit(5)`). + ''; }; preStart = mkOption { diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index 5bd343c85fa25..81aca86173899 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -70,14 +70,12 @@ let ; # Timeout in syslinux is in units of 1/10 of a second. - # 0 is used to disable timeouts. + # null means max timeout (35996, just under 1h in 1/10 seconds) + # 0 means disable timeout syslinuxTimeout = if config.boot.loader.timeout == null then - 0 + 35996 else - max (config.boot.loader.timeout * 10) 1; - - - max = x: y: if x > y then x else y; + config.boot.loader.timeout * 10; # The configuration file for syslinux. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 6ec6c74565cd1..b099dcc71c406 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -180,6 +180,7 @@ ./programs/hamster.nix ./programs/htop.nix ./programs/iftop.nix + ./programs/i3lock.nix ./programs/iotop.nix ./programs/java.nix ./programs/k3b.nix @@ -724,6 +725,7 @@ ./services/monitoring/riemann.nix ./services/monitoring/scollector.nix ./services/monitoring/smartd.nix + ./services/monitoring/statsd.nix ./services/monitoring/sysstat.nix ./services/monitoring/teamviewer.nix ./services/monitoring/telegraf.nix diff --git a/nixos/modules/profiles/keys/ssh_host_ed25519_key b/nixos/modules/profiles/keys/ssh_host_ed25519_key new file mode 100644 index 0000000000000..b18489795369e --- /dev/null +++ b/nixos/modules/profiles/keys/ssh_host_ed25519_key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCQVnMW/wZWqrdWrjrRPhfEFFq1KLYguagSflLhFnVQmwAAAJASuMMnErjD +JwAAAAtzc2gtZWQyNTUxOQAAACCQVnMW/wZWqrdWrjrRPhfEFFq1KLYguagSflLhFnVQmw +AAAEDIN2VWFyggtoSPXcAFy8dtG1uAig8sCuyE21eMDt2GgJBWcxb/Blaqt1auOtE+F8QU +WrUotiC5qBJ+UuEWdVCbAAAACnJvb3RAbml4b3MBAgM= +-----END OPENSSH PRIVATE KEY----- diff --git a/nixos/modules/profiles/keys/ssh_host_ed25519_key.pub b/nixos/modules/profiles/keys/ssh_host_ed25519_key.pub new file mode 100644 index 0000000000000..2c45826715fc5 --- /dev/null +++ b/nixos/modules/profiles/keys/ssh_host_ed25519_key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJBWcxb/Blaqt1auOtE+F8QUWrUotiC5qBJ+UuEWdVCb root@nixos diff --git a/nixos/modules/profiles/macos-builder.nix b/nixos/modules/profiles/macos-builder.nix new file mode 100644 index 0000000000000..895dd04cb4852 --- /dev/null +++ b/nixos/modules/profiles/macos-builder.nix @@ -0,0 +1,134 @@ +{ config, pkgs, ... }: + +let + keysDirectory = "/var/keys"; + + user = "builder"; + + keyType = "ed25519"; + +in + +{ imports = [ + ../virtualisation/qemu-vm.nix + ]; + + # The builder is not intended to be used interactively + documentation.enable = false; + + environment.etc = { + "ssh/ssh_host_ed25519_key" = { + mode = "0600"; + + source = ./keys/ssh_host_ed25519_key; + }; + + "ssh/ssh_host_ed25519_key.pub" = { + mode = "0644"; + + source = ./keys/ssh_host_ed25519_key.pub; + }; + }; + + # DNS fails for QEMU user networking (SLiRP) on macOS. See: + # + # https://github.com/utmapp/UTM/issues/2353 + # + # This works around that by using a public DNS server other than the DNS + # server that QEMU provides (normally 10.0.2.3) + networking.nameservers = [ "8.8.8.8" ]; + + nix.settings = { + auto-optimise-store = true; + + min-free = 1024 * 1024 * 1024; + + max-free = 3 * 1024 * 1024 * 1024; + + trusted-users = [ "root" user ]; + }; + + services.openssh = { + enable = true; + + authorizedKeysFiles = [ "${keysDirectory}/%u_${keyType}.pub" ]; + }; + + system.build.macos-builder-installer = + let + privateKey = "/etc/nix/${user}_${keyType}"; + + publicKey = "${privateKey}.pub"; + + # This installCredentials script is written so that it's as easy as + # possible for a user to audit before confirming the `sudo` + installCredentials = pkgs.writeShellScript "install-credentials" '' + KEYS="''${1}" + INSTALL=${hostPkgs.coreutils}/bin/install + "''${INSTALL}" -g nixbld -m 600 "''${KEYS}/${user}_${keyType}" ${privateKey} + "''${INSTALL}" -g nixbld -m 644 "''${KEYS}/${user}_${keyType}.pub" ${publicKey} + ''; + + hostPkgs = config.virtualisation.host.pkgs; + + in + hostPkgs.writeShellScriptBin "create-builder" '' + KEYS="''${KEYS:-./keys}" + ${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}" + PRIVATE_KEY="''${KEYS}/${user}_${keyType}" + PUBLIC_KEY="''${PRIVATE_KEY}.pub" + if [ ! -e "''${PRIVATE_KEY}" ] || [ ! -e "''${PUBLIC_KEY}" ]; then + ${hostPkgs.coreutils}/bin/rm --force -- "''${PRIVATE_KEY}" "''${PUBLIC_KEY}" + ${hostPkgs.openssh}/bin/ssh-keygen -q -f "''${PRIVATE_KEY}" -t ${keyType} -N "" -C 'builder@localhost' + fi + if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then + (set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}") + fi + KEYS="$(nix-store --add "$KEYS")" ${config.system.build.vm}/bin/run-nixos-vm + ''; + + system.stateVersion = "22.05"; + + users.users."${user}"= { + isNormalUser = true; + }; + + virtualisation = { + diskSize = 20 * 1024; + + memorySize = 3 * 1024; + + forwardPorts = [ + { from = "host"; guest.port = 22; host.port = 22; } + ]; + + # Disable graphics for the builder since users will likely want to run it + # non-interactively in the background. + graphics = false; + + sharedDirectories.keys = { + source = "\"$KEYS\""; + target = keysDirectory; + }; + + # If we don't enable this option then the host will fail to delegate builds + # to the guest, because: + # + # - The host will lock the path to build + # - The host will delegate the build to the guest + # - The guest will attempt to lock the same path and fail because + # the lockfile on the host is visible on the guest + # + # Snapshotting the host's /nix/store as an image isolates the guest VM's + # /nix/store from the host's /nix/store, preventing this problem. + useNixStoreImage = true; + + # Obviously the /nix/store needs to be writable on the guest in order for it + # to perform builds. + writableStore = true; + + # This ensures that anything built on the guest isn't lost when the guest is + # restarted. + writableStoreUseTmpfs = false; + }; +} diff --git a/nixos/modules/programs/i3lock.nix b/nixos/modules/programs/i3lock.nix new file mode 100644 index 0000000000000..466ae59c9277f --- /dev/null +++ b/nixos/modules/programs/i3lock.nix @@ -0,0 +1,58 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.programs.i3lock; + +in { + + ###### interface + + options = { + programs.i3lock = { + enable = mkEnableOption (mdDoc "i3lock"); + package = mkOption { + type = types.package; + default = pkgs.i3lock; + defaultText = literalExpression "pkgs.i3lock"; + example = literalExpression '' + pkgs.i3lock-color + ''; + description = mdDoc '' + Specify which package to use for the i3lock program, + The i3lock package must include a i3lock file or link in its out directory in order for the u2fSupport option to work correctly. + ''; + }; + u2fSupport = mkOption { + type = types.bool; + default = false; + example = true; + description = mdDoc '' + Whether to enable U2F support in the i3lock program. + U2F enables authentication using a hardware device, such as a security key. + When U2F support is enabled, the i3lock program will set the setuid bit on the i3lock binary and enable the pam u2fAuth service, + ''; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ cfg.package ]; + + security.wrappers.i3lock = mkIf cfg.u2fSupport { + setuid = true; + owner = "root"; + group = "root"; + source = "${cfg.package.out}/bin/i3lock"; + }; + + security.pam.services.i3lock.u2fAuth = cfg.u2fSupport; + + }; + +} diff --git a/nixos/modules/services/networking/firefox-syncserver.nix b/nixos/modules/services/networking/firefox-syncserver.nix index c3d9f43f74577..9733fb16d9032 100644 --- a/nixos/modules/services/networking/firefox-syncserver.nix +++ b/nixos/modules/services/networking/firefox-syncserver.nix @@ -11,8 +11,10 @@ let format = pkgs.formats.toml {}; settings = { - database_url = dbURL; human_logs = true; + syncstorage = { + database_url = dbURL; + }; tokenserver = { node_type = "mysql"; database_url = dbURL; @@ -253,8 +255,7 @@ in serviceConfig = { User = defaultUser; Group = defaultUser; - ExecStart = "${cfg.package}/bin/syncstorage --config ${configFile}"; - Stderr = "journal"; + ExecStart = "${cfg.package}/bin/syncserver --config ${configFile}"; EnvironmentFile = lib.mkIf (cfg.secrets != null) "${cfg.secrets}"; # hardening diff --git a/nixos/modules/services/networking/rpcbind.nix b/nixos/modules/services/networking/rpcbind.nix index aa04214debb0a..60e78dfec51ba 100644 --- a/nixos/modules/services/networking/rpcbind.nix +++ b/nixos/modules/services/networking/rpcbind.nix @@ -35,6 +35,16 @@ with lib; systemd.services.rpcbind = { wantedBy = [ "multi-user.target" ]; + # rpcbind performs a check for /var/run/rpcbind.lock at startup + # and will crash if /var/run isn't present. In the stock NixOS + # var.conf tmpfiles configuration file, /var/run is symlinked to + # /run, so rpcbind can enter a race condition in which /var/run + # isn't symlinked yet but tries to interact with the path, so + # controlling the order explicitly here ensures that rpcbind can + # start successfully. The `wants` instead of `requires` should + # avoid creating a strict/brittle dependency. + wants = [ "systemd-tmpfiles-setup.service" ]; + after = [ "systemd-tmpfiles-setup.service" ]; }; users.users.rpc = { diff --git a/nixos/modules/services/networking/tox-node.nix b/nixos/modules/services/networking/tox-node.nix index fa5b241f91836..884fd55dae51d 100644 --- a/nixos/modules/services/networking/tox-node.nix +++ b/nixos/modules/services/networking/tox-node.nix @@ -8,7 +8,7 @@ let homeDir = "/var/lib/tox-node"; configFile = let - src = "${pkg.src}/dpkg/config.yml"; + src = "${pkg.src}/tox_node/dpkg/config.yml"; confJSON = pkgs.writeText "config.json" ( builtins.toJSON { log-type = cfg.logType; diff --git a/nixos/modules/services/web-apps/dolibarr.nix b/nixos/modules/services/web-apps/dolibarr.nix index 5335c439329c0..f262099354d2c 100644 --- a/nixos/modules/services/web-apps/dolibarr.nix +++ b/nixos/modules/services/web-apps/dolibarr.nix @@ -1,11 +1,11 @@ { config, pkgs, lib, ... }: let - inherit (lib) any boolToString concatStringsSep isBool isString literalExpression mapAttrsToList mkDefault mkEnableOption mkIf mkOption optionalAttrs types; + inherit (lib) any boolToString concatStringsSep isBool isString mapAttrsToList mkDefault mkEnableOption mkIf mkMerge mkOption optionalAttrs types; package = pkgs.dolibarr.override { inherit (cfg) stateDir; }; cfg = config.services.dolibarr; - vhostCfg = config.services.nginx.virtualHosts."${cfg.domain}"; + vhostCfg = lib.optionalAttr (cfg.nginx != null) config.services.nginx.virtualHosts."${cfg.domain}"; mkConfigFile = filename: settings: let @@ -38,7 +38,7 @@ let force_install_database = cfg.database.name; force_install_databaselogin = cfg.database.user; - force_install_mainforcehttps = vhostCfg.forceSSL; + force_install_mainforcehttps = vhostCfg.forceSSL or false; force_install_createuser = false; force_install_dolibarrlogin = null; } // optionalAttrs (cfg.database.passwordFile != null) { @@ -183,7 +183,8 @@ in }; # implementation - config = mkIf cfg.enable { + config = mkIf cfg.enable (mkMerge [ + { assertions = [ { assertion = cfg.database.createLocally -> cfg.database.user == cfg.user; @@ -214,7 +215,7 @@ in # Security settings dolibarr_main_prod = true; - dolibarr_main_force_https = vhostCfg.forceSSL; + dolibarr_main_force_https = vhostCfg.forceSSL or false; dolibarr_main_restrict_os_commands = "${pkgs.mariadb}/bin/mysqldump, ${pkgs.mariadb}/bin/mysql"; dolibarr_nocsrfcheck = false; dolibarr_main_instance_unique_id = '' @@ -314,7 +315,9 @@ in users.groups = optionalAttrs (cfg.group == "dolibarr") { dolibarr = { }; }; - - users.users."${config.services.nginx.group}".extraGroups = [ cfg.group ]; - }; + } + (mkIf (cfg.nginx != null) { + users.users."${config.services.nginx.group}".extraGroups = mkIf (cfg.nginx != null) [ cfg.group ]; + }) +]); } diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index 2ab24951ec62e..9fcb408c287d5 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -585,6 +585,8 @@ in hardware.bluetooth.enable = true; hardware.pulseaudio.enable = true; networking.networkmanager.enable = true; + # Required for autorotate + hardware.sensor.iio.enable = lib.mkDefault true; # Recommendations can be found here: # - https://invent.kde.org/plasma-mobile/plasma-phone-settings/-/tree/master/etc/xdg diff --git a/nixos/modules/system/activation/bootspec.cue b/nixos/modules/system/activation/bootspec.cue index 3fc9ca381df77..9f857a1b1cd80 100644 --- a/nixos/modules/system/activation/bootspec.cue +++ b/nixos/modules/system/activation/bootspec.cue @@ -1,4 +1,5 @@ #V1: { + system: string init: string initrd?: string initrdSecrets?: string diff --git a/nixos/modules/system/activation/bootspec.nix b/nixos/modules/system/activation/bootspec.nix index da76bf9084af8..61407ab67558b 100644 --- a/nixos/modules/system/activation/bootspec.nix +++ b/nixos/modules/system/activation/bootspec.nix @@ -19,13 +19,15 @@ let (builtins.toJSON { v1 = { + system = config.boot.kernelPackages.stdenv.hostPlatform.system; 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; + } // lib.optionalAttrs config.boot.initrd.enable { + initrd = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}"; + initrdSecrets = "${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets"; }; }); @@ -54,7 +56,7 @@ let specialisationInjector = let specialisationLoader = (lib.mapAttrsToList - (childName: childToplevel: lib.escapeShellArgs [ "--slurpfile" childName "${childToplevel}/bootspec/${filename}" ]) + (childName: childToplevel: lib.escapeShellArgs [ "--slurpfile" childName "${childToplevel}/${filename}" ]) children); in lib.escapeShellArgs [ @@ -66,7 +68,7 @@ let '' mkdir -p $out/bootspec - ${toplevelInjector} | ${specialisationInjector} > $out/bootspec/${filename} + ${toplevelInjector} | ${specialisationInjector} > $out/${filename} ''; validator = pkgs.writeCueValidator ./bootspec.cue { @@ -80,7 +82,7 @@ in 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; + type = lib.types.attrsOf lib.types.attrs; # <namespace>: { ...namespace-specific fields } default = { }; description = lib.mdDoc '' User-defined data that extends the bootspec document. diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 0bb3628ceed9a..00b11471e1c71 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -81,7 +81,7 @@ let ${optionalString (!config.boot.isContainer && config.boot.bootspec.enable) '' ${config.boot.bootspec.writer} - ${config.boot.bootspec.validator} "$out/bootspec/${config.boot.bootspec.filename}" + ${config.boot.bootspec.validator} "$out/${config.boot.bootspec.filename}" ''} ${config.system.extraSystemBuilderCmds} diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 4b4f4cc801aba..0f14f2b501c22 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -503,6 +503,10 @@ in assertion = !cfgZfs.forceImportAll || cfgZfs.forceImportRoot; message = "If you enable boot.zfs.forceImportAll, you must also enable boot.zfs.forceImportRoot"; } + { + assertion = cfgZfs.allowHibernation -> !cfgZfs.forceImportRoot && !cfgZfs.forceImportAll; + message = "boot.zfs.allowHibernation while force importing is enabled will cause data corruption"; + } ]; boot = { diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix index 64bc99f6d325f..d62bf0c0fd92d 100644 --- a/nixos/tests/acme.nix +++ b/nixos/tests/acme.nix @@ -144,7 +144,11 @@ in { name = "acme"; - meta.maintainers = lib.teams.acme.members; + meta = { + maintainers = lib.teams.acme.members; + # Hard timeout in seconds. Average run time is about 7 minutes. + timeout = 1800; + }; nodes = { # The fake ACME server which will respond to client requests @@ -357,6 +361,30 @@ in { import time + TOTAL_RETRIES = 20 + + + class BackoffTracker(object): + delay = 1 + increment = 1 + + def handle_fail(self, retries, message) -> int: + assert retries < TOTAL_RETRIES, message + + print(f"Retrying in {self.delay}s, {retries + 1}/{TOTAL_RETRIES}") + time.sleep(self.delay) + + # Only increment after the first try + if retries == 0: + self.delay += self.increment + self.increment *= 2 + + return retries + 1 + + + backoff = BackoffTracker() + + def switch_to(node, name): # On first switch, this will create a symlink to the current system so that we can # quickly switch between derivations @@ -404,9 +432,7 @@ in { assert False - def check_connection(node, domain, retries=3): - assert retries >= 0, f"Failed to connect to https://{domain}" - + def check_connection(node, domain, retries=0): result = node.succeed( "openssl s_client -brief -verify 2 -CAfile /tmp/ca.crt" f" -servername {domain} -connect {domain}:443 < /dev/null 2>&1" @@ -414,13 +440,11 @@ in { for line in result.lower().split("\n"): if "verification" in line and "error" in line: - time.sleep(3) - return check_connection(node, domain, retries - 1) + retries = backoff.handle_fail(retries, f"Failed to connect to https://{domain}") + return check_connection(node, domain, retries) - def check_connection_key_bits(node, domain, bits, retries=3): - assert retries >= 0, f"Did not find expected number of bits ({bits}) in key" - + def check_connection_key_bits(node, domain, bits, retries=0): result = node.succeed( "openssl s_client -CAfile /tmp/ca.crt" f" -servername {domain} -connect {domain}:443 < /dev/null" @@ -429,13 +453,11 @@ in { print("Key type:", result) if bits not in result: - time.sleep(3) - return check_connection_key_bits(node, domain, bits, retries - 1) - + retries = backoff.handle_fail(retries, f"Did not find expected number of bits ({bits}) in key") + return check_connection_key_bits(node, domain, bits, retries) - def check_stapling(node, domain, retries=3): - assert retries >= 0, "OCSP Stapling check failed" + def check_stapling(node, domain, retries=0): # Pebble doesn't provide a full OCSP responder, so just check the URL result = node.succeed( "openssl s_client -CAfile /tmp/ca.crt" @@ -445,21 +467,19 @@ in { print("OCSP Responder URL:", result) if "${caDomain}:4002" not in result.lower(): - time.sleep(3) - return check_stapling(node, domain, retries - 1) - + retries = backoff.handle_fail(retries, "OCSP Stapling check failed") + return check_stapling(node, domain, retries) - def download_ca_certs(node, retries=5): - assert retries >= 0, "Failed to connect to pebble to download root CA certs" + def download_ca_certs(node, retries=0): exit_code, _ = node.execute("curl https://${caDomain}:15000/roots/0 > /tmp/ca.crt") exit_code_2, _ = node.execute( "curl https://${caDomain}:15000/intermediate-keys/0 >> /tmp/ca.crt" ) if exit_code + exit_code_2 > 0: - time.sleep(3) - return download_ca_certs(node, retries - 1) + retries = backoff.handle_fail(retries, "Failed to connect to pebble to download root CA certs") + return download_ca_certs(node, retries) start_all() diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 1956d3c9e8c7c..30bcfcf6111a3 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -96,6 +96,7 @@ in { blockbook-frontend = handleTest ./blockbook-frontend.nix {}; blocky = handleTest ./blocky.nix {}; boot = handleTestOn ["x86_64-linux" "aarch64-linux"] ./boot.nix {}; + bootspec = handleTestOn ["x86_64-linux"] ./bootspec.nix {}; boot-stage1 = handleTest ./boot-stage1.nix {}; borgbackup = handleTest ./borgbackup.nix {}; botamusique = handleTest ./botamusique.nix {}; diff --git a/nixos/tests/bootspec.nix b/nixos/tests/bootspec.nix index 13360bb1eaa2e..077dff918e0d2 100644 --- a/nixos/tests/bootspec.nix +++ b/nixos/tests/bootspec.nix @@ -43,7 +43,7 @@ in 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/boot.json") ''; }; @@ -65,7 +65,7 @@ in 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/boot.json") ''; }; @@ -86,7 +86,33 @@ in machine.start() machine.wait_for_unit("multi-user.target") + machine.succeed("test -e /run/current-system/boot.json") + ''; + }; + + # Check that initrd create corresponding entries in bootspec. + initrd = makeTest { + name = "bootspec-with-initrd"; + meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; + + nodes.machine = { + imports = [ standard ]; + environment.systemPackages = [ pkgs.jq ]; + # It's probably the case, but we want to make it explicit here. + boot.initrd.enable = true; + }; + + testScript = '' + import json + + machine.start() + machine.wait_for_unit("multi-user.target") + machine.succeed("test -e /run/current-system/bootspec/boot.json") + + bootspec = json.loads(machine.succeed("jq -r '.v1' /run/current-system/bootspec/boot.json")) + + assert all(key in bootspec for key in ('initrd', 'initrdSecrets')), "Bootspec should contain initrd or initrdSecrets field when initrd is enabled" ''; }; @@ -107,11 +133,11 @@ in 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") + machine.succeed("test -e /run/current-system/boot.json") + machine.succeed("test -e /run/current-system/specialisation/something/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")) + sp_in_parent = json.loads(machine.succeed("jq -r '.v1.specialisation.something' /run/current-system/boot.json")) + sp_in_fs = json.loads(machine.succeed("cat /run/current-system/specialisation/something/boot.json")) assert sp_in_parent == sp_in_fs['v1'], "Bootspecs of the same specialisation are different!" ''; @@ -135,7 +161,7 @@ in 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)") + bootspec_os_release = machine.succeed("cat $(jq -r '.v1.extensions.osRelease' /run/current-system/boot.json)") assert current_os_release == bootspec_os_release, "Filename referenced by extension has unexpected contents" ''; |