diff options
Diffstat (limited to 'nixos')
58 files changed, 837 insertions, 147 deletions
diff --git a/nixos/doc/manual/development/option-types.section.md b/nixos/doc/manual/development/option-types.section.md index 2ad3d6c4f9495..f9c7ac80018e4 100644 --- a/nixos/doc/manual/development/option-types.section.md +++ b/nixos/doc/manual/development/option-types.section.md @@ -13,6 +13,13 @@ merging is handled. `types.bool` : A boolean, its values can be `true` or `false`. + All definitions must have the same value, after priorities. An error is thrown in case of a conflict. + +`types.boolByOr` + +: A boolean, its values can be `true` or `false`. + The result is `true` if _any_ of multiple definitions is `true`. + In other words, definitions are merged with the logical _OR_ operator. `types.path` diff --git a/nixos/modules/config/nix.nix b/nixos/modules/config/nix.nix index cee4f54db0cb5..2769d8b25ef6f 100644 --- a/nixos/modules/config/nix.nix +++ b/nixos/modules/config/nix.nix @@ -109,13 +109,17 @@ let if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then '' echo "Ignoring validation for cross-compilation" '' - else '' + else + let + showCommand = if isNixAtLeast "2.20pre" then "config show" else "show-config"; + in + '' echo "Validating generated nix.conf" ln -s $out ./nix.conf set -e set +o pipefail NIX_CONF_DIR=$PWD \ - ${cfg.package}/bin/nix show-config ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \ + ${cfg.package}/bin/nix ${showCommand} ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \ ${optionalString (isNixAtLeast "2.4pre") "--option experimental-features nix-command"} \ |& sed -e 's/^warning:/error:/' \ | (! grep '${if cfg.checkAllErrors then "^error:" else "^error: unknown setting"}') diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 39aac9fb821bd..2aed620eb154c 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/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix index 6f58e848b38ae..a97c8c418c865 100644 --- a/nixos/modules/hardware/all-firmware.nix +++ b/nixos/modules/hardware/all-firmware.nix @@ -48,10 +48,7 @@ in { alsa-firmware sof-firmware libreelec-dvb-firmware - ] ++ optional pkgs.stdenv.hostPlatform.isAarch raspberrypiWirelessFirmware - ++ optionals (versionOlder config.boot.kernelPackages.kernel.version "4.13") [ - rtl8723bs-firmware - ]; + ] ++ optional pkgs.stdenv.hostPlatform.isAarch raspberrypiWirelessFirmware; }) (mkIf cfg.enableAllFirmware { assertions = [{ diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index fe2e0aed24842..0cc80f2906b3e 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -677,6 +677,7 @@ ./services/misc/gollum.nix ./services/misc/gpsd.nix ./services/misc/greenclip.nix + ./services/misc/guix ./services/misc/headphones.nix ./services/misc/heisenbridge.nix ./services/misc/homepage-dashboard.nix diff --git a/nixos/modules/programs/git.nix b/nixos/modules/programs/git.nix index 4e271a8c134b2..710dee349d590 100644 --- a/nixos/modules/programs/git.nix +++ b/nixos/modules/programs/git.nix @@ -58,6 +58,10 @@ in ''; }; + prompt = { + enable = mkEnableOption "automatically sourcing git-prompt.sh. This does not change $PS1; it simply provides relevant utility functions"; + }; + lfs = { enable = mkEnableOption (lib.mdDoc "git-lfs"); @@ -89,6 +93,11 @@ in }; }; }) + (mkIf (cfg.enable && cfg.prompt.enable) { + environment.interactiveShellInit = '' + source ${cfg.package}/share/bash-completion/completions/git-prompt.sh + ''; + }) ]; meta.maintainers = with maintainers; [ figsoda ]; diff --git a/nixos/modules/programs/mininet.nix b/nixos/modules/programs/mininet.nix index 01ffd811e70e2..3568736854d8e 100644 --- a/nixos/modules/programs/mininet.nix +++ b/nixos/modules/programs/mininet.nix @@ -6,39 +6,6 @@ with lib; let cfg = config.programs.mininet; - - telnet = pkgs.runCommand "inetutils-telnet" - { } - '' - mkdir -p $out/bin - ln -s ${pkgs.inetutils}/bin/telnet $out/bin - ''; - - generatedPath = with pkgs; makeSearchPath "bin" [ - iperf - ethtool - iproute2 - socat - # mn errors out without a telnet binary - # pkgs.inetutils brings an undesired ifconfig into PATH see #43105 - nettools - telnet - ]; - - pyEnv = pkgs.python3.withPackages (ps: [ ps.mininet-python ]); - - mnexecWrapped = pkgs.runCommand "mnexec-wrapper" - { nativeBuildInputs = [ pkgs.makeWrapper pkgs.python3Packages.wrapPython ]; } - '' - makeWrapper ${pkgs.mininet}/bin/mnexec \ - $out/bin/mnexec \ - --prefix PATH : "${generatedPath}" - - makeWrapper ${pyEnv}/bin/mn \ - $out/bin/mn \ - --prefix PYTHONPATH : "${pyEnv}/${pyEnv.sitePackages}" \ - --prefix PATH : "${generatedPath}" - ''; in { options.programs.mininet.enable = mkEnableOption (lib.mdDoc "Mininet"); @@ -47,6 +14,6 @@ in virtualisation.vswitch.enable = true; - environment.systemPackages = [ mnexecWrapped ]; + environment.systemPackages = [ pkgs.mininet ]; }; } diff --git a/nixos/modules/programs/wayland/river.nix b/nixos/modules/programs/wayland/river.nix index 71232a7d2618c..84ee281f6004d 100644 --- a/nixos/modules/programs/wayland/river.nix +++ b/nixos/modules/programs/wayland/river.nix @@ -51,6 +51,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/audio/wyoming/faster-whisper.nix b/nixos/modules/services/audio/wyoming/faster-whisper.nix index 2d56acdc1b4cd..8379f50f1905f 100644 --- a/nixos/modules/services/audio/wyoming/faster-whisper.nix +++ b/nixos/modules/services/audio/wyoming/faster-whisper.nix @@ -121,6 +121,7 @@ in in mkIf (cfg.servers != {}) { systemd.services = mapAttrs' (server: options: nameValuePair "wyoming-faster-whisper-${server}" { + inherit (options) enable; description = "Wyoming faster-whisper server instance ${server}"; after = [ "network-online.target" diff --git a/nixos/modules/services/audio/wyoming/piper.nix b/nixos/modules/services/audio/wyoming/piper.nix index ed50bd9f48e95..4944c958a2da7 100644 --- a/nixos/modules/services/audio/wyoming/piper.nix +++ b/nixos/modules/services/audio/wyoming/piper.nix @@ -116,6 +116,7 @@ in in mkIf (cfg.servers != {}) { systemd.services = mapAttrs' (server: options: nameValuePair "wyoming-piper-${server}" { + inherit (options) enable; description = "Wyoming Piper server instance ${server}"; after = [ "network-online.target" diff --git a/nixos/modules/services/backup/btrbk.nix b/nixos/modules/services/backup/btrbk.nix index 1e90ef54d33f9..3cbbf0f1bd5c0 100644 --- a/nixos/modules/services/backup/btrbk.nix +++ b/nixos/modules/services/backup/btrbk.nix @@ -13,7 +13,7 @@ let mkIf mkOption optionalString - sort + sortOn types ; @@ -37,7 +37,7 @@ let genConfig = set: let pairs = mapAttrsToList (name: value: { inherit name value; }) set; - sortedPairs = sort (a: b: prioOf a < prioOf b) pairs; + sortedPairs = sortOn prioOf pairs; in concatMap genPair sortedPairs; genSection = sec: secName: value: diff --git a/nixos/modules/services/backup/postgresql-backup.nix b/nixos/modules/services/backup/postgresql-backup.nix index d3c6f3104fc54..82067d8ade34d 100644 --- a/nixos/modules/services/backup/postgresql-backup.nix +++ b/nixos/modules/services/backup/postgresql-backup.nix @@ -17,8 +17,8 @@ let compressCmd = getAttr cfg.compression { "none" = "cat"; - "gzip" = "${pkgs.gzip}/bin/gzip -c -${toString cfg.compressionLevel}"; - "zstd" = "${pkgs.zstd}/bin/zstd -c -${toString cfg.compressionLevel}"; + "gzip" = "${pkgs.gzip}/bin/gzip -c -${toString cfg.compressionLevel} --rsyncable"; + "zstd" = "${pkgs.zstd}/bin/zstd -c -${toString cfg.compressionLevel} --rsyncable"; }; mkSqlPath = prefix: suffix: "${cfg.location}/${db}${prefix}.sql${suffix}"; @@ -178,4 +178,5 @@ in { }) ]; + meta.maintainers = with lib.maintainers; [ Scrumplex ]; } diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix index 87595f39796d9..d7cd6a29c52c6 100644 --- a/nixos/modules/services/backup/restic.nix +++ b/nixos/modules/services/backup/restic.nix @@ -391,10 +391,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/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix index e4d54b0cb0f49..11f30e6e49063 100644 --- a/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -241,6 +241,7 @@ in { serviceConfig = { User = cfg.user; + StateDirectory = mkIf (hasPrefix "/var/lib/jenkins" cfg.home) "jenkins"; }; }; }; diff --git a/nixos/modules/services/display-managers/greetd.nix b/nixos/modules/services/display-managers/greetd.nix index 89cb81f3a78f6..926ec1a963ba1 100644 --- a/nixos/modules/services/display-managers/greetd.nix +++ b/nixos/modules/services/display-managers/greetd.nix @@ -4,7 +4,7 @@ with lib; let cfg = config.services.greetd; tty = "tty${toString cfg.vt}"; - settingsFormat = pkgs.formats.toml {}; + settingsFormat = pkgs.formats.toml { }; in { options.services.greetd = { @@ -32,7 +32,7 @@ in ''; }; - vt = mkOption { + vt = mkOption { type = types.int; default = 1; description = lib.mdDoc '' @@ -102,12 +102,18 @@ in systemd.defaultUnit = "graphical.target"; + # Create directories potentially required by supported greeters + # See https://github.com/NixOS/nixpkgs/issues/248323 + systemd.tmpfiles.rules = [ + "d '/var/cache/tuigreet' - greeter greeter - -" + ]; + users.users.greeter = { isSystemUser = true; group = "greeter"; }; - users.groups.greeter = {}; + users.groups.greeter = { }; }; meta.maintainers = with maintainers; [ queezle ]; diff --git a/nixos/modules/services/games/teeworlds.nix b/nixos/modules/services/games/teeworlds.nix index ffef440330c4e..bd0df1ffca578 100644 --- a/nixos/modules/services/games/teeworlds.nix +++ b/nixos/modules/services/games/teeworlds.nix @@ -100,7 +100,7 @@ in serviceConfig = { DynamicUser = true; - ExecStart = "${pkgs.teeworlds}/bin/teeworlds_srv -f ${teeworldsConf}"; + ExecStart = "${pkgs.teeworlds-server}/bin/teeworlds_srv -f ${teeworldsConf}"; # Hardening CapabilityBoundingSet = false; diff --git a/nixos/modules/services/home-automation/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix index 54fd3e17292f6..f2cda9e83575a 100644 --- a/nixos/modules/services/home-automation/home-assistant.nix +++ b/nixos/modules/services/home-automation/home-assistant.nix @@ -11,14 +11,12 @@ let # options shown in settings. # We post-process the result to add support for YAML functions, like secrets or includes, see e.g. # https://www.home-assistant.io/docs/configuration/secrets/ - filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) cfg.config or {}; + filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) (lib.recursiveUpdate customLovelaceModulesResources (cfg.config or {})); configFile = pkgs.runCommandLocal "configuration.yaml" { } '' cp ${format.generate "configuration.yaml" filteredConfig} $out sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out ''; - lovelaceConfig = if (cfg.lovelaceConfig == null) then {} - else (lib.recursiveUpdate customLovelaceModulesResources cfg.lovelaceConfig); - lovelaceConfigFile = format.generate "ui-lovelace.yaml" lovelaceConfig; + lovelaceConfigFile = format.generate "ui-lovelace.yaml" cfg.lovelaceConfig; # Components advertised by the home-assistant package availableComponents = cfg.package.availableComponents; @@ -77,7 +75,7 @@ let # Create parts of the lovelace config that reference lovelave modules as resources customLovelaceModulesResources = { lovelace.resources = map (card: { - url = "/local/nixos-lovelace-modules/${card.entrypoint or card.pname}.js?${card.version}"; + url = "/local/nixos-lovelace-modules/${card.entrypoint or (card.pname + ".js")}?${card.version}"; type = "module"; }) cfg.customLovelaceModules; }; @@ -159,7 +157,7 @@ in { default = []; example = literalExpression '' with pkgs.home-assistant-custom-components; [ - prometheus-sensor + prometheus_sensor ]; ''; description = lib.mdDoc '' @@ -455,10 +453,10 @@ in { ln -s /etc/home-assistant/configuration.yaml "${cfg.configDir}/configuration.yaml" ''; copyLovelaceConfig = if cfg.lovelaceConfigWritable then '' + rm -f "${cfg.configDir}/ui-lovelace.yaml" cp --no-preserve=mode ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml" '' else '' - rm -f "${cfg.configDir}/ui-lovelace.yaml" - ln -s /etc/home-assistant/ui-lovelace.yaml "${cfg.configDir}/ui-lovelace.yaml" + ln -fs /etc/home-assistant/ui-lovelace.yaml "${cfg.configDir}/ui-lovelace.yaml" ''; copyCustomLovelaceModules = if cfg.customLovelaceModules != [] then '' mkdir -p "${cfg.configDir}/www" @@ -470,8 +468,8 @@ in { mkdir -p "${cfg.configDir}/custom_components" # remove components symlinked in from below the /nix/store - components="$(find "${cfg.configDir}/custom_components" -maxdepth 1 -type l)" - for component in "$components"; do + readarray -d "" components < <(find "${cfg.configDir}/custom_components" -maxdepth 1 -type l -print0) + for component in "''${components[@]}"; do if [[ "$(readlink "$component")" =~ ^${escapeShellArg builtins.storeDir} ]]; then rm "$component" fi diff --git a/nixos/modules/services/matrix/synapse.md b/nixos/modules/services/matrix/synapse.md index 58be24204fcfe..f270be8c8d781 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 9cc769c2d0db7..50019d2a25cb5 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 new file mode 100644 index 0000000000000..2bfa3b77971f4 --- /dev/null +++ b/nixos/modules/services/misc/guix/default.nix @@ -0,0 +1,387 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.services.guix; + + package = cfg.package.override { inherit (cfg) stateDir storeDir; }; + + guixBuildUser = id: { + name = "guixbuilder${toString id}"; + group = cfg.group; + extraGroups = [ cfg.group ]; + createHome = false; + description = "Guix build user ${toString id}"; + isSystemUser = true; + }; + + guixBuildUsers = numberOfUsers: + builtins.listToAttrs (map + (user: { + name = user.name; + value = user; + }) + (builtins.genList guixBuildUser numberOfUsers)); + + # A set of Guix user profiles to be linked at activation. + guixUserProfiles = { + # The current Guix profile that is created through `guix pull`. + "current-guix" = "\${XDG_CONFIG_HOME}/guix/current"; + + # The default Guix profile similar to $HOME/.nix-profile from Nix. + "guix-profile" = "$HOME/.guix-profile"; + }; + + # All of the Guix profiles to be used. + guixProfiles = lib.attrValues guixUserProfiles; + + serviceEnv = { + GUIX_LOCPATH = "${cfg.stateDir}/guix/profiles/per-user/root/guix-profile/lib/locale"; + LC_ALL = "C.UTF-8"; + }; +in +{ + meta.maintainers = with lib.maintainers; [ foo-dogsquared ]; + + options.services.guix = with lib; { + enable = mkEnableOption "Guix build daemon service"; + + group = mkOption { + type = types.str; + default = "guixbuild"; + example = "guixbuild"; + description = '' + The group of the Guix build user pool. + ''; + }; + + nrBuildUsers = mkOption { + type = types.ints.unsigned; + description = '' + Number of Guix build users to be used in the build pool. + ''; + default = 10; + example = 20; + }; + + extraArgs = mkOption { + type = with types; listOf str; + default = [ ]; + example = [ "--max-jobs=4" "--debug" ]; + description = '' + Extra flags to pass to the Guix daemon service. + ''; + }; + + package = mkPackageOption pkgs "guix" { + extraDescription = '' + It should contain {command}`guix-daemon` and {command}`guix` + executable. + ''; + }; + + storeDir = mkOption { + type = types.path; + default = "/gnu/store"; + description = '' + The store directory where the Guix service will serve to/from. Take + note Guix cannot take advantage of substitutes if you set it something + other than {file}`/gnu/store` since most of the cached builds are + assumed to be in there. + + ::: {.warning} + This will also recompile all packages because the normal cache no + longer applies. + ::: + ''; + }; + + stateDir = mkOption { + type = types.path; + default = "/var"; + description = '' + The state directory where Guix service will store its data such as its + user-specific profiles, cache, and state files. + + ::: {.warning} + Changing it to something other than the default will rebuild the + package. + ::: + ''; + example = "/gnu/var"; + }; + + publish = { + enable = mkEnableOption "substitute server for your Guix store directory"; + + generateKeyPair = mkOption { + type = types.bool; + description = '' + Whether to generate signing keys in {file}`/etc/guix` which are + required to initialize a substitute server. Otherwise, + `--public-key=$FILE` and `--private-key=$FILE` can be passed in + {option}`services.guix.publish.extraArgs`. + ''; + default = true; + example = false; + }; + + port = mkOption { + type = types.port; + default = 8181; + example = 8200; + description = '' + Port of the substitute server to listen on. + ''; + }; + + user = mkOption { + type = types.str; + default = "guix-publish"; + description = '' + Name of the user to change once the server is up. + ''; + }; + + extraArgs = mkOption { + type = with types; listOf str; + description = '' + Extra flags to pass to the substitute server. + ''; + default = []; + example = [ + "--compression=zstd:6" + "--discover=no" + ]; + }; + }; + + gc = { + enable = mkEnableOption "automatic garbage collection service for Guix"; + + extraArgs = mkOption { + type = with types; listOf str; + default = [ ]; + description = '' + List of arguments to be passed to {command}`guix gc`. + + When given no option, it will try to collect all garbage which is + often inconvenient so it is recommended to set [some + options](https://guix.gnu.org/en/manual/en/html_node/Invoking-guix-gc.html). + ''; + example = [ + "--delete-generations=1m" + "--free-space=10G" + "--optimize" + ]; + }; + + dates = lib.mkOption { + type = types.str; + default = "03:15"; + example = "weekly"; + description = '' + How often the garbage collection occurs. This takes the time format + from {manpage}`systemd.time(7)`. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + environment.systemPackages = [ package ]; + + users.users = guixBuildUsers cfg.nrBuildUsers; + users.groups.${cfg.group} = { }; + + # Guix uses Avahi (through guile-avahi) both for the auto-discovering and + # advertising substitute servers in the local network. + services.avahi.enable = lib.mkDefault true; + services.avahi.publish.enable = lib.mkDefault true; + services.avahi.publish.userServices = lib.mkDefault true; + + # It's similar to Nix daemon so there's no question whether or not this + # should be sandboxed. + systemd.services.guix-daemon = { + environment = serviceEnv; + script = '' + ${lib.getExe' package "guix-daemon"} \ + --build-users-group=${cfg.group} \ + ${lib.escapeShellArgs cfg.extraArgs} + ''; + serviceConfig = { + OOMPolicy = "continue"; + RemainAfterExit = "yes"; + Restart = "always"; + TasksMax = 8192; + }; + unitConfig.RequiresMountsFor = [ + cfg.storeDir + cfg.stateDir + ]; + wantedBy = [ "multi-user.target" ]; + }; + + # This is based from Nix daemon socket unit from upstream Nix package. + # Guix build daemon has support for systemd-style socket activation. + systemd.sockets.guix-daemon = { + description = "Guix daemon socket"; + before = [ "multi-user.target" ]; + listenStreams = [ "${cfg.stateDir}/guix/daemon-socket/socket" ]; + unitConfig.RequiresMountsFor = [ cfg.storeDir cfg.stateDir ]; + wantedBy = [ "sockets.target" ]; + }; + + systemd.mounts = [{ + description = "Guix read-only store directory"; + before = [ "guix-daemon.service" ]; + what = cfg.storeDir; + where = cfg.storeDir; + type = "none"; + options = "bind,ro"; + + unitConfig.DefaultDependencies = false; + wantedBy = [ "guix-daemon.service" ]; + }]; + + # Make transferring files from one store to another easier with the usual + # case being of most substitutes from the official Guix CI instance. + system.activationScripts.guix-authorize-keys = '' + for official_server_keys in ${package}/share/guix/*.pub; do + ${lib.getExe' package "guix"} archive --authorize < $official_server_keys + done + ''; + + # Link the usual Guix profiles to the home directory. This is useful in + # ephemeral setups where only certain part of the filesystem is + # persistent (e.g., "Erase my darlings"-type of setup). + system.userActivationScripts.guix-activate-user-profiles.text = let + linkProfileToPath = acc: profile: location: let + guixProfile = "${cfg.stateDir}/guix/profiles/per-user/\${USER}/${profile}"; + in acc + '' + [ -d "${guixProfile}" ] && [ -L "${location}" ] || ln -sf "${guixProfile}" "${location}" + ''; + + activationScript = lib.foldlAttrs linkProfileToPath "" guixUserProfiles; + in '' + # Don't export this please! It is only expected to be used for this + # activation script and nothing else. + XDG_CONFIG_HOME=''${XDG_CONFIG_HOME:-$HOME/.config} + + # Linking the usual Guix profiles into the home directory. + ${activationScript} + ''; + + # GUIX_LOCPATH is basically LOCPATH but for Guix libc which in turn used by + # virtually every Guix-built packages. This is so that Guix-installed + # applications wouldn't use incompatible locale data and not touch its host + # system. + environment.sessionVariables.GUIX_LOCPATH = lib.makeSearchPath "lib/locale" guixProfiles; + + # What Guix profiles export is very similar to Nix profiles so it is + # acceptable to list it here. Also, it is more likely that the user would + # want to use packages explicitly installed from Guix so we're putting it + # first. + environment.profiles = lib.mkBefore guixProfiles; + } + + (lib.mkIf cfg.publish.enable { + systemd.services.guix-publish = { + description = "Guix remote store"; + environment = serviceEnv; + + # Mounts will be required by the daemon service anyways so there's no + # need add RequiresMountsFor= or something similar. + requires = [ "guix-daemon.service" ]; + after = [ "guix-daemon.service" ]; + partOf = [ "guix-daemon.service" ]; + + preStart = lib.mkIf cfg.publish.generateKeyPair '' + # Generate the keypair if it's missing. + [ -f "/etc/guix/signing-key.sec" ] && [ -f "/etc/guix/signing-key.pub" ] || \ + ${lib.getExe' package "guix"} archive --generate-key || { + rm /etc/guix/signing-key.*; + ${lib.getExe' package "guix"} archive --generate-key; + } + ''; + script = '' + ${lib.getExe' package "guix"} publish \ + --user=${cfg.publish.user} --port=${builtins.toString cfg.publish.port} \ + ${lib.escapeShellArgs cfg.publish.extraArgs} + ''; + + serviceConfig = { + Restart = "always"; + RestartSec = 10; + + ProtectClock = true; + ProtectHostname = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + SystemCallFilter = [ + "@system-service" + "@debug" + "@setuid" + ]; + + RestrictNamespaces = true; + RestrictAddressFamilies = [ + "AF_UNIX" + "AF_INET" + "AF_INET6" + ]; + + # While the permissions can be set, it is assumed to be taken by Guix + # daemon service which it has already done the setup. + ConfigurationDirectory = "guix"; + + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + CapabilityBoundingSet = [ + "CAP_NET_BIND_SERVICE" + "CAP_SETUID" + "CAP_SETGID" + ]; + }; + wantedBy = [ "multi-user.target" ]; + }; + + users.users.guix-publish = lib.mkIf (cfg.publish.user == "guix-publish") { + description = "Guix publish user"; + group = config.users.groups.guix-publish.name; + isSystemUser = true; + }; + users.groups.guix-publish = {}; + }) + + (lib.mkIf cfg.gc.enable { + # This service should be handled by root to collect all garbage by all + # users. + systemd.services.guix-gc = { + description = "Guix garbage collection"; + startAt = cfg.gc.dates; + script = '' + ${lib.getExe' package "guix"} gc ${lib.escapeShellArgs cfg.gc.extraArgs} + ''; + + serviceConfig = { + Type = "oneshot"; + + PrivateDevices = true; + PrivateNetworks = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelTunables = true; + SystemCallFilter = [ + "@default" + "@file-system" + "@basic-io" + "@system-service" + ]; + }; + }; + + systemd.timers.guix-gc.timerConfig.Persistent = true; + }) + ]); +} diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix index a38855ccd4088..822a4946ba271 100644 --- a/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixos/modules/services/monitoring/prometheus/default.nix @@ -41,12 +41,12 @@ let # This becomes the main config file for Prometheus promConfig = { global = filterValidPrometheus cfg.globalConfig; - rule_files = map (promtoolCheck "check rules" "rules") (cfg.ruleFiles ++ [ - (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules)) - ]); scrape_configs = filterValidPrometheus cfg.scrapeConfigs; remote_write = filterValidPrometheus cfg.remoteWrite; remote_read = filterValidPrometheus cfg.remoteRead; + rule_files = optionals (!(cfg.enableAgentMode)) (map (promtoolCheck "check rules" "rules") (cfg.ruleFiles ++ [ + (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules)) + ])); alerting = { inherit (cfg) alertmanagers; }; @@ -62,15 +62,20 @@ let promtoolCheck "check config ${lib.optionalString (cfg.checkConfig == "syntax-only") "--syntax-only"}" "prometheus.yml" yml; cmdlineArgs = cfg.extraFlags ++ [ - "--storage.tsdb.path=${workingDir}/data/" "--config.file=${ if cfg.enableReload then "/etc/prometheus/prometheus.yaml" else prometheusYml }" "--web.listen-address=${cfg.listenAddress}:${builtins.toString cfg.port}" - "--alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}" - ] ++ optional (cfg.webExternalUrl != null) "--web.external-url=${cfg.webExternalUrl}" + ] ++ ( + if (cfg.enableAgentMode) then [ + "--enable-feature=agent" + ] else [ + "--alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity }" + "--storage.tsdb.path=${workingDir}/data/" + ]) + ++ optional (cfg.webExternalUrl != null) "--web.external-url=${cfg.webExternalUrl}" ++ optional (cfg.retentionTime != null) "--storage.tsdb.retention.time=${cfg.retentionTime}" ++ optional (cfg.webConfigFile != null) "--web.config.file=${cfg.webConfigFile}"; @@ -1619,6 +1624,8 @@ in ''; }; + enableAgentMode = mkEnableOption (lib.mdDoc "agent mode"); + configText = mkOption { type = types.nullOr types.lines; default = null; diff --git a/nixos/modules/services/monitoring/prometheus/exporters/kea.nix b/nixos/modules/services/monitoring/prometheus/exporters/kea.nix index 8b1cd47d0a409..3abb6ff6bdf8b 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/kea.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/kea.nix @@ -15,8 +15,8 @@ in { type = types.listOf types.str; example = literalExpression '' [ - "/run/kea-dhcp4/kea-dhcp4.socket" - "/run/kea-dhcp6/kea-dhcp6.socket" + "/run/kea/kea-dhcp4.socket" + "/run/kea/kea-dhcp6.socket" ] ''; description = lib.mdDoc '' @@ -31,13 +31,15 @@ in { ]; serviceConfig = { User = "kea"; + DynamicUser = true; ExecStart = '' ${pkgs.prometheus-kea-exporter}/bin/kea-exporter \ --address ${cfg.listenAddress} \ --port ${toString cfg.port} \ ${concatStringsSep " " cfg.controlSocketPaths} ''; - SupplementaryGroups = [ "kea" ]; + RuntimeDirectory = "kea"; + RuntimeDirectoryPreserve = true; RestrictAddressFamilies = [ # Need AF_UNIX to collect data "AF_UNIX" diff --git a/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix b/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix index 4112774940139..b9ab305f7c082 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix @@ -19,7 +19,11 @@ in }; apiKeyFile = mkOption { type = types.str; - description = "File containing the API key."; + description = '' + The path to a file containing the API key. + The file is securely passed to the service by leveraging systemd credentials. + No special permissions need to be set on this file. + ''; example = "/run/secrets/sabnzbd_apikey"; }; }; @@ -30,18 +34,24 @@ in serviceOpts = let servers = lib.zipAttrs cfg.servers; - apiKeys = lib.concatStringsSep "," (builtins.map (file: "$(cat ${file})") servers.apiKeyFile); + credentials = lib.imap0 (i: v: { name = "apikey-${toString i}"; path = v; }) servers.apiKeyFile; in { + serviceConfig.LoadCredential = builtins.map ({ name, path }: "${name}:${path}") credentials; + environment = { METRICS_PORT = toString cfg.port; METRICS_ADDR = cfg.listenAddress; SABNZBD_BASEURLS = lib.concatStringsSep "," servers.baseUrl; }; - script = '' - export SABNZBD_APIKEYS="${apiKeys}" - exec ${lib.getExe pkgs.prometheus-sabnzbd-exporter} - ''; + script = + let + apiKeys = lib.concatStringsSep "," (builtins.map (cred: "$(< $CREDENTIALS_DIRECTORY/${cred.name})") credentials); + in + '' + export SABNZBD_APIKEYS="${apiKeys}" + exec ${lib.getExe pkgs.prometheus-sabnzbd-exporter} + ''; }; } diff --git a/nixos/modules/services/network-filesystems/drbd.nix b/nixos/modules/services/network-filesystems/drbd.nix index e74ed391d48e3..79a1b768b4615 100644 --- a/nixos/modules/services/network-filesystems/drbd.nix +++ b/nixos/modules/services/network-filesystems/drbd.nix @@ -55,8 +55,8 @@ let cfg = config.services.drbd; in wants = [ "systemd-udev.settle.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { - ExecStart = "${pkgs.drbd}/sbin/drbdadm up all"; - ExecStop = "${pkgs.drbd}/sbin/drbdadm down all"; + ExecStart = "${pkgs.drbd}/bin/drbdadm up all"; + ExecStop = "${pkgs.drbd}/bin/drbdadm down all"; }; }; }; diff --git a/nixos/modules/services/network-filesystems/kubo.nix b/nixos/modules/services/network-filesystems/kubo.nix index bc746bed31f22..b6a81fedcfba3 100644 --- a/nixos/modules/services/network-filesystems/kubo.nix +++ b/nixos/modules/services/network-filesystems/kubo.nix @@ -366,6 +366,8 @@ in Group = cfg.group; StateDirectory = ""; ReadWritePaths = optionals (!cfg.autoMount) [ "" cfg.dataDir ]; + # Make sure the socket units are started before ipfs.service + Sockets = [ "ipfs-gateway.socket" "ipfs-api.socket" ]; } // optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; }; } // optionalAttrs (!cfg.startWhenNeeded) { wantedBy = [ "default.target" ]; diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix index 3feafc3bb3bd1..72dffac9365b6 100644 --- a/nixos/modules/services/networking/ejabberd.nix +++ b/nixos/modules/services/networking/ejabberd.nix @@ -125,6 +125,12 @@ in { if [ -z "$(ls -A '${cfg.spoolDir}')" ]; then touch "${cfg.spoolDir}/.firstRun" fi + + if ! test -e ${cfg.spoolDir}/.erlang.cookie; then + touch ${cfg.spoolDir}/.erlang.cookie + chmod 600 ${cfg.spoolDir}/.erlang.cookie + dd if=/dev/random bs=16 count=1 | base64 > ${cfg.spoolDir}/.erlang.cookie + fi ''; postStart = '' diff --git a/nixos/modules/services/networking/kea.nix b/nixos/modules/services/networking/kea.nix index 2f922a026a3a9..5ca705976c413 100644 --- a/nixos/modules/services/networking/kea.nix +++ b/nixos/modules/services/networking/kea.nix @@ -254,6 +254,8 @@ in DynamicUser = true; User = "kea"; ConfigurationDirectory = "kea"; + RuntimeDirectory = "kea"; + RuntimeDirectoryPreserve = true; StateDirectory = "kea"; UMask = "0077"; }; @@ -288,8 +290,8 @@ in ]; environment = { - KEA_PIDFILE_DIR = "/run/kea-ctrl-agent"; - KEA_LOCKFILE_DIR = "/run/kea-ctrl-agent"; + KEA_PIDFILE_DIR = "/run/kea"; + KEA_LOCKFILE_DIR = "/run/kea"; }; restartTriggers = [ @@ -300,7 +302,6 @@ in ExecStart = "${package}/bin/kea-ctrl-agent -c /etc/kea/ctrl-agent.conf ${lib.escapeShellArgs cfg.ctrl-agent.extraArgs}"; KillMode = "process"; Restart = "on-failure"; - RuntimeDirectory = "kea-ctrl-agent"; } // commonServiceConfig; }; }) @@ -329,8 +330,8 @@ in ]; environment = { - KEA_PIDFILE_DIR = "/run/kea-dhcp4"; - KEA_LOCKFILE_DIR = "/run/kea-dhcp4"; + KEA_PIDFILE_DIR = "/run/kea"; + KEA_LOCKFILE_DIR = "/run/kea"; }; restartTriggers = [ @@ -348,7 +349,6 @@ in "CAP_NET_BIND_SERVICE" "CAP_NET_RAW" ]; - RuntimeDirectory = "kea-dhcp4"; } // commonServiceConfig; }; }) @@ -377,8 +377,8 @@ in ]; environment = { - KEA_PIDFILE_DIR = "/run/kea-dhcp6"; - KEA_LOCKFILE_DIR = "/run/kea-dhcp6"; + KEA_PIDFILE_DIR = "/run/kea"; + KEA_LOCKFILE_DIR = "/run/kea"; }; restartTriggers = [ @@ -394,7 +394,6 @@ in CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; - RuntimeDirectory = "kea-dhcp6"; } // commonServiceConfig; }; }) @@ -423,8 +422,8 @@ in ]; environment = { - KEA_PIDFILE_DIR = "/run/kea-dhcp-ddns"; - KEA_LOCKFILE_DIR = "/run/kea-dhcp-ddns"; + KEA_PIDFILE_DIR = "/run/kea"; + KEA_LOCKFILE_DIR = "/run/kea"; }; restartTriggers = [ @@ -439,7 +438,6 @@ in CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; - RuntimeDirectory = "kea-dhcp-ddns"; } // commonServiceConfig; }; }) diff --git a/nixos/modules/services/networking/nebula.nix b/nixos/modules/services/networking/nebula.nix index e1a8c6740f57e..38e657d04437c 100644 --- a/nixos/modules/services/networking/nebula.nix +++ b/nixos/modules/services/networking/nebula.nix @@ -201,7 +201,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/nix-serve.nix b/nixos/modules/services/networking/nix-serve.nix index 8c4352bc95e82..86bb603e12719 100644 --- a/nixos/modules/services/networking/nix-serve.nix +++ b/nixos/modules/services/networking/nix-serve.nix @@ -67,7 +67,9 @@ in }; config = mkIf cfg.enable { - nix.settings.extra-allowed-users = [ "nix-serve" ]; + nix.settings = lib.optionalAttrs (lib.versionAtLeast config.nix.package.version "2.4") { + extra-allowed-users = [ "nix-serve" ]; + }; systemd.services.nix-serve = { description = "nix-serve binary cache server"; diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index 6d9af6141f12c..0a493f0b2b95f 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 = []; @@ -667,7 +676,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/teamspeak3.nix b/nixos/modules/services/networking/teamspeak3.nix index f09ef1a959ed4..ff41539a6d9b7 100644 --- a/nixos/modules/services/networking/teamspeak3.nix +++ b/nixos/modules/services/networking/teamspeak3.nix @@ -50,7 +50,7 @@ in }; defaultVoicePort = mkOption { - type = types.int; + type = types.port; default = 9987; description = lib.mdDoc '' Default UDP port for clients to connect to virtual servers - used for first virtual server, subsequent ones will open on incrementing port numbers by default. @@ -67,7 +67,7 @@ in }; fileTransferPort = mkOption { - type = types.int; + type = types.port; default = 30033; description = lib.mdDoc '' TCP port opened for file transfers. @@ -84,10 +84,26 @@ in }; queryPort = mkOption { - type = types.int; + type = types.port; default = 10011; description = lib.mdDoc '' - TCP port opened for ServerQuery connections. + TCP port opened for ServerQuery connections using the raw telnet protocol. + ''; + }; + + querySshPort = mkOption { + type = types.port; + default = 10022; + description = lib.mdDoc '' + TCP port opened for ServerQuery connections using the SSH protocol. + ''; + }; + + queryHttpPort = mkOption { + type = types.port; + default = 10080; + description = lib.mdDoc '' + TCP port opened for ServerQuery connections using the HTTP protocol. ''; }; @@ -128,7 +144,9 @@ in ]; networking.firewall = mkIf cfg.openFirewall { - allowedTCPPorts = [ cfg.fileTransferPort ] ++ optionals (cfg.openFirewallServerQuery) [ cfg.queryPort (cfg.queryPort + 11) ]; + allowedTCPPorts = [ cfg.fileTransferPort ] ++ (map (port: + mkIf cfg.openFirewallServerQuery port + ) [cfg.queryPort cfg.querySshPort cfg.queryHttpPort]); # subsequent vServers will use the incremented voice port, let's just open the next 10 allowedUDPPortRanges = [ { from = cfg.defaultVoicePort; to = cfg.defaultVoicePort + 10; } ]; }; @@ -141,13 +159,19 @@ in serviceConfig = { ExecStart = '' ${ts3}/bin/ts3server \ - dbsqlpath=${ts3}/lib/teamspeak/sql/ logpath=${cfg.logPath} \ - ${optionalString (cfg.voiceIP != null) "voice_ip=${cfg.voiceIP}"} \ + dbsqlpath=${ts3}/lib/teamspeak/sql/ \ + logpath=${cfg.logPath} \ + license_accepted=1 \ default_voice_port=${toString cfg.defaultVoicePort} \ - ${optionalString (cfg.fileTransferIP != null) "filetransfer_ip=${cfg.fileTransferIP}"} \ filetransfer_port=${toString cfg.fileTransferPort} \ + query_port=${toString cfg.queryPort} \ + query_ssh_port=${toString cfg.querySshPort} \ + query_http_port=${toString cfg.queryHttpPort} \ + ${optionalString (cfg.voiceIP != null) "voice_ip=${cfg.voiceIP}"} \ + ${optionalString (cfg.fileTransferIP != null) "filetransfer_ip=${cfg.fileTransferIP}"} \ ${optionalString (cfg.queryIP != null) "query_ip=${cfg.queryIP}"} \ - query_port=${toString cfg.queryPort} license_accepted=1 + ${optionalString (cfg.queryIP != null) "query_ssh_ip=${cfg.queryIP}"} \ + ${optionalString (cfg.queryIP != null) "query_http_ip=${cfg.queryIP}"} \ ''; WorkingDirectory = cfg.dataDir; User = user; diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix index 5efb9334ea03e..06f1d6c5de354 100644 --- a/nixos/modules/services/torrent/transmission.nix +++ b/nixos/modules/services/torrent/transmission.nix @@ -333,10 +333,10 @@ in cfg.settings.watch-dir; StateDirectory = [ "transmission" - "transmission/.config/transmission-daemon" - "transmission/.incomplete" - "transmission/Downloads" - "transmission/watch-dir" + "transmission/${settingsDir}" + "transmission/${incompleteDir}" + "transmission/${downloadsDir}" + "transmission/${watchDir}" ]; StateDirectoryMode = mkDefault 750; # The following options are only for optimizing: diff --git a/nixos/modules/services/video/frigate.nix b/nixos/modules/services/video/frigate.nix index 8db2bfae80ac0..17c8d59c30958 100644 --- a/nixos/modules/services/video/frigate.nix +++ b/nixos/modules/services/video/frigate.nix @@ -358,6 +358,7 @@ in ]; serviceConfig = { ExecStart = "${cfg.package.python.interpreter} -m frigate"; + Restart = "on-failure"; User = "frigate"; Group = "frigate"; diff --git a/nixos/modules/services/web-apps/keycloak.nix b/nixos/modules/services/web-apps/keycloak.nix index a7e4fab8ea287..c90ee78a3e04b 100644 --- a/nixos/modules/services/web-apps/keycloak.nix +++ b/nixos/modules/services/web-apps/keycloak.nix @@ -24,7 +24,6 @@ let maintainers catAttrs collect - splitString hasPrefix ; @@ -335,7 +334,8 @@ in }; hostname = mkOption { - type = str; + type = nullOr str; + default = null; example = "keycloak.example.com"; description = lib.mdDoc '' The hostname part of the public URL used as base for @@ -457,7 +457,7 @@ in keycloakConfig = lib.generators.toKeyValue { mkKeyValue = lib.flip lib.generators.mkKeyValueDefault "=" { - mkValueString = v: with builtins; + mkValueString = v: if isInt v then toString v else if isString v then v else if true == v then "true" @@ -486,6 +486,14 @@ in assertion = createLocalPostgreSQL -> config.services.postgresql.settings.standard_conforming_strings or true; message = "Setting up a local PostgreSQL db for Keycloak requires `standard_conforming_strings` turned on to work reliably"; } + { + assertion = cfg.settings.hostname != null || cfg.settings.hostname-url or null != null; + message = "Setting the Keycloak hostname is required, see `services.keycloak.settings.hostname`"; + } + { + assertion = !(cfg.settings.hostname != null && cfg.settings.hostname-url or null != null); + message = "`services.keycloak.settings.hostname` and `services.keycloak.settings.hostname-url` are mutually exclusive"; + } ]; environment.systemPackages = [ keycloakBuild ]; diff --git a/nixos/modules/services/web-apps/mastodon.nix b/nixos/modules/services/web-apps/mastodon.nix index 7b00ce35eb1a7..40219edcd4470 100644 --- a/nixos/modules/services/web-apps/mastodon.nix +++ b/nixos/modules/services/web-apps/mastodon.nix @@ -711,31 +711,28 @@ in { systemd.services.mastodon-init-db = lib.mkIf cfg.automaticMigrations { script = lib.optionalString (!databaseActuallyCreateLocally) '' umask 077 - - export PGPASSFILE - PGPASSFILE=$(mktemp) - cat > $PGPASSFILE <<EOF - ${cfg.database.host}:${toString cfg.database.port}:${cfg.database.name}:${cfg.database.user}:$(cat ${cfg.database.passwordFile}) - EOF - + export PGPASSWORD="$(cat '${cfg.database.passwordFile}')" '' + '' - if [ `psql ${cfg.database.name} -c \ + if [ `psql -c \ "select count(*) from pg_class c \ join pg_namespace s on s.oid = c.relnamespace \ where s.nspname not in ('pg_catalog', 'pg_toast', 'information_schema') \ and s.nspname not like 'pg_temp%';" | sed -n 3p` -eq 0 ]; then + echo "Seeding database" SAFETY_ASSURED=1 rails db:schema:load rails db:seed else + echo "Migrating database (this might be a noop)" rails db:migrate fi '' + lib.optionalString (!databaseActuallyCreateLocally) '' - rm $PGPASSFILE - unset PGPASSFILE + unset PGPASSWORD ''; path = [ cfg.package pkgs.postgresql ]; environment = env // lib.optionalAttrs (!databaseActuallyCreateLocally) { PGHOST = cfg.database.host; + PGPORT = toString cfg.database.port; + PGDATABASE = cfg.database.name; PGUSER = cfg.database.user; }; serviceConfig = { diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index d3d318304ee95..380923758161f 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -28,6 +28,7 @@ let phpPackage = cfg.phpPackage.buildEnv { extensions = { enabled, all }: (with all; enabled + ++ [ bz2 intl sodium ] # recommended ++ optional cfg.enableImagemagick imagick # Optionally enabled depending on caching settings ++ optional cfg.caching.apcu apcu @@ -188,7 +189,7 @@ in { package = mkOption { type = types.package; description = lib.mdDoc "Which package to use for the Nextcloud instance."; - relatedPackages = [ "nextcloud26" "nextcloud27" ]; + relatedPackages = [ "nextcloud26" "nextcloud27" "nextcloud28" ]; }; phpPackage = mkOption { type = types.package; @@ -1134,10 +1135,13 @@ in { fastcgi_read_timeout ${builtins.toString cfg.fastcgiTimeout}s; ''; }; - "~ \\.(?:css|js|mjs|svg|gif|png|jpg|jpeg|ico|wasm|tflite|map|html|ttf|bcmap|mp4|webm)$".extraConfig = '' + "~ \\.(?:css|js|mjs|svg|gif|png|jpg|jpeg|ico|wasm|tflite|map|html|ttf|bcmap|mp4|webm|ogg|flac)$".extraConfig = '' try_files $uri /index.php$request_uri; expires 6M; access_log off; + location ~ \.mjs$ { + default_type text/javascript; + } location ~ \.wasm$ { default_type application/wasm; } diff --git a/nixos/modules/services/web-apps/wordpress.nix b/nixos/modules/services/web-apps/wordpress.nix index 5d2e775d45216..d4c987da1144c 100644 --- a/nixos/modules/services/web-apps/wordpress.nix +++ b/nixos/modules/services/web-apps/wordpress.nix @@ -34,7 +34,7 @@ let # copy additional plugin(s), theme(s) and language(s) ${concatStringsSep "\n" (mapAttrsToList (name: theme: "cp -r ${theme} $out/share/wordpress/wp-content/themes/${name}") cfg.themes)} ${concatStringsSep "\n" (mapAttrsToList (name: plugin: "cp -r ${plugin} $out/share/wordpress/wp-content/plugins/${name}") cfg.plugins)} - ${concatMapStringsSep "\n" (language: "cp -r ${language}/* $out/share/wordpress/wp-content/languages/") cfg.languages} + ${concatMapStringsSep "\n" (language: "cp -r ${language} $out/share/wordpress/wp-content/languages/") cfg.languages} ''; }; diff --git a/nixos/modules/services/web-servers/caddy/default.nix b/nixos/modules/services/web-servers/caddy/default.nix index cc89553fbb756..d50d8e34d50b4 100644 --- a/nixos/modules/services/web-servers/caddy/default.nix +++ b/nixos/modules/services/web-servers/caddy/default.nix @@ -154,7 +154,7 @@ in default = configFile; defaultText = "A Caddyfile automatically generated by values from services.caddy.*"; example = literalExpression '' - pkgs.writeTextDir "Caddyfile" ''' + pkgs.writeText "Caddyfile" ''' example.com root * /var/www/wordpress @@ -171,9 +171,9 @@ in }; adapter = mkOption { - default = if (builtins.baseNameOf cfg.configFile) == "Caddyfile" then "caddyfile" else null; + default = if ((cfg.configFile != configFile) || (builtins.baseNameOf cfg.configFile) == "Caddyfile") then "caddyfile" else null; defaultText = literalExpression '' - if (builtins.baseNameOf cfg.configFile) == "Caddyfile" then "caddyfile" else null + if ((cfg.configFile != configFile) || (builtins.baseNameOf cfg.configFile) == "Caddyfile") then "caddyfile" else null ''; example = literalExpression "nginx"; type = with types; nullOr str; diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix index 30d6b99fcfda1..8430265eabcef 100644 --- a/nixos/modules/services/web-servers/tomcat.nix +++ b/nixos/modules/services/web-servers/tomcat.nix @@ -8,7 +8,7 @@ in { meta = { - maintainers = with lib.maintainers; [ danbst ]; + maintainers = with lib.maintainers; [ danbst anthonyroussel ]; }; ###### interface diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 33261021480f1..5ce04484710a8 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -597,6 +597,8 @@ let "DHCP" "DHCPServer" "LinkLocalAddressing" + "IPv6LinkLocalAddressGenerationMode" + "IPv6StableSecretAddress" "IPv4LLRoute" "DefaultRouteOnDevice" "LLMNR" @@ -648,6 +650,7 @@ let (assertValueOneOf "DHCP" ["yes" "no" "ipv4" "ipv6"]) (assertValueOneOf "DHCPServer" boolValues) (assertValueOneOf "LinkLocalAddressing" ["yes" "no" "ipv4" "ipv6" "fallback" "ipv4-fallback"]) + (assertValueOneOf "IPv6LinkLocalAddressGenerationMode" ["eui64" "none" "stable-privacy" "random"]) (assertValueOneOf "IPv4LLRoute" boolValues) (assertValueOneOf "DefaultRouteOnDevice" boolValues) (assertValueOneOf "LLMNR" (boolValues ++ ["resolve"])) diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix index 0e7d59b32075b..d7e8a67c4bc9d 100644 --- a/nixos/modules/system/boot/systemd/initrd.nix +++ b/nixos/modules/system/boot/systemd/initrd.nix @@ -90,8 +90,6 @@ let fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems; - needMakefs = lib.any (fs: fs.autoFormat) fileSystems; - kernel-name = config.boot.kernelPackages.kernel.name or "kernel"; modulesTree = config.system.modulesTree.override { name = kernel-name + "-modules"; }; firmware = config.hardware.firmware; @@ -430,7 +428,7 @@ in { "${cfg.package}/lib/systemd/systemd-fsck" "${cfg.package}/lib/systemd/systemd-hibernate-resume" "${cfg.package}/lib/systemd/systemd-journald" - (lib.mkIf needMakefs "${cfg.package}/lib/systemd/systemd-makefs") + "${cfg.package}/lib/systemd/systemd-makefs" "${cfg.package}/lib/systemd/systemd-modules-load" "${cfg.package}/lib/systemd/systemd-remount-fs" "${cfg.package}/lib/systemd/systemd-shutdown" diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 298add13437a0..53ffaa028038d 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -1396,6 +1396,8 @@ in "net.ipv4.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces); "net.ipv6.conf.all.disable_ipv6" = mkDefault (!cfg.enableIPv6); "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6); + # allow all users to do ICMP echo requests (ping) + "net.ipv4.ping_group_range" = mkDefault "0 2147483647"; # networkmanager falls back to "/proc/sys/net/ipv6/conf/default/use_tempaddr" "net.ipv6.conf.default.use_tempaddr" = tempaddrValues.${cfg.tempAddresses}.sysctl; } // listToAttrs (forEach interfaces diff --git a/nixos/modules/virtualisation/lxd-agent.nix b/nixos/modules/virtualisation/lxd-agent.nix index 5bcc86e3bcbe9..59df658920f0f 100644 --- a/nixos/modules/virtualisation/lxd-agent.nix +++ b/nixos/modules/virtualisation/lxd-agent.nix @@ -56,7 +56,13 @@ in { systemd.services.lxd-agent = { enable = true; wantedBy = [ "multi-user.target" ]; - path = [ pkgs.kmod pkgs.util-linux ]; + path = [ + pkgs.kmod + pkgs.util-linux + + # allow `incus exec` to find system binaries + "/run/current-system/sw" + ]; preStart = preStartScript; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 44e99203856d5..69c3ad9fe0cc5 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -354,6 +354,7 @@ in { grow-partition = runTest ./grow-partition.nix; grub = handleTest ./grub.nix {}; guacamole-server = handleTest ./guacamole-server.nix {}; + guix = handleTest ./guix {}; gvisor = handleTest ./gvisor.nix {}; hadoop = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop; }; hadoop_3_2 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop_3_2; }; diff --git a/nixos/tests/caddy.nix b/nixos/tests/caddy.nix index 5a0d3539394b6..41d8e57de4686 100644 --- a/nixos/tests/caddy.nix +++ b/nixos/tests/caddy.nix @@ -48,11 +48,19 @@ import ./make-test-python.nix ({ pkgs, ... }: { }; }; }; + specialisation.explicit-config-file.configuration = { + services.caddy.configFile = pkgs.writeText "Caddyfile" '' + localhost:80 + + respond "hello world" + ''; + }; }; }; testScript = { nodes, ... }: let + explicitConfigFile = "${nodes.webserver.system.build.toplevel}/specialisation/explicit-config-file"; justReloadSystem = "${nodes.webserver.system.build.toplevel}/specialisation/config-reload"; multipleConfigs = "${nodes.webserver.system.build.toplevel}/specialisation/multiple-configs"; rfc42Config = "${nodes.webserver.system.build.toplevel}/specialisation/rfc42"; @@ -84,5 +92,12 @@ import ./make-test-python.nix ({ pkgs, ... }: { ) webserver.wait_for_open_port(80) webserver.succeed("curl http://localhost | grep hello") + + with subtest("explicit configFile"): + webserver.succeed( + "${explicitConfigFile}/bin/switch-to-configuration test >&2" + ) + webserver.wait_for_open_port(80) + webserver.succeed("curl http://localhost | grep hello") ''; }) diff --git a/nixos/tests/fontconfig-default-fonts.nix b/nixos/tests/fontconfig-default-fonts.nix index 293dc43f91f38..209d348204b44 100644 --- a/nixos/tests/fontconfig-default-fonts.nix +++ b/nixos/tests/fontconfig-default-fonts.nix @@ -3,7 +3,6 @@ import ./make-test-python.nix ({ lib, ... }: name = "fontconfig-default-fonts"; meta.maintainers = with lib.maintainers; [ - jtojnar ]; nodes.machine = { config, pkgs, ... }: { diff --git a/nixos/tests/guix/basic.nix b/nixos/tests/guix/basic.nix new file mode 100644 index 0000000000000..9b943b8965e60 --- /dev/null +++ b/nixos/tests/guix/basic.nix @@ -0,0 +1,42 @@ +# Take note the Guix store directory is empty. Also, we're trying to prevent +# Guix from trying to downloading substitutes because of the restricted +# access (assuming it's in a sandboxed environment). +# +# So this test is what it is: a basic test while trying to use Guix as much as +# we possibly can (including the API) without triggering its download alarm. + +import ../make-test-python.nix ({ lib, pkgs, ... }: { + name = "guix-basic"; + meta.maintainers = with lib.maintainers; [ foo-dogsquared ]; + + nodes.machine = { config, ... }: { + environment.etc."guix/scripts".source = ./scripts; + services.guix = { + enable = true; + gc.enable = true; + }; + }; + + testScript = '' + import pathlib + + 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"): + machine.succeed("guix build --dry-run --verbosity=0 hello") + machine.succeed("guix show hello") + + # This is to see if the Guix API is usable and mostly working. + with subtest("Guix API scripting"): + scripts_dir = pathlib.Path("/etc/guix/scripts") + + text_msg = "Hello there, NixOS!" + text_store_file = machine.succeed(f"guix repl -- {scripts_dir}/create-file-to-store.scm '{text_msg}'") + assert machine.succeed(f"cat {text_store_file}") == text_msg + + machine.succeed(f"guix repl -- {scripts_dir}/add-existing-files-to-store.scm {scripts_dir}") + ''; +}) diff --git a/nixos/tests/guix/default.nix b/nixos/tests/guix/default.nix new file mode 100644 index 0000000000000..a017668c05a75 --- /dev/null +++ b/nixos/tests/guix/default.nix @@ -0,0 +1,8 @@ +{ system ? builtins.currentSystem +, pkgs ? import ../../.. { inherit system; } +}: + +{ + basic = import ./basic.nix { inherit system pkgs; }; + publish = import ./publish.nix { inherit system pkgs; }; +} diff --git a/nixos/tests/guix/publish.nix b/nixos/tests/guix/publish.nix new file mode 100644 index 0000000000000..6dbe8f99ebd68 --- /dev/null +++ b/nixos/tests/guix/publish.nix @@ -0,0 +1,95 @@ +# Testing out the substitute server with two machines in a local network. As a +# bonus, we'll also test a feature of the substitute server being able to +# advertise its service to the local network with Avahi. + +import ../make-test-python.nix ({ pkgs, lib, ... }: let + publishPort = 8181; + inherit (builtins) toString; +in { + name = "guix-publish"; + + meta.maintainers = with lib.maintainers; [ foo-dogsquared ]; + + nodes = let + commonConfig = { config, ... }: { + # We'll be using '--advertise' flag with the + # substitute server which requires Avahi. + services.avahi = { + enable = true; + nssmdns = true; + publish = { + enable = true; + userServices = true; + }; + }; + }; + in { + server = { config, lib, pkgs, ... }: { + imports = [ commonConfig ]; + + services.guix = { + enable = true; + publish = { + enable = true; + port = publishPort; + + generateKeyPair = true; + extraArgs = [ "--advertise" ]; + }; + }; + + networking.firewall.allowedTCPPorts = [ publishPort ]; + }; + + client = { config, lib, pkgs, ... }: { + imports = [ commonConfig ]; + + services.guix = { + enable = true; + + extraArgs = [ + # Force to only get all substitutes from the local server. We don't + # have anything in the Guix store directory and we cannot get + # anything from the official substitute servers anyways. + "--substitute-urls='http://server.local:${toString publishPort}'" + + # Enable autodiscovery of the substitute servers in the local + # network. This machine shouldn't need to import the signing key from + # the substitute server since it is automatically done anyways. + "--discover=yes" + ]; + }; + }; + }; + + testScript = '' + import pathlib + + start_all() + + scripts_dir = pathlib.Path("/etc/guix/scripts") + + for machine in machines: + machine.wait_for_unit("multi-user.target") + machine.wait_for_unit("guix-daemon.service") + machine.wait_for_unit("avahi-daemon.service") + + server.wait_for_unit("guix-publish.service") + server.wait_for_open_port(${toString publishPort}) + server.succeed("curl http://localhost:${toString publishPort}/") + + # Now it's the client turn to make use of it. + substitute_server = "http://server.local:${toString publishPort}" + client.wait_for_unit("network-online.target") + response = client.succeed(f"curl {substitute_server}") + assert "Guix Substitute Server" in response + + # Authorizing the server to be used as a substitute server. + client.succeed(f"curl -O {substitute_server}/signing-key.pub") + client.succeed("guix archive --authorize < ./signing-key.pub") + + # Since we're using the substitute server with the `--advertise` flag, we + # might as well check it. + client.succeed("avahi-browse --resolve --terminate _guix_publish._tcp | grep '_guix_publish._tcp'") + ''; +}) diff --git a/nixos/tests/guix/scripts/add-existing-files-to-store.scm b/nixos/tests/guix/scripts/add-existing-files-to-store.scm new file mode 100644 index 0000000000000..fa47320b6a511 --- /dev/null +++ b/nixos/tests/guix/scripts/add-existing-files-to-store.scm @@ -0,0 +1,52 @@ +;; A simple script that adds each file given from the command-line into the +;; store and checks them if it's the same. +(use-modules (guix) + (srfi srfi-1) + (ice-9 ftw) + (rnrs io ports)) + +;; This is based from tests/derivations.scm from Guix source code. +(define* (directory-contents dir #:optional (slurp get-bytevector-all)) + "Return an alist representing the contents of DIR" + (define prefix-len (string-length dir)) + (sort (file-system-fold (const #t) + (lambda (path stat result) + (alist-cons (string-drop path prefix-len) + (call-with-input-file path slurp) + result)) + (lambda (path stat result) result) + (lambda (path stat result) result) + (lambda (path stat result) result) + (lambda (path stat errno result) result) + '() + dir) + (lambda (e1 e2) + (string<? (car e1) (car e2))))) + +(define* (check-if-same store drv path) + "Check if the given path and its store item are the same" + (let* ((filetype (stat:type (stat drv)))) + (case filetype + ((regular) + (and (valid-path? store drv) + (equal? (call-with-input-file path get-bytevector-all) + (call-with-input-file drv get-bytevector-all)))) + ((directory) + (and (valid-path? store drv) + (equal? (directory-contents path) + (directory-contents drv)))) + (else #f)))) + +(define* (add-and-check-item-to-store store path) + "Add PATH to STORE and check if the contents are the same" + (let* ((store-item (add-to-store store + (basename path) + #t "sha256" path)) + (is-same (check-if-same store store-item path))) + (if (not is-same) + (exit 1)))) + +(with-store store + (map (lambda (path) + (add-and-check-item-to-store store (readlink* path))) + (cdr (command-line)))) diff --git a/nixos/tests/guix/scripts/create-file-to-store.scm b/nixos/tests/guix/scripts/create-file-to-store.scm new file mode 100644 index 0000000000000..467e4c4fd53f2 --- /dev/null +++ b/nixos/tests/guix/scripts/create-file-to-store.scm @@ -0,0 +1,8 @@ +;; A script that creates a store item with the given text and prints the +;; resulting store item path. +(use-modules (guix)) + +(with-store store + (display (add-text-to-store store "guix-basic-test-text" + (string-join + (cdr (command-line)))))) diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index e1588088ba198..05fb2fa1e06aa 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -43,7 +43,7 @@ in { # test loading custom components customComponents = with pkgs.home-assistant-custom-components; [ - prometheus-sensor + prometheus_sensor ]; # test loading lovelace modules @@ -182,7 +182,7 @@ in { hass.wait_until_succeeds("journalctl -u home-assistant.service | grep -q 'We found a custom integration prometheus_sensor which has not been tested by Home Assistant'") with subtest("Check that lovelace modules are referenced and fetchable"): - hass.succeed("grep -q 'mini-graph-card-bundle.js' '${configDir}/ui-lovelace.yaml'") + hass.succeed("grep -q 'mini-graph-card-bundle.js' '${configDir}/configuration.yaml'") hass.succeed("curl --fail http://localhost:8123/local/nixos-lovelace-modules/mini-graph-card-bundle.js") with subtest("Check that optional dependencies are in the PYTHONPATH"): diff --git a/nixos/tests/incus/virtual-machine.nix b/nixos/tests/incus/virtual-machine.nix index bfa116679d43b..b7d130c8feb17 100644 --- a/nixos/tests/incus/virtual-machine.nix +++ b/nixos/tests/incus/virtual-machine.nix @@ -51,5 +51,8 @@ in with subtest("lxd-agent is started"): machine.succeed("incus exec ${instance-name} systemctl is-active lxd-agent") + + with subtest("lxd-agent has a valid path"): + machine.succeed("incus exec ${instance-name} -- bash -c 'true'") ''; }) diff --git a/nixos/tests/kernel-generic.nix b/nixos/tests/kernel-generic.nix index 352deb521a478..72d31246b75d3 100644 --- a/nixos/tests/kernel-generic.nix +++ b/nixos/tests/kernel-generic.nix @@ -31,6 +31,7 @@ let linux_5_15_hardened linux_6_1_hardened linux_6_5_hardened + linux_6_6_hardened linux_rt_5_4 linux_rt_5_10 linux_rt_5_15 diff --git a/nixos/tests/munin.nix b/nixos/tests/munin.nix index 4ec17e0339df0..e371b2dffa6b8 100644 --- a/nixos/tests/munin.nix +++ b/nixos/tests/munin.nix @@ -37,8 +37,10 @@ import ./make-test-python.nix ({ pkgs, ...} : { with subtest("ensure munin-node starts and listens on 4949"): one.wait_for_unit("munin-node.service") one.wait_for_open_port(4949) + with subtest("ensure munin-cron output is correct"): one.wait_for_file("/var/lib/munin/one/one-uptime-uptime-g.rrd") one.wait_for_file("/var/www/munin/one/index.html") + one.wait_for_file("/var/www/munin/one/one/diskstat_iops_vda-day.png", timeout=60) ''; }) diff --git a/nixos/tests/nextcloud/default.nix b/nixos/tests/nextcloud/default.nix index 19d04b28b4f99..84ac371537271 100644 --- a/nixos/tests/nextcloud/default.nix +++ b/nixos/tests/nextcloud/default.nix @@ -22,4 +22,4 @@ foldl }; }) { } - [ 26 27 ] + [ 26 27 28 ] diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index 7840130d4a364..e9f54208e95f9 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -431,8 +431,8 @@ let }; kea = let - controlSocketPathV4 = "/run/kea-dhcp4/dhcp4.sock"; - controlSocketPathV6 = "/run/kea-dhcp6/dhcp6.sock"; + controlSocketPathV4 = "/run/kea/dhcp4.sock"; + controlSocketPathV6 = "/run/kea/dhcp6.sock"; in { exporterConfig = { diff --git a/nixos/tests/tomcat.nix b/nixos/tests/tomcat.nix index a5f219e104ad4..df5cb033b78f0 100644 --- a/nixos/tests/tomcat.nix +++ b/nixos/tests/tomcat.nix @@ -1,5 +1,6 @@ -import ./make-test-python.nix ({ pkgs, ... }: { +import ./make-test-python.nix ({ lib, pkgs, ... }: { name = "tomcat"; + meta.maintainers = [ lib.maintainers.anthonyroussel ]; nodes.machine = { pkgs, ... }: { services.tomcat = { |