diff options
Diffstat (limited to 'nixos')
29 files changed, 414 insertions, 221 deletions
diff --git a/nixos/doc/manual/development/option-declarations.section.md b/nixos/doc/manual/development/option-declarations.section.md index 2e11218e82389..ef7255557a109 100644 --- a/nixos/doc/manual/development/option-declarations.section.md +++ b/nixos/doc/manual/development/option-declarations.section.md @@ -120,14 +120,14 @@ lib.mkOption { ```nix lib.mkPackageOption pkgs "GHC" { default = [ "ghc" ]; - example = "pkgs.haskell.package.ghc922.ghc.withPackages (hkgs: [ hkgs.primes ])"; + example = "pkgs.haskell.package.ghc923.ghc.withPackages (hkgs: [ hkgs.primes ])"; } # is like lib.mkOption { type = lib.types.package; default = pkgs.ghc; defaultText = lib.literalExpression "pkgs.ghc"; - example = lib.literalExpression "pkgs.haskell.package.ghc922.ghc.withPackages (hkgs: [ hkgs.primes ])"; + example = lib.literalExpression "pkgs.haskell.package.ghc923.ghc.withPackages (hkgs: [ hkgs.primes ])"; description = "The GHC package to use."; } ``` diff --git a/nixos/doc/manual/from_md/development/option-declarations.section.xml b/nixos/doc/manual/from_md/development/option-declarations.section.xml index 91867c224107a..381163dd7c74d 100644 --- a/nixos/doc/manual/from_md/development/option-declarations.section.xml +++ b/nixos/doc/manual/from_md/development/option-declarations.section.xml @@ -183,14 +183,14 @@ lib.mkOption { <programlisting language="bash"> lib.mkPackageOption pkgs "GHC" { default = [ "ghc" ]; - example = "pkgs.haskell.package.ghc922.ghc.withPackages (hkgs: [ hkgs.primes ])"; + example = "pkgs.haskell.package.ghc923.ghc.withPackages (hkgs: [ hkgs.primes ])"; } # is like lib.mkOption { type = lib.types.package; default = pkgs.ghc; defaultText = lib.literalExpression "pkgs.ghc"; - example = lib.literalExpression "pkgs.haskell.package.ghc922.ghc.withPackages (hkgs: [ hkgs.primes ])"; + example = lib.literalExpression "pkgs.haskell.package.ghc923.ghc.withPackages (hkgs: [ hkgs.primes ])"; description = "The GHC package to use."; } </programlisting> diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml index b0a84de57e0b2..4a7ef8b71686e 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml @@ -40,7 +40,7 @@ </section> <section xml:id="sec-release-22.11-new-services"> <title>New Services</title> - <itemizedlist spacing="compact"> + <itemizedlist> <listitem> <para> <link xlink:href="https://github.com/jollheef/appvm">appvm</link>, @@ -48,6 +48,13 @@ <link xlink:href="options.html#opt-virtualisation.appvm.enable">virtualisation.appvm</link>. </para> </listitem> + <listitem> + <para> + <link xlink:href="https://github.com/leetronics/infnoise">infnoise</link>, + a hardware True Random Number Generator dongle. Available as + <link xlink:href="options.html#opt-services.infnoise.enable">services.infnoise</link>. + </para> + </listitem> </itemizedlist> </section> <section xml:id="sec-release-22.11-incompatibilities"> @@ -89,7 +96,7 @@ </section> <section xml:id="sec-release-22.11-notable-changes"> <title>Other Notable Changes</title> - <itemizedlist spacing="compact"> + <itemizedlist> <listitem> <para> A new module was added for the Saleae Logic device family, diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md index acad456a4fd3a..89a799cafc507 100644 --- a/nixos/doc/manual/release-notes/rl-2211.section.md +++ b/nixos/doc/manual/release-notes/rl-2211.section.md @@ -25,6 +25,9 @@ In addition to numerous new and upgraded packages, this release has the followin - [appvm](https://github.com/jollheef/appvm), Nix based app VMs. Available as [virtualisation.appvm](options.html#opt-virtualisation.appvm.enable). +- [infnoise](https://github.com/leetronics/infnoise), a hardware True Random Number Generator dongle. + Available as [services.infnoise](options.html#opt-services.infnoise.enable). + <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. --> ## Backward Incompatibilities {#sec-release-22.11-incompatibilities} @@ -44,7 +47,8 @@ In addition to numerous new and upgraded packages, this release has the followin ## Other Notable Changes {#sec-release-22.11-notable-changes} -* A new module was added for the Saleae Logic device family, providing the options `hardware.saleae-logic.enable` and `hardware.saleae-logic.package`. -* Matrix Synapse now requires entries in the `state_group_edges` table to be unique, in order to prevent accidentally introducing duplicate information (for example, because a database backup was restored multiple times). If your Synapse database already has duplicate rows in this table, this could fail with an error and require manual remediation. +- A new module was added for the Saleae Logic device family, providing the options `hardware.saleae-logic.enable` and `hardware.saleae-logic.package`. + +- Matrix Synapse now requires entries in the `state_group_edges` table to be unique, in order to prevent accidentally introducing duplicate information (for example, because a database backup was restored multiple times). If your Synapse database already has duplicate rows in this table, this could fail with an error and require manual remediation. <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. --> diff --git a/nixos/lib/test-driver/test_driver/machine.py b/nixos/lib/test-driver/test_driver/machine.py index 035e3ffe89731..3ff3cf5645f82 100644 --- a/nixos/lib/test-driver/test_driver/machine.py +++ b/nixos/lib/test-driver/test_driver/machine.py @@ -682,7 +682,7 @@ class Machine: with self.nested("waiting for {} to appear on tty {}".format(regexp, tty)): retry(tty_matches) - def send_chars(self, chars: List[str]) -> None: + def send_chars(self, chars: str) -> None: with self.nested("sending keys ‘{}‘".format(chars)): for char in chars: self.send_key(char) diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 902fffd60f9b9..d59d7bfe40d9f 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -983,6 +983,7 @@ ./services/security/hologram-server.nix ./services/security/hologram-agent.nix ./services/security/kanidm.nix + ./services/security/infnoise.nix ./services/security/munge.nix ./services/security/nginx-sso.nix ./services/security/oauth2_proxy.nix diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix index 8ff8e31864be2..333fdd494e3b9 100644 --- a/nixos/modules/services/backup/restic.nix +++ b/nixos/modules/services/backup/restic.nix @@ -96,13 +96,22 @@ in }; repository = mkOption { - type = types.str; + type = with types; nullOr str; + default = null; description = '' repository to backup to. ''; example = "sftp:backup@192.168.1.100:/backups/${name}"; }; + repositoryFile = mkOption { + type = with types; nullOr path; + default = null; + description = '' + Path to the file containing the repository location to backup to. + ''; + }; + paths = mkOption { type = types.nullOr (types.listOf types.str); default = null; @@ -142,7 +151,7 @@ in extraBackupArgs = mkOption { type = types.listOf types.str; - default = []; + default = [ ]; description = '' Extra arguments passed to restic backup. ''; @@ -153,7 +162,7 @@ in extraOptions = mkOption { type = types.listOf types.str; - default = []; + default = [ ]; description = '' Extra extended options to be passed to the restic --option flag. ''; @@ -172,7 +181,7 @@ in pruneOpts = mkOption { type = types.listOf types.str; - default = []; + default = [ ]; description = '' A list of options (--keep-* et al.) for 'restic forget --prune', to automatically prune old snapshots. The @@ -197,9 +206,25 @@ in ''; example = "find /home/matt/git -type d -name .git"; }; + + backupPrepareCommand = mkOption { + type = with types; nullOr str; + default = null; + description = '' + A script that must run before starting the backup process. + ''; + }; + + backupCleanupCommand = mkOption { + type = with types; nullOr str; + default = null; + description = '' + A script that must run after finishing the backup process. + ''; + }; }; })); - default = {}; + default = { }; example = { localbackup = { paths = [ "/home" ]; @@ -225,66 +250,85 @@ in config = { warnings = mapAttrsToList (n: v: "services.restic.backups.${n}.s3CredentialsFile is deprecated, please use services.restic.backups.${n}.environmentFile instead.") (filterAttrs (n: v: v.s3CredentialsFile != null) config.services.restic.backups); systemd.services = - mapAttrs' (name: backup: - let - extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions; - resticCmd = "${pkgs.restic}/bin/restic${extraOptions}"; - filesFromTmpFile = "/run/restic-backups-${name}/includes"; - backupPaths = if (backup.dynamicFilesFrom == null) - then if (backup.paths != null) then concatStringsSep " " backup.paths else "" - else "--files-from ${filesFromTmpFile}"; - pruneCmd = optionals (builtins.length backup.pruneOpts > 0) [ - ( resticCmd + " forget --prune " + (concatStringsSep " " backup.pruneOpts) ) - ( resticCmd + " check" ) - ]; - # Helper functions for rclone remotes - rcloneRemoteName = builtins.elemAt (splitString ":" backup.repository) 1; - rcloneAttrToOpt = v: "RCLONE_" + toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v); - rcloneAttrToConf = v: "RCLONE_CONFIG_" + toUpper (rcloneRemoteName + "_" + v); - toRcloneVal = v: if lib.isBool v then lib.boolToString v else v; - in nameValuePair "restic-backups-${name}" ({ - environment = { - RESTIC_PASSWORD_FILE = backup.passwordFile; - RESTIC_REPOSITORY = backup.repository; - } // optionalAttrs (backup.rcloneOptions != null) (mapAttrs' (name: value: - nameValuePair (rcloneAttrToOpt name) (toRcloneVal value) - ) backup.rcloneOptions) // optionalAttrs (backup.rcloneConfigFile != null) { - RCLONE_CONFIG = backup.rcloneConfigFile; - } // optionalAttrs (backup.rcloneConfig != null) (mapAttrs' (name: value: - nameValuePair (rcloneAttrToConf name) (toRcloneVal value) - ) backup.rcloneConfig); - path = [ pkgs.openssh ]; - restartIfChanged = false; - serviceConfig = { - Type = "oneshot"; - ExecStart = (optionals (backupPaths != "") [ "${resticCmd} backup --cache-dir=%C/restic-backups-${name} ${concatStringsSep " " backup.extraBackupArgs} ${backupPaths}" ]) - ++ pruneCmd; - User = backup.user; - RuntimeDirectory = "restic-backups-${name}"; - CacheDirectory = "restic-backups-${name}"; - CacheDirectoryMode = "0700"; - } // optionalAttrs (backup.environmentFile != null) { - EnvironmentFile = backup.environmentFile; - }; - } // optionalAttrs (backup.initialize || backup.dynamicFilesFrom != null) { - preStart = '' - ${optionalString (backup.initialize) '' - ${resticCmd} snapshots || ${resticCmd} init - ''} - ${optionalString (backup.dynamicFilesFrom != null) '' - ${pkgs.writeScript "dynamicFilesFromScript" backup.dynamicFilesFrom} > ${filesFromTmpFile} - ''} - ''; - } // optionalAttrs (backup.dynamicFilesFrom != null) { - postStart = '' - rm ${filesFromTmpFile} - ''; - }) - ) config.services.restic.backups; + mapAttrs' + (name: backup: + let + extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions; + resticCmd = "${pkgs.restic}/bin/restic${extraOptions}"; + filesFromTmpFile = "/run/restic-backups-${name}/includes"; + backupPaths = + if (backup.dynamicFilesFrom == null) + then if (backup.paths != null) then concatStringsSep " " backup.paths else "" + else "--files-from ${filesFromTmpFile}"; + pruneCmd = optionals (builtins.length backup.pruneOpts > 0) [ + (resticCmd + " forget --prune " + (concatStringsSep " " backup.pruneOpts)) + (resticCmd + " check") + ]; + # Helper functions for rclone remotes + rcloneRemoteName = builtins.elemAt (splitString ":" backup.repository) 1; + rcloneAttrToOpt = v: "RCLONE_" + toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v); + rcloneAttrToConf = v: "RCLONE_CONFIG_" + toUpper (rcloneRemoteName + "_" + v); + toRcloneVal = v: if lib.isBool v then lib.boolToString v else v; + in + nameValuePair "restic-backups-${name}" ({ + environment = { + RESTIC_PASSWORD_FILE = backup.passwordFile; + RESTIC_REPOSITORY = backup.repository; + RESTIC_REPOSITORY_FILE = backup.repositoryFile; + } // optionalAttrs (backup.rcloneOptions != null) (mapAttrs' + (name: value: + nameValuePair (rcloneAttrToOpt name) (toRcloneVal value) + ) + backup.rcloneOptions) // optionalAttrs (backup.rcloneConfigFile != null) { + RCLONE_CONFIG = backup.rcloneConfigFile; + } // optionalAttrs (backup.rcloneConfig != null) (mapAttrs' + (name: value: + nameValuePair (rcloneAttrToConf name) (toRcloneVal value) + ) + backup.rcloneConfig); + path = [ pkgs.openssh ]; + restartIfChanged = false; + serviceConfig = { + Type = "oneshot"; + ExecStart = (optionals (backupPaths != "") [ "${resticCmd} backup --cache-dir=%C/restic-backups-${name} ${concatStringsSep " " backup.extraBackupArgs} ${backupPaths}" ]) + ++ pruneCmd; + User = backup.user; + RuntimeDirectory = "restic-backups-${name}"; + CacheDirectory = "restic-backups-${name}"; + CacheDirectoryMode = "0700"; + } // optionalAttrs (backup.environmentFile != null) { + EnvironmentFile = backup.environmentFile; + }; + } // optionalAttrs (backup.initialize || backup.dynamicFilesFrom != null || backup.backupPrepareCommand != null) { + preStart = '' + ${optionalString (backup.backupPrepareCommand != null) '' + ${pkgs.writeScript "backupPrepareCommand" backup.backupPrepareCommand} + ''} + ${optionalString (backup.initialize) '' + ${resticCmd} snapshots || ${resticCmd} init + ''} + ${optionalString (backup.dynamicFilesFrom != null) '' + ${pkgs.writeScript "dynamicFilesFromScript" backup.dynamicFilesFrom} > ${filesFromTmpFile} + ''} + ''; + } // optionalAttrs (backup.dynamicFilesFrom != null || backup.backupCleanupCommand != null) { + postStart = '' + ${optionalString (backup.backupCleanupCommand != null) '' + ${pkgs.writeScript "backupCleanupCommand" backup.backupCleanupCommand} + ''} + ${optionalString (backup.dynamicFilesFrom != null) '' + rm ${filesFromTmpFile} + ''} + ''; + }) + ) + config.services.restic.backups; systemd.timers = - mapAttrs' (name: backup: nameValuePair "restic-backups-${name}" { - wantedBy = [ "timers.target" ]; - timerConfig = backup.timerConfig; - }) config.services.restic.backups; + mapAttrs' + (name: backup: nameValuePair "restic-backups-${name}" { + wantedBy = [ "timers.target" ]; + timerConfig = backup.timerConfig; + }) + config.services.restic.backups; }; } diff --git a/nixos/modules/services/desktops/pipewire/pipewire.nix b/nixos/modules/services/desktops/pipewire/pipewire.nix index 1323336d866e9..6459b22519dbe 100644 --- a/nixos/modules/services/desktops/pipewire/pipewire.nix +++ b/nixos/modules/services/desktops/pipewire/pipewire.nix @@ -239,7 +239,7 @@ in { }; environment.sessionVariables.LD_LIBRARY_PATH = - lib.optional cfg.jack.enable "${cfg.package.jack}/lib"; + lib.mkIf cfg.jack.enable [ "${cfg.package.jack}/lib" ]; users = lib.mkIf cfg.systemWide { users.pipewire = { diff --git a/nixos/modules/services/monitoring/netdata.nix b/nixos/modules/services/monitoring/netdata.nix index f528d18304244..489dd337bb7cc 100644 --- a/nixos/modules/services/monitoring/netdata.nix +++ b/nixos/modules/services/monitoring/netdata.nix @@ -201,6 +201,8 @@ in { serviceConfig = { ExecStart = "${cfg.package}/bin/netdata -P /run/netdata/netdata.pid -D -c /etc/netdata/netdata.conf"; ExecReload = "${pkgs.util-linux}/bin/kill -s HUP -s USR1 -s USR2 $MAINPID"; + ExecPostStart = ''while [ "$(netdatacli ping)" != pong ]; do sleep 0.5; done''; + TimeoutStopSec = 60; Restart = "on-failure"; # User and group diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix index a683c537f05b2..e88daae1fbbac 100644 --- a/nixos/modules/services/networking/unifi.nix +++ b/nixos/modules/services/networking/unifi.nix @@ -51,7 +51,7 @@ in services.unifi.openFirewall = mkOption { type = types.bool; - default = true; + default = false; description = '' Whether or not to open the minimum required ports on the firewall. @@ -85,10 +85,6 @@ in config = mkIf cfg.enable { - warnings = optional - (options.services.unifi.openFirewall.highestPrio >= (mkOptionDefault null).priority) - "The current services.unifi.openFirewall = true default is deprecated and will change to false in 22.11. Set it explicitly to silence this warning."; - users.users.unifi = { isSystemUser = true; group = "unifi"; diff --git a/nixos/modules/services/security/infnoise.nix b/nixos/modules/services/security/infnoise.nix new file mode 100644 index 0000000000000..4fb8adaf33f89 --- /dev/null +++ b/nixos/modules/services/security/infnoise.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.infnoise; +in { + options = { + services.infnoise = { + enable = mkEnableOption "the Infinite Noise TRNG driver"; + + fillDevRandom = mkOption { + description = '' + Whether to run the infnoise driver as a daemon to refill /dev/random. + + If disabled, you can use the `infnoise` command-line tool to + manually obtain randomness. + ''; + type = types.bool; + default = true; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.infnoise ]; + + services.udev.extraRules = '' + SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", SYMLINK+="infnoise", TAG+="systemd", GROUP="dialout", MODE="0664", ENV{SYSTEMD_WANTS}="infnoise.service" + ''; + + systemd.services.infnoise = mkIf cfg.fillDevRandom { + description = "Infinite Noise TRNG driver"; + + bindsTo = [ "dev-infnoise.device" ]; + after = [ "dev-infnoise.device" ]; + + serviceConfig = { + ExecStart = "${pkgs.infnoise}/bin/infnoise --dev-random --debug"; + Restart = "always"; + User = "infnoise"; + DynamicUser = true; + SupplementaryGroups = [ "dialout" ]; + DeviceAllow = [ "/dev/infnoise" ]; + DevicePolicy = "closed"; + PrivateNetwork = true; + ProtectSystem = "strict"; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; # only reads entropy pool size and watermark + RestrictNamespaces = true; + RestrictRealtime = true; + LockPersonality = true; + MemoryDenyWriteExecute = true; + }; + }; + }; +} diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index b0f160c1dbf95..66fdc61d28357 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -219,14 +219,15 @@ let cidr = "${route.address}/${toString route.prefixLength}"; via = optionalString (route.via != null) ''via "${route.via}"''; options = concatStrings (mapAttrsToList (name: val: "${name} ${val} ") route.options); + type = toString route.type; in '' echo "${cidr}" >> $state echo -n "adding route ${cidr}... " - if out=$(ip route add "${cidr}" ${options} ${via} dev "${i.name}" proto static 2>&1); then + if out=$(ip route add ${type} "${cidr}" ${options} ${via} dev "${i.name}" proto static 2>&1); then echo "done" elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then - echo "'ip route add "${cidr}" ${options} ${via} dev "${i.name}"' failed: $out" + echo "'ip route add ${type} "${cidr}" ${options} ${via} dev "${i.name}"' failed: $out" exit 1 fi '' diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index 110e84494a3dc..80808e0c08fa5 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -142,6 +142,9 @@ in optionalAttrs (route.via != null) { Gateway = route.via; } // + optionalAttrs (route.type != null) { + Type = route.type; + } // optionalAttrs (route.options ? onlink) { GatewayOnLink = true; } // diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index d56159f15960d..07bccf98f407f 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -90,6 +90,22 @@ let ''; }; + type = mkOption { + type = types.nullOr (types.enum [ + "unicast" "local" "broadcast" "multicast" + ]); + default = null; + description = '' + Type of the route. See the <literal>Route types</literal> section + in the <literal>ip-route(8)</literal> manual page for the details. + + Note that <literal>prohibit</literal>, <literal>blackhole</literal>, + <literal>unreachable</literal>, and <literal>throw</literal> cannot + be configured per device, so they are not available here. Similarly, + <literal>nat</literal> hasn't been supported since kernel 2.6. + ''; + }; + via = mkOption { type = types.nullOr types.str; default = null; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 1d177f595b568..f534888592ffc 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -26,8 +26,22 @@ let featureFlags.minimalModules = {}; }; evalMinimalConfig = module: nixosLib.evalModules { modules = [ module ]; }; -in -{ + + allDrivers = getDrivers tests; + + getDrivers = ts: + if isDerivation ts + then ts.driver or null + else if isAttrs ts + then recurseIntoAttrs (mapAttrs (k: getDrivers) ts) + else null; + + tests = { + + # for typechecking of the scripts and evaluation of + # the nodes, without running VMs. + inherit allDrivers; + _3proxy = handleTest ./3proxy.nix {}; acme = handleTest ./acme.nix {}; adguardhome = handleTest ./adguardhome.nix {}; @@ -621,4 +635,5 @@ in zookeeper = handleTest ./zookeeper.nix {}; zrepl = handleTest ./zrepl.nix {}; zsh-history = handleTest ./zsh-history.nix {}; -} +}; +in tests diff --git a/nixos/tests/ecryptfs.nix b/nixos/tests/ecryptfs.nix index e3cfb2ed998c2..1c67d307a00e8 100644 --- a/nixos/tests/ecryptfs.nix +++ b/nixos/tests/ecryptfs.nix @@ -11,16 +11,16 @@ import ./make-test-python.nix ({ ... }: testScript = '' def login_as_alice(): - machine.wait_until_tty_matches(1, "login: ") + machine.wait_until_tty_matches("1", "login: ") machine.send_chars("alice\n") - machine.wait_until_tty_matches(1, "Password: ") + machine.wait_until_tty_matches("1", "Password: ") machine.send_chars("foobar\n") - machine.wait_until_tty_matches(1, "alice\@machine") + machine.wait_until_tty_matches("1", "alice\@machine") def logout(): machine.send_chars("logout\n") - machine.wait_until_tty_matches(1, "login: ") + machine.wait_until_tty_matches("1", "login: ") machine.wait_for_unit("default.target") @@ -36,7 +36,7 @@ import ./make-test-python.nix ({ ... }: with subtest("Log alice in (ecryptfs passwhrase is wrapped during first login)"): login_as_alice() machine.send_chars("logout\n") - machine.wait_until_tty_matches(1, "login: ") + machine.wait_until_tty_matches("1", "login: ") # Why do I need to do this?? machine.succeed("su alice -c ecryptfs-umount-private || true") diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index 10f9cb05c9cb1..f7b9d283e4572 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -111,6 +111,7 @@ in { pattern = re.compile(r"path=(?P<path>[\/a-z0-9-.]+)\/bin\/hass") response = hass.execute("systemctl show -p ExecStart home-assistant.service")[1] match = pattern.search(response) + assert match package = match.group('path') hass.wait_for_unit("home-assistant.service") diff --git a/nixos/tests/ihatemoney/default.nix b/nixos/tests/ihatemoney/default.nix index cd5f073343daa..894a97d43d35e 100644 --- a/nixos/tests/ihatemoney/default.nix +++ b/nixos/tests/ihatemoney/default.nix @@ -32,14 +32,7 @@ let }; }; # ihatemoney needs a local smtp server otherwise project creation just crashes - services.opensmtpd = { - enable = true; - serverConfiguration = '' - listen on lo - action foo relay - match from any for any action foo - ''; - }; + services.postfix.enable = true; }; testScript = '' machine.wait_for_open_port(8000) diff --git a/nixos/tests/login.nix b/nixos/tests/login.nix index 0d6f81b172191..2cff38d20059d 100644 --- a/nixos/tests/login.nix +++ b/nixos/tests/login.nix @@ -29,11 +29,11 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... }: machine.wait_until_succeeds("pgrep -f 'agetty.*tty2'") with subtest("Log in as alice on a virtual console"): - machine.wait_until_tty_matches(2, "login: ") + machine.wait_until_tty_matches("2", "login: ") machine.send_chars("alice\n") - machine.wait_until_tty_matches(2, "login: alice") + machine.wait_until_tty_matches("2", "login: alice") machine.wait_until_succeeds("pgrep login") - machine.wait_until_tty_matches(2, "Password: ") + machine.wait_until_tty_matches("2", "Password: ") machine.send_chars("foobar\n") machine.wait_until_succeeds("pgrep -u alice bash") machine.send_chars("touch done\n") diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index 2cc1e9b0942ca..1fe1229f24a4a 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -77,12 +77,14 @@ let testCases = { loopback = { name = "Loopback"; - machine.networking.useDHCP = false; - machine.networking.useNetworkd = networkd; + nodes.client = { pkgs, ... }: with pkgs.lib; { + networking.useDHCP = false; + networking.useNetworkd = networkd; + }; testScript = '' start_all() - machine.wait_for_unit("network.target") - loopback_addresses = machine.succeed("ip addr show lo") + client.wait_for_unit("network.target") + loopback_addresses = client.succeed("ip addr show lo") assert "inet 127.0.0.1/8" in loopback_addresses assert "inet6 ::1/128" in loopback_addresses ''; @@ -139,6 +141,25 @@ let client.wait_until_succeeds("ping -c 1 192.168.3.1") ''; }; + routeType = { + name = "RouteType"; + nodes.client = { pkgs, ... }: with pkgs.lib; { + networking = { + useDHCP = false; + useNetworkd = networkd; + interfaces.eth1.ipv4.routes = [{ + address = "192.168.1.127"; + prefixLength = 32; + type = "local"; + }]; + }; + }; + testScript = '' + start_all() + client.wait_for_unit("network.target") + client.succeed("ip -4 route list table local | grep 'local 192.168.1.127'") + ''; + }; dhcpDefault = { name = "useDHCP-by-default"; nodes.router = router; diff --git a/nixos/tests/nitter.nix b/nixos/tests/nitter.nix index 0e1a6d150f38e..8bc55ba8c69fc 100644 --- a/nixos/tests/nitter.nix +++ b/nixos/tests/nitter.nix @@ -12,7 +12,7 @@ import ./make-test-python.nix ({ pkgs, ... }: testScript = '' machine.wait_for_unit("nitter.service") - machine.wait_for_open_port("80") + machine.wait_for_open_port(80) machine.succeed("curl --fail http://localhost:80/") ''; }) diff --git a/nixos/tests/pam/pam-oath-login.nix b/nixos/tests/pam/pam-oath-login.nix index c532e81e674d7..dd6ef4a0abcb8 100644 --- a/nixos/tests/pam/pam-oath-login.nix +++ b/nixos/tests/pam/pam-oath-login.nix @@ -77,28 +77,28 @@ in machine.screenshot("postboot") with subtest("Invalid password"): - switch_to_tty(2) - enter_user_alice(2) + switch_to_tty("2") + enter_user_alice("2") machine.send_chars("${oathSnakeOilPassword1}\n") - machine.wait_until_tty_matches(2, "Password: ") + machine.wait_until_tty_matches("2", "Password: ") machine.send_chars("blorg\n") - machine.wait_until_tty_matches(2, "Login incorrect") + machine.wait_until_tty_matches("2", "Login incorrect") with subtest("Invalid oath token"): - switch_to_tty(3) - enter_user_alice(3) + switch_to_tty("3") + enter_user_alice("3") machine.send_chars("000000\n") - machine.wait_until_tty_matches(3, "Login incorrect") - machine.wait_until_tty_matches(3, "login:") + machine.wait_until_tty_matches("3", "Login incorrect") + machine.wait_until_tty_matches("3", "login:") with subtest("Happy path: Both passwords are mandatory to get us in"): - switch_to_tty(4) - enter_user_alice(4) + switch_to_tty("4") + enter_user_alice("4") machine.send_chars("${oathSnakeOilPassword2}\n") - machine.wait_until_tty_matches(4, "Password: ") + machine.wait_until_tty_matches("4", "Password: ") machine.send_chars("${alicePassword}\n") machine.wait_until_succeeds("pgrep -u alice bash") diff --git a/nixos/tests/restic.nix b/nixos/tests/restic.nix index 16979eab82170..7523d5e5ed5da 100644 --- a/nixos/tests/restic.nix +++ b/nixos/tests/restic.nix @@ -1,96 +1,119 @@ import ./make-test-python.nix ( { pkgs, ... }: - let - password = "some_password"; - repository = "/tmp/restic-backup"; - rcloneRepository = "rclone:local:/tmp/restic-rclone-backup"; + let + password = "some_password"; + repository = "/tmp/restic-backup"; + repositoryFile = "${pkgs.writeText "repositoryFile" "/tmp/restic-backup-from-file"}"; + rcloneRepository = "rclone:local:/tmp/restic-rclone-backup"; - passwordFile = "${pkgs.writeText "password" "correcthorsebatterystaple"}"; - initialize = true; - paths = [ "/opt" ]; - pruneOpts = [ - "--keep-daily 2" - "--keep-weekly 1" - "--keep-monthly 1" - "--keep-yearly 99" - ]; - in - { - name = "restic"; + backupPrepareCommand = '' + touch /opt/backupPrepareCommand + test ! -e /opt/backupCleanupCommand + ''; - meta = with pkgs.lib.maintainers; { - maintainers = [ bbigras i077 ]; - }; + backupCleanupCommand = '' + rm /opt/backupPrepareCommand + touch /opt/backupCleanupCommand + ''; - nodes = { - server = - { pkgs, ... }: - { - services.restic.backups = { - remotebackup = { - inherit repository passwordFile initialize paths pruneOpts; - }; - rclonebackup = { - repository = rcloneRepository; - rcloneConfig = { - type = "local"; - one_file_system = true; - }; + passwordFile = "${pkgs.writeText "password" "correcthorsebatterystaple"}"; + initialize = true; + paths = [ "/opt" ]; + pruneOpts = [ + "--keep-daily 2" + "--keep-weekly 1" + "--keep-monthly 1" + "--keep-yearly 99" + ]; + in + { + name = "restic"; - # This gets overridden by rcloneConfig.type - rcloneConfigFile = pkgs.writeText "rclone.conf" '' - [local] - type=ftp - ''; - inherit passwordFile initialize paths pruneOpts; - }; - remoteprune = { - inherit repository passwordFile; - pruneOpts = [ "--keep-last 1" ]; - }; - }; + meta = with pkgs.lib.maintainers; { + maintainers = [ bbigras i077 ]; + }; - environment.sessionVariables.RCLONE_CONFIG_LOCAL_TYPE = "local"; + nodes = { + server = + { pkgs, ... }: + { + services.restic.backups = { + remotebackup = { + inherit repository passwordFile initialize paths pruneOpts backupPrepareCommand backupCleanupCommand; + }; + remotebackup-from-file = { + inherit repositoryFile passwordFile initialize paths pruneOpts; + }; + rclonebackup = { + repository = rcloneRepository; + rcloneConfig = { + type = "local"; + one_file_system = true; }; + + # This gets overridden by rcloneConfig.type + rcloneConfigFile = pkgs.writeText "rclone.conf" '' + [local] + type=ftp + ''; + inherit passwordFile initialize paths pruneOpts; + }; + remoteprune = { + inherit repository passwordFile; + pruneOpts = [ "--keep-last 1" ]; + }; + }; + + environment.sessionVariables.RCLONE_CONFIG_LOCAL_TYPE = "local"; }; + }; - testScript = '' - server.start() - server.wait_for_unit("dbus.socket") - server.fail( - "${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots", - "${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots", - ) - server.succeed( - "mkdir -p /opt", - "touch /opt/some_file", - "mkdir -p /tmp/restic-rclone-backup", - "timedatectl set-time '2016-12-13 13:45'", - "systemctl start restic-backups-remotebackup.service", - "systemctl start restic-backups-rclonebackup.service", - '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"', - '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"', - "timedatectl set-time '2017-12-13 13:45'", - "systemctl start restic-backups-remotebackup.service", - "systemctl start restic-backups-rclonebackup.service", - "timedatectl set-time '2018-12-13 13:45'", - "systemctl start restic-backups-remotebackup.service", - "systemctl start restic-backups-rclonebackup.service", - "timedatectl set-time '2018-12-14 13:45'", - "systemctl start restic-backups-remotebackup.service", - "systemctl start restic-backups-rclonebackup.service", - "timedatectl set-time '2018-12-15 13:45'", - "systemctl start restic-backups-remotebackup.service", - "systemctl start restic-backups-rclonebackup.service", - "timedatectl set-time '2018-12-16 13:45'", - "systemctl start restic-backups-remotebackup.service", - "systemctl start restic-backups-rclonebackup.service", - '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^4 snapshot"', - '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots -c | grep -e "^4 snapshot"', - "systemctl start restic-backups-remoteprune.service", - '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"', - ) - ''; - } + testScript = '' + server.start() + server.wait_for_unit("dbus.socket") + server.fail( + "${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots", + '${pkgs.restic}/bin/restic --repository-file ${repositoryFile} -p ${passwordFile} snapshots"', + "${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots", + ) + server.succeed( + "mkdir -p /opt", + "touch /opt/some_file", + "mkdir -p /tmp/restic-rclone-backup", + "timedatectl set-time '2016-12-13 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /opt/backupCleanupCommand", + "systemctl start restic-backups-remotebackup-from-file.service", + "systemctl start restic-backups-rclonebackup.service", + '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"', + '${pkgs.restic}/bin/restic --repository-file ${repositoryFile} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"', + '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"', + "timedatectl set-time '2017-12-13 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /opt/backupCleanupCommand", + "systemctl start restic-backups-rclonebackup.service", + "timedatectl set-time '2018-12-13 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /opt/backupCleanupCommand", + "systemctl start restic-backups-rclonebackup.service", + "timedatectl set-time '2018-12-14 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /opt/backupCleanupCommand", + "systemctl start restic-backups-rclonebackup.service", + "timedatectl set-time '2018-12-15 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /opt/backupCleanupCommand", + "systemctl start restic-backups-rclonebackup.service", + "timedatectl set-time '2018-12-16 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /opt/backupCleanupCommand", + "systemctl start restic-backups-rclonebackup.service", + '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^4 snapshot"', + '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots -c | grep -e "^4 snapshot"', + "systemctl start restic-backups-remoteprune.service", + '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"', + ) + ''; + } ) diff --git a/nixos/tests/shadow.nix b/nixos/tests/shadow.nix index dd2a575b1935a..50a9f71246469 100644 --- a/nixos/tests/shadow.nix +++ b/nixos/tests/shadow.nix @@ -39,9 +39,9 @@ in import ./make-test-python.nix ({ pkgs, ... }: { shadow.wait_until_succeeds("[ $(fgconsole) = 2 ]") shadow.wait_for_unit("getty@tty2.service") shadow.wait_until_succeeds("pgrep -f 'agetty.*tty2'") - shadow.wait_until_tty_matches(2, "login: ") + shadow.wait_until_tty_matches("2", "login: ") shadow.send_chars("emma\n") - shadow.wait_until_tty_matches(2, "login: emma") + shadow.wait_until_tty_matches("2", "login: emma") shadow.wait_until_succeeds("pgrep login") shadow.sleep(2) shadow.send_chars("${password1}\n") @@ -63,9 +63,9 @@ in import ./make-test-python.nix ({ pkgs, ... }: { shadow.wait_until_succeeds("[ $(fgconsole) = 3 ]") shadow.wait_for_unit("getty@tty3.service") shadow.wait_until_succeeds("pgrep -f 'agetty.*tty3'") - shadow.wait_until_tty_matches(3, "login: ") + shadow.wait_until_tty_matches("3", "login: ") shadow.send_chars("emma\n") - shadow.wait_until_tty_matches(3, "login: emma") + shadow.wait_until_tty_matches("3", "login: emma") shadow.wait_until_succeeds("pgrep login") shadow.sleep(2) shadow.send_chars("${password1}\n") @@ -81,16 +81,16 @@ in import ./make-test-python.nix ({ pkgs, ... }: { shadow.wait_until_succeeds("[ $(fgconsole) = 4 ]") shadow.wait_for_unit("getty@tty4.service") shadow.wait_until_succeeds("pgrep -f 'agetty.*tty4'") - shadow.wait_until_tty_matches(4, "login: ") + shadow.wait_until_tty_matches("4", "login: ") shadow.send_chars("emma\n") - shadow.wait_until_tty_matches(4, "login: emma") + shadow.wait_until_tty_matches("4", "login: emma") shadow.wait_until_succeeds("pgrep login") shadow.sleep(2) shadow.send_chars("${password1}\n") - shadow.wait_until_tty_matches(4, "Login incorrect") - shadow.wait_until_tty_matches(4, "login:") + shadow.wait_until_tty_matches("4", "Login incorrect") + shadow.wait_until_tty_matches("4", "login:") shadow.send_chars("emma\n") - shadow.wait_until_tty_matches(4, "login: emma") + shadow.wait_until_tty_matches("4", "login: emma") shadow.wait_until_succeeds("pgrep login") shadow.sleep(2) shadow.send_chars("${password3}\n") @@ -109,11 +109,11 @@ in import ./make-test-python.nix ({ pkgs, ... }: { shadow.wait_until_succeeds("[ $(fgconsole) = 5 ]") shadow.wait_for_unit("getty@tty5.service") shadow.wait_until_succeeds("pgrep -f 'agetty.*tty5'") - shadow.wait_until_tty_matches(5, "login: ") + shadow.wait_until_tty_matches("5", "login: ") shadow.send_chars("layla\n") - shadow.wait_until_tty_matches(5, "login: layla") + shadow.wait_until_tty_matches("5", "login: layla") shadow.wait_until_succeeds("pgrep login") shadow.send_chars("${password2}\n") - shadow.wait_until_tty_matches(5, "login:") + shadow.wait_until_tty_matches("5", "login:") ''; }) diff --git a/nixos/tests/sway.nix b/nixos/tests/sway.nix index 8f95f2a030d1b..52e2c7c99ec4b 100644 --- a/nixos/tests/sway.nix +++ b/nixos/tests/sway.nix @@ -4,6 +4,12 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { maintainers = with lib.maintainers; [ primeos synthetica ]; }; + # testScriptWithTypes:49: error: Cannot call function of unknown type + # (machine.succeed if succeed else machine.execute)( + # ^ + # Found 1 error in 1 file (checked 1 source file) + skipTypeCheck = true; + nodes.machine = { config, ... }: { # Automatically login on tty1 as a normal user: imports = [ ./common/user-account.nix ]; diff --git a/nixos/tests/uptermd.nix b/nixos/tests/uptermd.nix index d504ef0641916..429e3c9dd5ff3 100644 --- a/nixos/tests/uptermd.nix +++ b/nixos/tests/uptermd.nix @@ -42,7 +42,7 @@ in client1.wait_for_unit("multi-user.target") client1.wait_until_succeeds("pgrep -f 'agetty.*tty1'") - client1.wait_until_tty_matches(1, "login: ") + client1.wait_until_tty_matches("1", "login: ") client1.send_chars("root\n") client1.wait_until_succeeds("pgrep -u root bash") diff --git a/nixos/tests/user-activation-scripts.nix b/nixos/tests/user-activation-scripts.nix index 9345735781873..5df072ce0508a 100644 --- a/nixos/tests/user-activation-scripts.nix +++ b/nixos/tests/user-activation-scripts.nix @@ -19,9 +19,9 @@ import ./make-test-python.nix ({ lib, ... }: { machine.wait_for_unit("multi-user.target") machine.wait_for_unit("getty@tty1.service") - machine.wait_until_tty_matches(1, "login: ") + machine.wait_until_tty_matches("1", "login: ") machine.send_chars("alice\n") - machine.wait_until_tty_matches(1, "Password: ") + machine.wait_until_tty_matches("1", "Password: ") machine.send_chars("pass1\n") machine.send_chars("touch login-ok\n") machine.wait_for_file("/home/alice/login-ok") diff --git a/nixos/tests/user-home-mode.nix b/nixos/tests/user-home-mode.nix index 1366d102a99b3..070cb0b75cc9d 100644 --- a/nixos/tests/user-home-mode.nix +++ b/nixos/tests/user-home-mode.nix @@ -17,9 +17,9 @@ import ./make-test-python.nix ({ lib, ... }: { testScript = '' machine.wait_for_unit("multi-user.target") machine.wait_for_unit("getty@tty1.service") - machine.wait_until_tty_matches(1, "login: ") + machine.wait_until_tty_matches("1", "login: ") machine.send_chars("alice\n") - machine.wait_until_tty_matches(1, "Password: ") + machine.wait_until_tty_matches("1", "Password: ") machine.send_chars("pass1\n") machine.succeed('[ "$(stat -c %a /home/alice)" == "700" ]') machine.succeed('[ "$(stat -c %a /home/bob)" == "750" ]') diff --git a/nixos/tests/zsh-history.nix b/nixos/tests/zsh-history.nix index 355687798406b..64f32a07e2158 100644 --- a/nixos/tests/zsh-history.nix +++ b/nixos/tests/zsh-history.nix @@ -21,13 +21,13 @@ import ./make-test-python.nix ({ pkgs, ...} : { default.wait_until_succeeds("pgrep -f 'agetty.*tty1'") # Login - default.wait_until_tty_matches(1, "login: ") + default.wait_until_tty_matches("1", "login: ") default.send_chars("root\n") - default.wait_until_tty_matches(1, r"\nroot@default\b") + default.wait_until_tty_matches("1", r"\nroot@default\b") # Generate some history default.send_chars("echo foobar\n") - default.wait_until_tty_matches(1, "foobar") + default.wait_until_tty_matches("1", "foobar") # Ensure that command was recorded in history default.succeed("/run/current-system/sw/bin/history list | grep -q foobar") |