diff options
Diffstat (limited to 'nixos')
44 files changed, 457 insertions, 61 deletions
diff --git a/nixos/doc/manual/administration/nixos-state.section.md b/nixos/doc/manual/administration/nixos-state.section.md new file mode 100644 index 000000000000..9819d613198c --- /dev/null +++ b/nixos/doc/manual/administration/nixos-state.section.md @@ -0,0 +1,28 @@ +# NixOS {#sec-nixos-state} + +## `/nix` {#sec-state-nix} + +NixOS needs the entirety of `/nix` to be persistent, as it includes: +- `/nix/store`, which contains all the system's executables, libraries, and supporting data; +- `/nix/var/nix`, which contains: + - the Nix daemon's database; + - roots whose transitive closure is preserved when garbage-collecting the Nix store; + - system-wide and per-user profiles. + +## `/boot` {#sec-state-boot} + +`/boot` should also be persistent, as it contains: +- the kernel and initrd which the bootloader loads, +- the bootloader's configuration, including the kernel's command-line which + determines the store path to use as system environment. + + +## Users and groups {#sec-state-users} + +- `/var/lib/nixos` should persist: it holds state needed to generate stable + uids and gids for declaratively-managed users and groups, etc. +- `users.mutableUsers` should be false, *or* the following files under `/etc` + should all persist: + - {manpage}`passwd(5)` and {manpage}`group(5)`, + - {manpage}`shadow(5)` and {manpage}`gshadow(5)`, + - {manpage}`subuid(5)` and {manpage}`subgid(5)`. diff --git a/nixos/doc/manual/administration/running.md b/nixos/doc/manual/administration/running.md index 48e8c7c6668b..83412d9b7af5 100644 --- a/nixos/doc/manual/administration/running.md +++ b/nixos/doc/manual/administration/running.md @@ -8,6 +8,7 @@ rebooting.chapter.md user-sessions.chapter.md control-groups.chapter.md logging.chapter.md +system-state.chapter.md cleaning-store.chapter.md containers.chapter.md troubleshooting.chapter.md diff --git a/nixos/doc/manual/administration/system-state.chapter.md b/nixos/doc/manual/administration/system-state.chapter.md new file mode 100644 index 000000000000..6840cc390257 --- /dev/null +++ b/nixos/doc/manual/administration/system-state.chapter.md @@ -0,0 +1,17 @@ +# Necessary system state {#ch-system-state} + +Normally — on systems with a persistent `rootfs` — system services can persist state to +the filesystem without administrator intervention. + +However, it is possible and not-uncommon to create [impermanent systems], whose +`rootfs` is either a `tmpfs` or reset during boot. While NixOS itself supports +this kind of configuration, special care needs to be taken. + +[impermanent systems]: https://nixos.wiki/wiki/Impermanence + + +```{=include=} sections +nixos-state.section.md +systemd-state.section.md +zfs-state.section.md +``` diff --git a/nixos/doc/manual/administration/systemd-state.section.md b/nixos/doc/manual/administration/systemd-state.section.md new file mode 100644 index 000000000000..84f074871a65 --- /dev/null +++ b/nixos/doc/manual/administration/systemd-state.section.md @@ -0,0 +1,52 @@ +# systemd {#sec-systemd-state} + +## `machine-id(5)` {#sec-machine-id} + +`systemd` uses per-machine identifier — {manpage}`machine-id(5)` — which must be +unique and persistent; otherwise, the system journal may fail to list earlier +boots, etc. + +`systemd` generates a random `machine-id(5)` during boot if it does not already exist, +and persists it in `/etc/machine-id`. As such, it suffices to make that file persistent. + +Alternatively, it is possible to generate a random `machine-id(5)`; while the +specification allows for *any* hex-encoded 128b value, systemd itself uses +[UUIDv4], *i.e.* random UUIDs, and it is thus preferable to do so as well, in +case some software assumes `machine-id(5)` to be a UUIDv4. Those can be +generated with `uuidgen -r | tr -d -` (`tr` being used to remove the dashes). + +Such a `machine-id(5)` can be set by writing it to `/etc/machine-id` or through +the kernel's command-line, though NixOS' systemd maintainers [discourage] the +latter approach. + +[UUIDv4]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) +[discourage]: https://github.com/NixOS/nixpkgs/pull/268995 + + +## `/var/lib/systemd` {#sec-var-systemd} + +Moreover, `systemd` expects its state directory — `/var/lib/systemd` — to persist, for: +- {manpage}`systemd-random-seed(8)`, which loads a 256b “seed” into the kernel's RNG + at boot time, and saves a fresh one during shutdown; +- {manpage}`systemd.timer(5)` with `Persistent=yes`, which are then run after boot if + the timer would have triggered during the time the system was shut down; +- {manpage}`systemd-coredump(8)` to store core dumps there by default; + (see {manpage}`coredump.conf(5)`) +- {manpage}`systemd-timesyncd(8)`; +- {manpage}`systemd-backlight(8)` and {manpage}`systemd-rfkill(8)` persist hardware-related + state; +- possibly other things, this list is not meant to be exhaustive. + +In any case, making `/var/lib/systemd` persistent is recommended. + + +## `/var/log/journal/{machine-id}` {#sec-var-journal} + +Lastly, {manpage}`systemd-journald(8)` writes the system's journal in binary +form to `/var/log/journal/{machine-id}`; if (locally) persisting the entire log +is desired, it is recommended to make all of `/var/log/journal` persistent. + +If not, one can set `Storage=volatile` in {manpage}`journald.conf(5)` +([`services.journald.storage = "volatile";`](#opt-services.journald.storage)), +which disables journal persistence and causes it to be written to +`/run/log/journal`. diff --git a/nixos/doc/manual/administration/zfs-state.section.md b/nixos/doc/manual/administration/zfs-state.section.md new file mode 100644 index 000000000000..11ad5badea7e --- /dev/null +++ b/nixos/doc/manual/administration/zfs-state.section.md @@ -0,0 +1,16 @@ +# ZFS {#sec-zfs-state} + +When using ZFS, `/etc/zfs/zpool.cache` should be persistent (or a symlink to a persistent +location) as it is the default value for the `cachefile` [property](man:zpoolprops(7)). + +This cachefile is used on system startup to discover ZFS pools, so ZFS pools +holding the `rootfs` and/or early-boot datasets such as `/nix` can be set to +`cachefile=none`. + +In principle, if there are no other pools attached to the system, `zpool.cache` +does not need to be persisted; it is however *strongly recommended* to persist +it, in case additional pools are added later on, temporarily or permanently: + +While mishandling the cachefile does not lead to data loss by itself, it may +cause zpools not to be imported during boot, and services may then write to a +location where a dataset was expected to be mounted. diff --git a/nixos/doc/manual/release-notes/release-notes.md b/nixos/doc/manual/release-notes/release-notes.md index 3f926fb21a5c..0514a1b0044a 100644 --- a/nixos/doc/manual/release-notes/release-notes.md +++ b/nixos/doc/manual/release-notes/release-notes.md @@ -3,6 +3,7 @@ This section lists the release notes for each stable version of NixOS and current unstable revision. ```{=include=} sections +rl-2405.section.md rl-2311.section.md rl-2305.section.md rl-2211.section.md diff --git a/nixos/doc/manual/release-notes/rl-2111.section.md b/nixos/doc/manual/release-notes/rl-2111.section.md index 400eb1062d9a..8edf4fd35e4f 100644 --- a/nixos/doc/manual/release-notes/rl-2111.section.md +++ b/nixos/doc/manual/release-notes/rl-2111.section.md @@ -100,7 +100,7 @@ In addition to numerous new and upgraded packages, this release has the followin - [opensnitch](https://github.com/evilsocket/opensnitch), an application firewall. Available as [services.opensnitch](#opt-services.opensnitch.enable). - [snapraid](https://www.snapraid.it/), a backup program for disk arrays. - Available as [snapraid](#opt-snapraid.enable). + Available as [snapraid](#opt-services.snapraid.enable). - [Hockeypuck](https://github.com/hockeypuck/hockeypuck), a OpenPGP Key Server. Available as [services.hockeypuck](#opt-services.hockeypuck.enable). diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index 5c6bdf97d120..1aef1828908f 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -1313,6 +1313,14 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2 - When using [split parity files](https://www.snapraid.it/manual#7.1) in `snapraid`, the snapraid-sync systemd service will no longer fail to run. +- `wpa_supplicant`'s configuration file cannot be read by non-root users, and + secrets (such as Pre-Shared Keys) can safely be passed via + `networking.wireless.environmentFile`. + + The configuration file could previously be read, when `userControlled.enable` (non-default), + by users who are in both `wheel` and `userControlled.group` (defaults to `wheel`) + + ## Nixpkgs Library {#sec-release-23.11-nixpkgs-lib} ### Breaking Changes {#sec-release-23.11-lib-breaking} diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 3ea887bfee40..f792194da224 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -10,6 +10,10 @@ In addition to numerous new and upgraded packages, this release has the followin - `screen`'s module has been cleaned, and will now require you to set `programs.screen.enable` in order to populate `screenrc` and add the program to the environment. +- NixOS now installs a stub ELF loader that prints an informative error message when users attempt to run binaries not made for NixOS. + - This can be disabled through the `environment.stub-ld.enable` option. + - If you use `programs.nix-ld.enable`, no changes are needed. The stub will be disabled automatically. + ## New Services {#sec-release-24.05-new-services} <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. --> @@ -73,6 +77,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m `globalRedirect` can now have redirect codes other than 301 through `redirectCode`. +- [](#opt-boot.kernel.sysctl._net.core.wmem_max_) changed from a string to an integer because of the addition of a custom merge option (taking the highest value defined to avoid conflicts between 2 services trying to set that value), just as [](#opt-boot.kernel.sysctl._net.core.rmem_max_) since 22.11. + - Gitea 1.21 upgrade has several breaking changes, including: - Custom themes and other assets that were previously stored in `custom/public/*` now belong in `custom/public/assets/*` - New instances of Gitea using MySQL now ignore the `[database].CHARSET` config option and always use the `utf8mb4` charset, existing instances should migrate via the `gitea doctor convert` CLI command. diff --git a/nixos/lib/test-driver/test_driver/machine.py b/nixos/lib/test-driver/test_driver/machine.py index f430321bb607..da60b669fa27 100644 --- a/nixos/lib/test-driver/test_driver/machine.py +++ b/nixos/lib/test-driver/test_driver/machine.py @@ -447,8 +447,7 @@ class Machine: """ def check_active(_: Any) -> bool: - info = self.get_unit_info(unit, user) - state = info["ActiveState"] + state = self.get_unit_property(unit, "ActiveState", user) if state == "failed": raise Exception(f'unit "{unit}" reached state "{state}"') @@ -491,6 +490,35 @@ class Machine: if line_pattern.match(line) ) + def get_unit_property( + self, + unit: str, + property: str, + user: Optional[str] = None, + ) -> str: + status, lines = self.systemctl( + f'--no-pager show "{unit}" --property="{property}"', + user, + ) + if status != 0: + raise Exception( + f'retrieving systemctl property "{property}" for unit "{unit}"' + + ("" if user is None else f' under user "{user}"') + + f" failed with exit code {status}" + ) + + invalid_output_message = ( + f'systemctl show --property "{property}" "{unit}"' + f"produced invalid output: {lines}" + ) + + line_pattern = re.compile(r"^([^=]+)=(.*)$") + match = line_pattern.match(lines) + assert match is not None, invalid_output_message + + assert match[1] == property, invalid_output_message + return match[2] + def systemctl(self, q: str, user: Optional[str] = None) -> Tuple[int, str]: """ Runs `systemctl` commands with optional support for diff --git a/nixos/modules/config/ldso.nix b/nixos/modules/config/ldso.nix new file mode 100644 index 000000000000..e5ae13a21145 --- /dev/null +++ b/nixos/modules/config/ldso.nix @@ -0,0 +1,58 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) last splitString mkOption types mdDoc optionals; + + libDir = pkgs.stdenv.hostPlatform.libDir; + ldsoBasename = last (splitString "/" pkgs.stdenv.cc.bintools.dynamicLinker); + + pkgs32 = pkgs.pkgsi686Linux; + libDir32 = pkgs32.stdenv.hostPlatform.libDir; + ldsoBasename32 = last (splitString "/" pkgs32.stdenv.cc.bintools.dynamicLinker); +in { + options = { + environment.ldso = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + The executable to link into the normal FHS location of the ELF loader. + ''; + }; + + environment.ldso32 = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + The executable to link into the normal FHS location of the 32-bit ELF loader. + + This currently only works on x86_64 architectures. + ''; + }; + }; + + config = { + assertions = [ + { assertion = isNull config.environment.ldso32 || pkgs.stdenv.isx86_64; + message = "Option environment.ldso32 currently only works on x86_64."; + } + ]; + + systemd.tmpfiles.rules = ( + if isNull config.environment.ldso then [ + "r /${libDir}/${ldsoBasename} - - - - -" + ] else [ + "d /${libDir} 0755 root root - -" + "L+ /${libDir}/${ldsoBasename} - - - - ${config.environment.ldso}" + ] + ) ++ optionals pkgs.stdenv.isx86_64 ( + if isNull config.environment.ldso32 then [ + "r /${libDir32}/${ldsoBasename32} - - - - -" + ] else [ + "d /${libDir32} 0755 root root - -" + "L+ /${libDir32}/${ldsoBasename32} - - - - ${config.environment.ldso32}" + ] + ); + }; + + meta.maintainers = with lib.maintainers; [ tejing ]; +} diff --git a/nixos/modules/config/stub-ld.nix b/nixos/modules/config/stub-ld.nix new file mode 100644 index 000000000000..14c07466d061 --- /dev/null +++ b/nixos/modules/config/stub-ld.nix @@ -0,0 +1,56 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) optionalString mkOption types mdDoc mkIf mkDefault; + + cfg = config.environment.stub-ld; + + message = '' + NixOS cannot run dynamically linked executables intended for generic + linux environments out of the box. For more information, see: + https://nix.dev/permalink/stub-ld + ''; + + stub-ld-for = pkgsArg: messageArg: pkgsArg.pkgsStatic.runCommandCC "stub-ld" { + nativeBuildInputs = [ pkgsArg.unixtools.xxd ]; + inherit messageArg; + } '' + printf "%s" "$messageArg" | xxd -i -n message >main.c + cat <<EOF >>main.c + #include <stdio.h> + int main(int argc, char * argv[]) { + fprintf(stderr, "Could not start dynamically linked executable: %s\n", argv[0]); + fwrite(message, sizeof(unsigned char), message_len, stderr); + return 127; // matches behavior of bash and zsh without a loader. fish uses 139 + } + EOF + $CC -Os main.c -o $out + ''; + + pkgs32 = pkgs.pkgsi686Linux; + + stub-ld = stub-ld-for pkgs message; + stub-ld32 = stub-ld-for pkgs32 message; +in { + options = { + environment.stub-ld = { + enable = mkOption { + type = types.bool; + default = true; + example = false; + description = mdDoc '' + Install a stub ELF loader to print an informative error message + in the event that a user attempts to run an ELF binary not + compiled for NixOS. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + environment.ldso = mkDefault stub-ld; + environment.ldso32 = mkIf pkgs.stdenv.isx86_64 (mkDefault stub-ld32); + }; + + meta.maintainers = with lib.maintainers; [ tejing ]; +} diff --git a/nixos/modules/config/sysctl.nix b/nixos/modules/config/sysctl.nix index 452c050b6dda..b779f12aca30 100644 --- a/nixos/modules/config/sysctl.nix +++ b/nixos/modules/config/sysctl.nix @@ -21,19 +21,27 @@ in options = { boot.kernel.sysctl = mkOption { - type = types.submodule { + type = let + highestValueType = types.ints.unsigned // { + merge = loc: defs: + foldl + (a: b: if b.value == null then null else lib.max a b.value) + 0 + (filterOverrides defs); + }; + in types.submodule { freeformType = types.attrsOf sysctlOption; options."net.core.rmem_max" = mkOption { - type = types.nullOr types.ints.unsigned // { - merge = loc: defs: - foldl - (a: b: if b.value == null then null else lib.max a b.value) - 0 - (filterOverrides defs); - }; + type = types.nullOr highestValueType; default = null; description = lib.mdDoc "The maximum socket receive buffer size. In case of conflicting values, the highest will be used."; }; + + options."net.core.wmem_max" = mkOption { + type = types.nullOr highestValueType; + default = null; + description = lib.mdDoc "The maximum socket send buffer size. In case of conflicting values, the highest will be used."; + }; }; default = {}; example = literalExpression '' diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 39aac9fb821b..2aed620eb154 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -475,7 +475,7 @@ let sdInitrdUidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) config.boot.initrd.systemd.users) "uid"; sdInitrdGidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) config.boot.initrd.systemd.groups) "gid"; groupNames = lib.mapAttrsToList (n: g: g.name) cfg.groups; - usersWithoutExistingGroup = lib.filterAttrs (n: u: !lib.elem u.group groupNames) cfg.users; + usersWithoutExistingGroup = lib.filterAttrs (n: u: u.group != "" && !lib.elem u.group groupNames) cfg.users; spec = pkgs.writeText "users-groups.json" (builtins.toJSON { inherit (cfg) mutableUsers; diff --git a/nixos/modules/hardware/keyboard/qmk.nix b/nixos/modules/hardware/keyboard/qmk.nix index df3bcaeccd2e..d95d36dedb44 100644 --- a/nixos/modules/hardware/keyboard/qmk.nix +++ b/nixos/modules/hardware/keyboard/qmk.nix @@ -12,5 +12,6 @@ in config = mkIf cfg.enable { services.udev.packages = [ pkgs.qmk-udev-rules ]; + users.groups.plugdev = {}; }; } diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 820ce54ddeb6..c0bd0b1600b9 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -12,6 +12,7 @@ ./config/iproute2.nix ./config/krb5/default.nix ./config/ldap.nix + ./config/ldso.nix ./config/locale.nix ./config/malloc.nix ./config/mysql.nix @@ -28,6 +29,7 @@ ./config/resolvconf.nix ./config/shells-environment.nix ./config/stevenblack.nix + ./config/stub-ld.nix ./config/swap.nix ./config/sysctl.nix ./config/system-environment.nix @@ -364,6 +366,7 @@ ./services/backup/mysql-backup.nix ./services/backup/postgresql-backup.nix ./services/backup/postgresql-wal-receiver.nix + ./services/backup/snapraid.nix ./services/backup/restic-rest-server.nix ./services/backup/restic.nix ./services/backup/rsnapshot.nix @@ -1507,7 +1510,6 @@ ./tasks/network-interfaces.nix ./tasks/powertop.nix ./tasks/scsi-link-power-management.nix - ./tasks/snapraid.nix ./tasks/stratis.nix ./tasks/swraid.nix ./tasks/trackpoint.nix diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix index 75f355b4a002..b76740f7cc58 100644 --- a/nixos/modules/profiles/minimal.nix +++ b/nixos/modules/profiles/minimal.nix @@ -21,6 +21,8 @@ with lib; # Perl is a default package. environment.defaultPackages = mkDefault [ ]; + environment.stub-ld.enable = false; + # The lessopen package pulls in Perl. programs.less.lessopen = mkDefault null; diff --git a/nixos/modules/programs/hyprland.nix b/nixos/modules/programs/hyprland.nix index 166c6cbc5c18..9061ce5da83a 100644 --- a/nixos/modules/programs/hyprland.nix +++ b/nixos/modules/programs/hyprland.nix @@ -30,7 +30,6 @@ in readOnly = true; default = cfg.package.override { enableXWayland = cfg.xwayland.enable; - enableNvidiaPatches = cfg.enableNvidiaPatches; }; defaultText = literalExpression "`programs.hyprland.package` with applied configuration"; @@ -42,8 +41,6 @@ in portalPackage = mkPackageOption pkgs "xdg-desktop-portal-hyprland" { }; xwayland.enable = mkEnableOption (mdDoc "XWayland") // { default = true; }; - - enableNvidiaPatches = mkEnableOption (mdDoc "patching wlroots for better Nvidia support"); }; config = mkIf cfg.enable { @@ -73,9 +70,13 @@ in [ "programs" "hyprland" "xwayland" "hidpi" ] "XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland" ) - (mkRenamedOptionModule - [ "programs" "hyprland" "nvidiaPatches" ] + (mkRemovedOptionModule [ "programs" "hyprland" "enableNvidiaPatches" ] + "Nvidia patches are no longer needed" + ) + (mkRemovedOptionModule + [ "programs" "hyprland" "nvidiaPatches" ] + "Nvidia patches are no longer needed" ) ]; } diff --git a/nixos/modules/programs/nix-ld.nix b/nixos/modules/programs/nix-ld.nix index e3a9bb16410c..6f36ce33640c 100644 --- a/nixos/modules/programs/nix-ld.nix +++ b/nixos/modules/programs/nix-ld.nix @@ -47,7 +47,7 @@ in }; config = lib.mkIf config.programs.nix-ld.enable { - systemd.tmpfiles.packages = [ cfg.package ]; + environment.ldso = "${cfg.package}/libexec/nix-ld"; environment.systemPackages = [ nix-ld-libraries ]; diff --git a/nixos/modules/programs/wayland/river.nix b/nixos/modules/programs/wayland/river.nix index ec59bd50a015..995129b9710a 100644 --- a/nixos/modules/programs/wayland/river.nix +++ b/nixos/modules/programs/wayland/river.nix @@ -48,6 +48,9 @@ in { # To make a river session available if a display manager like SDDM is enabled: services.xserver.displayManager.sessionPackages = optionals (cfg.package != null) [ cfg.package ]; + + # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050913 + xdg.portal.config.river.default = mkDefault [ "wlr" "gtk" ]; } (import ./wayland-session.nix { inherit lib pkgs; }) ]); diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix index e3eb504e0adf..b222dd952d15 100644 --- a/nixos/modules/services/backup/restic.nix +++ b/nixos/modules/services/backup/restic.nix @@ -384,10 +384,11 @@ in ${lib.optionalString (backup.environmentFile != null) "source ${backup.environmentFile}"} # set same environment variables as the systemd service ${lib.pipe config.systemd.services."restic-backups-${name}".environment [ - (lib.filterAttrs (_: v: v != null)) + (lib.filterAttrs (n: v: v != null && n != "PATH")) (lib.mapAttrsToList (n: v: "${n}=${v}")) (lib.concatStringsSep "\n") ]} + PATH=${config.systemd.services."restic-backups-${name}".environment.PATH}:$PATH exec ${resticCmd} $@ '') (lib.filterAttrs (_: v: v.createWrapper) config.services.restic.backups); diff --git a/nixos/modules/tasks/snapraid.nix b/nixos/modules/services/backup/snapraid.nix index 9570c6b76123..c9b2550e80e8 100644 --- a/nixos/modules/tasks/snapraid.nix +++ b/nixos/modules/services/backup/snapraid.nix @@ -2,10 +2,15 @@ with lib; -let cfg = config.snapraid; +let cfg = config.services.snapraid; in { - options.snapraid = with types; { + imports = [ + # Should have never been on the top-level. + (mkRenamedOptionModule [ "snapraid" ] [ "services" "snapraid" ]) + ]; + + options.services.snapraid = with types; { enable = mkEnableOption (lib.mdDoc "SnapRAID"); dataDisks = mkOption { default = { }; diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix index e96743784e04..d69cf4587aab 100644 --- a/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -236,6 +236,7 @@ in { serviceConfig = { User = cfg.user; + StateDirectory = mkIf (hasPrefix "/var/lib/jenkins" cfg.home) "jenkins"; }; }; }; diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index d0058fd1948b..ed5915735730 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -404,7 +404,7 @@ in default = {}; description = lib.mdDoc '' PostgreSQL configuration. Refer to - <https://www.postgresql.org/docs/15/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE> + <https://www.postgresql.org/docs/current/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE> for an overview of `postgresql.conf`. ::: {.note} diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix index 08ca7a0d247d..311f60795bae 100644 --- a/nixos/modules/services/hardware/udev.nix +++ b/nixos/modules/services/hardware/udev.nix @@ -222,6 +222,9 @@ in description = lib.mdDoc '' Packages added to the {env}`PATH` environment variable when executing programs from Udev rules. + + coreutils, gnu{sed,grep}, util-linux and config.systemd.package are + automatically included. ''; }; diff --git a/nixos/modules/services/matrix/synapse.md b/nixos/modules/services/matrix/synapse.md index 58be24204fcf..f270be8c8d78 100644 --- a/nixos/modules/services/matrix/synapse.md +++ b/nixos/modules/services/matrix/synapse.md @@ -16,13 +16,13 @@ around Matrix. ## Synapse Homeserver {#module-services-matrix-synapse} -[Synapse](https://github.com/matrix-org/synapse) is +[Synapse](https://github.com/element-hq/synapse) is the reference homeserver implementation of Matrix from the core development team at matrix.org. The following configuration example will set up a synapse server for the `example.org` domain, served from the host `myhostname.example.org`. For more information, please refer to the -[installation instructions of Synapse](https://matrix-org.github.io/synapse/latest/setup/installation.html) . +[installation instructions of Synapse](https://element-hq.github.io/synapse/latest/setup/installation.html) . ``` { pkgs, lib, config, ... }: let @@ -70,7 +70,7 @@ in { # the domain (i.e. example.org from @foo:example.org) and the federation port # is 8448. # Further reference can be found in the docs about delegation under - # https://matrix-org.github.io/synapse/latest/delegate.html + # https://element-hq.github.io/synapse/latest/delegate.html locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; # This is usually needed for homeserver discovery (from e.g. other Matrix clients). # Further reference can be found in the upstream docs at @@ -169,7 +169,7 @@ in an additional file like this: ::: {.note} It's also possible to user alternative authentication mechanism such as [LDAP (via `matrix-synapse-ldap3`)](https://github.com/matrix-org/matrix-synapse-ldap3) -or [OpenID](https://matrix-org.github.io/synapse/latest/openid.html). +or [OpenID](https://element-hq.github.io/synapse/latest/openid.html). ::: ## Element (formerly known as Riot) Web Client {#module-services-matrix-element-web} diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix index 9cc769c2d0db..50019d2a25cb 100644 --- a/nixos/modules/services/matrix/synapse.nix +++ b/nixos/modules/services/matrix/synapse.nix @@ -446,7 +446,7 @@ in { default = { }; description = mdDoc '' The primary synapse configuration. See the - [sample configuration](https://github.com/matrix-org/synapse/blob/v${pkgs.matrix-synapse-unwrapped.version}/docs/sample_config.yaml) + [sample configuration](https://github.com/element-hq/synapse/blob/v${pkgs.matrix-synapse-unwrapped.version}/docs/sample_config.yaml) for possible values. Secrets should be passed in by using the `extraConfigFiles` option. @@ -749,7 +749,7 @@ in { by the module, but in practice it broke on runtime and as a result, no URL preview worked anywhere if this was set. - See https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#url_preview_url_blacklist + See https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#url_preview_url_blacklist on how to configure it properly. '')) (types.attrsOf types.str)); @@ -873,7 +873,7 @@ in { Redis configuration for synapse. See the - [upstream documentation](https://github.com/matrix-org/synapse/blob/v${pkgs.matrix-synapse-unwrapped.version}/usage/configuration/config_documentation.md#redis) + [upstream documentation](https://github.com/element-hq/synapse/blob/v${pkgs.matrix-synapse-unwrapped.version}/docs/usage/configuration/config_documentation.md#redis) for available options. ''; }; @@ -886,7 +886,7 @@ in { description = lib.mdDoc '' Options for configuring workers. Worker support will be enabled if at least one worker is configured here. - See the [worker documention](https://matrix-org.github.io/synapse/latest/workers.html#worker-configuration) + See the [worker documention](https://element-hq.github.io/synapse/latest/workers.html#worker-configuration) for possible options for each worker. Worker-specific options overriding the shared homeserver configuration can be specified here for each worker. @@ -900,9 +900,9 @@ in { using [`services.matrix-synapse.configureRedisLocally`](#opt-services.matrix-synapse.configureRedisLocally). Workers also require a proper reverse proxy setup to direct incoming requests to the appropriate process. See - the [reverse proxy documentation](https://matrix-org.github.io/synapse/latest/reverse_proxy.html) for a + the [reverse proxy documentation](https://element-hq.github.io/synapse/latest/reverse_proxy.html) for a general reverse proxying setup and - the [worker documentation](https://matrix-org.github.io/synapse/latest/workers.html#available-worker-applications) + the [worker documentation](https://element-hq.github.io/synapse/latest/workers.html#available-worker-applications) for the available endpoints per worker application. ::: ''; @@ -932,7 +932,7 @@ in { The file for log configuration. See the [python documentation](https://docs.python.org/3/library/logging.config.html#configuration-dictionary-schema) - for the schema and the [upstream repository](https://github.com/matrix-org/synapse/blob/v${pkgs.matrix-synapse-unwrapped.version}/docs/sample_log_config.yaml) + for the schema and the [upstream repository](https://github.com/element-hq/synapse/blob/v${pkgs.matrix-synapse-unwrapped.version}/docs/sample_log_config.yaml) for an example. ''; }; diff --git a/nixos/modules/services/misc/guix/default.nix b/nixos/modules/services/misc/guix/default.nix index 7b468e7067cc..3e1a212693b9 100644 --- a/nixos/modules/services/misc/guix/default.nix +++ b/nixos/modules/services/misc/guix/default.nix @@ -373,7 +373,6 @@ in serviceConfig = { Type = "oneshot"; - MemoryDenyWriteExecute = true; PrivateDevices = true; PrivateNetworks = true; ProtectControlGroups = true; diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix index e78cb4d01dc5..b4ac8e21451a 100644 --- a/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixos/modules/services/monitoring/prometheus/default.nix @@ -1435,6 +1435,10 @@ let remote_timeout = mkOpt types.str '' Timeout for requests to the remote write endpoint. ''; + headers = mkOpt (types.attrsOf types.str) '' + Custom HTTP headers to be sent along with each remote write request. + Be aware that headers that are set by Prometheus itself can't be overwritten. + ''; write_relabel_configs = mkOpt (types.listOf promTypes.relabel_config) '' List of remote write relabel configurations. ''; @@ -1530,6 +1534,10 @@ let remote_timeout = mkOpt types.str '' Timeout for requests to the remote read endpoint. ''; + headers = mkOpt (types.attrsOf types.str) '' + Custom HTTP headers to be sent along with each remote read request. + Be aware that headers that are set by Prometheus itself can't be overwritten. + ''; read_recent = mkOpt types.bool '' Whether reads should be made for queries for time ranges that the local storage should have complete data for. diff --git a/nixos/modules/services/networking/jigasi.nix b/nixos/modules/services/networking/jigasi.nix index 8d2d25c6edfc..e701689031b1 100644 --- a/nixos/modules/services/networking/jigasi.nix +++ b/nixos/modules/services/networking/jigasi.nix @@ -96,7 +96,7 @@ in config = mkOption { type = attrsOf str; default = { }; - example = literalExample '' + example = literalExpression '' { "org.jitsi.jigasi.auth.URL" = "XMPP:jitsi-meet.example.com"; } diff --git a/nixos/modules/services/networking/nebula.nix b/nixos/modules/services/networking/nebula.nix index b9ebbfbd9a29..e13876172dac 100644 --- a/nixos/modules/services/networking/nebula.nix +++ b/nixos/modules/services/networking/nebula.nix @@ -196,7 +196,7 @@ in before = [ "sshd.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { - Type = "simple"; + Type = "notify"; Restart = "always"; ExecStart = "${netCfg.package}/bin/nebula -config ${configFile}"; UMask = "0027"; diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index 99d4d9eeffcc..e0425792431e 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -559,6 +559,15 @@ in { ''; }; + databaseDir = mkOption { + type = types.path; + description = lib.mdDoc '' + The directory containing the database and logs. + ''; + default = cfg.configDir; + defaultText = literalExpression "config.${opt.configDir}"; + }; + extraFlags = mkOption { type = types.listOf types.str; default = []; @@ -660,7 +669,7 @@ in { -no-browser \ -gui-address=${if isUnixGui then "unix://" else ""}${cfg.guiAddress} \ -config=${cfg.configDir} \ - -data=${cfg.dataDir} \ + -data=${cfg.databaseDir} \ ${escapeShellArgs cfg.extraFlags} ''; MemoryDenyWriteExecute = true; diff --git a/nixos/modules/services/networking/tinyproxy.nix b/nixos/modules/services/networking/tinyproxy.nix index 42d45c460c2e..8ff12b52f10c 100644 --- a/nixos/modules/services/networking/tinyproxy.nix +++ b/nixos/modules/services/networking/tinyproxy.nix @@ -85,7 +85,7 @@ in User = "tinyproxy"; Group = "tinyproxy"; Type = "simple"; - ExecStart = "${getExe pkgs.tinyproxy} -d -c ${configFile}"; + ExecStart = "${getExe cfg.package} -d -c ${configFile}"; ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID"; KillSignal = "SIGINT"; TimeoutStopSec = "30s"; diff --git a/nixos/modules/services/networking/vdirsyncer.nix b/nixos/modules/services/networking/vdirsyncer.nix index 6a069943434d..165dc70f0876 100644 --- a/nixos/modules/services/networking/vdirsyncer.nix +++ b/nixos/modules/services/networking/vdirsyncer.nix @@ -20,9 +20,11 @@ let else pkgs.writeText "vdirsyncer-${name}.conf" (toIniJson ( { - general = cfg'.config.general // (lib.optionalAttrs (cfg'.config.statusPath == null) { - status_path = "/var/lib/vdirsyncer/${name}"; - }); + general = cfg'.config.general // { + status_path = if cfg'.config.statusPath == null + then "/var/lib/vdirsyncer/${name}" + else cfg'.config.statusPath; + }; } // ( mapAttrs' (name: nameValuePair "pair ${name}") cfg'.config.pairs ) // ( diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix index 90d9c68433cf..4586550ed75e 100644 --- a/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -107,6 +107,10 @@ let stopIfChanged = false; path = [ package ]; + # if `userControl.enable`, the supplicant automatically changes the permissions + # and owning group of the runtime dir; setting `umask` ensures the generated + # config file isn't readable (except to root); see nixpkgs#267693 + serviceConfig.UMask = "066"; serviceConfig.RuntimeDirectory = "wpa_supplicant"; serviceConfig.RuntimeDirectoryMode = "700"; serviceConfig.EnvironmentFile = mkIf (cfg.environmentFile != null) diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix index 88537f8c4f7b..7fb7847ce935 100644 --- a/nixos/modules/services/torrent/transmission.nix +++ b/nixos/modules/services/torrent/transmission.nix @@ -434,7 +434,7 @@ in # at least up to the values hardcoded here: (mkIf cfg.settings.utp-enabled { "net.core.rmem_max" = mkDefault 4194304; # 4MB - "net.core.wmem_max" = mkDefault "1048576"; # 1MB + "net.core.wmem_max" = mkDefault 1048576; # 1MB }) (mkIf cfg.performanceNetParameters { # Increase the number of available source (local) TCP and UDP ports to 49151. diff --git a/nixos/modules/services/web-apps/node-red.nix b/nixos/modules/services/web-apps/node-red.nix index de78f05a98ca..7f265d289bdb 100644 --- a/nixos/modules/services/web-apps/node-red.nix +++ b/nixos/modules/services/web-apps/node-red.nix @@ -19,7 +19,7 @@ in options.services.node-red = { enable = mkEnableOption (lib.mdDoc "the Node-RED service"); - package = mkPackageOption pkgs "nodePackages.node-red" { }; + package = mkPackageOption pkgs.nodePackages "node-red" { }; openFirewall = mkOption { type = types.bool; diff --git a/nixos/modules/services/web-servers/caddy/default.nix b/nixos/modules/services/web-servers/caddy/default.nix index 9a544e98cfc4..95dc219d108c 100644 --- a/nixos/modules/services/web-servers/caddy/default.nix +++ b/nixos/modules/services/web-servers/caddy/default.nix @@ -342,8 +342,9 @@ in } ''; - # https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size + # https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes boot.kernel.sysctl."net.core.rmem_max" = mkDefault 2500000; + boot.kernel.sysctl."net.core.wmem_max" = mkDefault 2500000; systemd.packages = [ cfg.package ]; systemd.services.caddy = { diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 523035ae2a0a..ab07428cf055 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -788,6 +788,7 @@ in { step-ca = handleTestOn ["x86_64-linux"] ./step-ca.nix {}; stratis = handleTest ./stratis {}; strongswan-swanctl = handleTest ./strongswan-swanctl.nix {}; + stub-ld = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./stub-ld.nix {}; stunnel = handleTest ./stunnel.nix {}; sudo = handleTest ./sudo.nix {}; sudo-rs = handleTest ./sudo-rs.nix {}; diff --git a/nixos/tests/ceph-single-node.nix b/nixos/tests/ceph-single-node.nix index 4a5636fac156..a3a4072365af 100644 --- a/nixos/tests/ceph-single-node.nix +++ b/nixos/tests/ceph-single-node.nix @@ -182,16 +182,19 @@ let monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'") monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'") + # This test has been commented out due to the upstream issue with pyo3 + # that has broken this dashboard + # Reference: https://www.spinics.net/lists/ceph-users/msg77812.html # Enable the dashboard and recheck health - monA.succeed( - "ceph mgr module enable dashboard", - "ceph config set mgr mgr/dashboard/ssl false", - # default is 8080 but it's better to be explicit - "ceph config set mgr mgr/dashboard/server_port 8080", - ) - monA.wait_for_open_port(8080) - monA.wait_until_succeeds("curl -q --fail http://localhost:8080") - monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'") + # monA.succeed( + # "ceph mgr module enable dashboard", + # "ceph config set mgr mgr/dashboard/ssl false", + # # default is 8080 but it's better to be explicit + # "ceph config set mgr mgr/dashboard/server_port 8080", + # ) + # monA.wait_for_open_port(8080) + # monA.wait_until_succeeds("curl -q --fail http://localhost:8080") + # monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'") ''; in { name = "basic-single-node-ceph-cluster"; diff --git a/nixos/tests/guix/basic.nix b/nixos/tests/guix/basic.nix index 7f90bdeeb1e0..9b943b8965e6 100644 --- a/nixos/tests/guix/basic.nix +++ b/nixos/tests/guix/basic.nix @@ -11,7 +11,10 @@ import ../make-test-python.nix ({ lib, pkgs, ... }: { nodes.machine = { config, ... }: { environment.etc."guix/scripts".source = ./scripts; - services.guix.enable = true; + services.guix = { + enable = true; + gc.enable = true; + }; }; testScript = '' @@ -19,6 +22,7 @@ import ../make-test-python.nix ({ lib, pkgs, ... }: { machine.wait_for_unit("multi-user.target") machine.wait_for_unit("guix-daemon.service") + machine.succeed("systemctl start guix-gc.service") # Can't do much here since the environment has restricted network access. with subtest("Guix basic package management"): diff --git a/nixos/tests/nebula.nix b/nixos/tests/nebula.nix index 1bece2200f23..89b91d89fcb3 100644 --- a/nixos/tests/nebula.nix +++ b/nixos/tests/nebula.nix @@ -144,7 +144,6 @@ in restartAndCheckNebula = name: ip: '' ${name}.systemctl("restart nebula@smoke.service") - ${name}.wait_for_unit("nebula@smoke.service") ${name}.succeed("ping -c5 ${ip}") ''; @@ -180,8 +179,6 @@ in ${nodeB}.succeed("iptables -I INPUT -s " + node_a + " -j DROP") ${nodeA}.systemctl("restart nebula@smoke.service") ${nodeB}.systemctl("restart nebula@smoke.service") - ${nodeA}.wait_for_unit("nebula@smoke.service") - ${nodeB}.wait_for_unit("nebula@smoke.service") ''; allowTrafficBetween = nodeA: nodeB: '' node_a = ${getPublicIp nodeA} @@ -190,8 +187,6 @@ in ${nodeB}.succeed("iptables -D INPUT -s " + node_a + " -j DROP") ${nodeA}.systemctl("restart nebula@smoke.service") ${nodeB}.systemctl("restart nebula@smoke.service") - ${nodeA}.wait_for_unit("nebula@smoke.service") - ${nodeB}.wait_for_unit("nebula@smoke.service") ''; in '' # Create the certificate and sign the lighthouse's keys. diff --git a/nixos/tests/stub-ld.nix b/nixos/tests/stub-ld.nix new file mode 100644 index 000000000000..25161301741b --- /dev/null +++ b/nixos/tests/stub-ld.nix @@ -0,0 +1,73 @@ +import ./make-test-python.nix ({ lib, pkgs, ... }: { + name = "stub-ld"; + + nodes.machine = { lib, ... }: + { + environment.stub-ld.enable = true; + + specialisation.nostub = { + inheritParentConfig = true; + + configuration = { ... }: { + environment.stub-ld.enable = lib.mkForce false; + }; + }; + }; + + testScript = let + libDir = pkgs.stdenv.hostPlatform.libDir; + ldsoBasename = lib.last (lib.splitString "/" pkgs.stdenv.cc.bintools.dynamicLinker); + + check32 = pkgs.stdenv.isx86_64; + pkgs32 = pkgs.pkgsi686Linux; + + libDir32 = pkgs32.stdenv.hostPlatform.libDir; + ldsoBasename32 = lib.last (lib.splitString "/" pkgs32.stdenv.cc.bintools.dynamicLinker); + + test-exec = builtins.mapAttrs (n: v: pkgs.runCommand "test-exec-${n}" { src = pkgs.fetchurl v; } "mkdir -p $out;cd $out;tar -xzf $src") { + x86_64-linux.url = "https://github.com/rustic-rs/rustic/releases/download/v0.6.1/rustic-v0.6.1-x86_64-unknown-linux-gnu.tar.gz"; + x86_64-linux.hash = "sha256-3zySzx8MKFprMOi++yr2ZGASE0aRfXHQuG3SN+kWUCI="; + i686-linux.url = "https://github.com/rustic-rs/rustic/releases/download/v0.6.1/rustic-v0.6.1-i686-unknown-linux-gnu.tar.gz"; + i686-linux.hash = "sha256-fWNiATFeg0B2pfB5zndlnzGn7Ztl8diVS1rFLEDnSLU="; + aarch64-linux.url = "https://github.com/rustic-rs/rustic/releases/download/v0.6.1/rustic-v0.6.1-aarch64-unknown-linux-gnu.tar.gz"; + aarch64-linux.hash = "sha256-hnldbd2cctQIAhIKoEZLIWY8H3jiFBClkNy2UlyyvAs="; + }; + exec-name = "rustic"; + + if32 = pythonStatement: if check32 then pythonStatement else "pass"; + in + '' + machine.start() + machine.wait_for_unit("multi-user.target") + + with subtest("Check for stub (enabled, initial)"): + machine.succeed('test -L /${libDir}/${ldsoBasename}') + ${if32 "machine.succeed('test -L /${libDir32}/${ldsoBasename32}')"} + + with subtest("Try FHS executable"): + machine.copy_from_host('${test-exec.${pkgs.system}}','test-exec') + machine.succeed('if test-exec/${exec-name} 2>outfile; then false; else [ $? -eq 127 ];fi') + machine.succeed('grep -qi nixos outfile') + ${if32 "machine.copy_from_host('${test-exec.${pkgs32.system}}','test-exec32')"} + ${if32 "machine.succeed('if test-exec32/${exec-name} 2>outfile32; then false; else [ $? -eq 127 ];fi')"} + ${if32 "machine.succeed('grep -qi nixos outfile32')"} + + with subtest("Disable stub"): + machine.succeed("/run/booted-system/specialisation/nostub/bin/switch-to-configuration test") + + with subtest("Check for stub (disabled)"): + machine.fail('test -e /${libDir}/${ldsoBasename}') + ${if32 "machine.fail('test -e /${libDir32}/${ldsoBasename32}')"} + + with subtest("Create file in stub location (to be overwritten)"): + machine.succeed('mkdir -p /${libDir};touch /${libDir}/${ldsoBasename}') + ${if32 "machine.succeed('mkdir -p /${libDir32};touch /${libDir32}/${ldsoBasename32}')"} + + with subtest("Re-enable stub"): + machine.succeed("/run/booted-system/bin/switch-to-configuration test") + + with subtest("Check for stub (enabled, final)"): + machine.succeed('test -L /${libDir}/${ldsoBasename}') + ${if32 "machine.succeed('test -L /${libDir32}/${ldsoBasename32}')"} + ''; +}) diff --git a/nixos/tests/telegraf.nix b/nixos/tests/telegraf.nix index af9c5c387a5d..c3cdb1645213 100644 --- a/nixos/tests/telegraf.nix +++ b/nixos/tests/telegraf.nix @@ -12,7 +12,6 @@ import ./make-test-python.nix ({ pkgs, ...} : { services.telegraf.extraConfig = { agent.interval = "1s"; agent.flush_interval = "1s"; - inputs.procstat = {}; inputs.exec = { commands = [ "${pkgs.runtimeShell} -c 'echo $SECRET,tag=a i=42i'" |