diff options
Diffstat (limited to 'nixos')
55 files changed, 859 insertions, 165 deletions
diff --git a/nixos/doc/manual/configuration/x-windows.chapter.md b/nixos/doc/manual/configuration/x-windows.chapter.md index 5a870a46cbb8..0451e4d25265 100644 --- a/nixos/doc/manual/configuration/x-windows.chapter.md +++ b/nixos/doc/manual/configuration/x-windows.chapter.md @@ -208,7 +208,7 @@ qt.style = "gtk2"; It is possible to install custom [ XKB ](https://en.wikipedia.org/wiki/X_keyboard_extension) keyboard layouts -using the option `services.xserver.extraLayouts`. +using the option `services.xserver.xkb.extraLayouts`. As a first example, we are going to create a layout based on the basic US layout, with an additional layer to type some greek symbols by @@ -235,7 +235,7 @@ xkb_symbols "us-greek" A minimal layout specification must include the following: ```nix -services.xserver.extraLayouts.us-greek = { +services.xserver.xkb.extraLayouts.us-greek = { description = "US layout with alt-gr greek"; languages = [ "eng" ]; symbolsFile = /yourpath/symbols/us-greek; @@ -298,7 +298,7 @@ xkb_symbols "media" As before, to install the layout do ```nix -services.xserver.extraLayouts.media = { +services.xserver.xkb.extraLayouts.media = { description = "Multimedia keys remapping"; languages = [ "eng" ]; symbolsFile = /path/to/media-key; diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index deb6ba46ec2e..22bc4c31618e 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -104,6 +104,8 @@ - hardware/infiniband.nix adds infiniband subnet manager support using an [opensm](https://github.com/linux-rdma/opensm) systemd-template service, instantiated on card guids. The module also adds kernel modules and cli tooling to help administrators debug and measure performance. Available as [hardware.infiniband.enable](#opt-hardware.infiniband.enable). +- [zwave-js](https://github.com/zwave-js/zwave-js-server), a small server wrapper around Z-Wave JS to access it via a WebSocket. Available as [services.zwave-js](#opt-services.zwave-js.enable). + - [Honk](https://humungus.tedunangst.com/r/honk), a complete ActivityPub server with minimal setup and support costs. Available as [services.honk](#opt-services.honk.enable). @@ -322,7 +324,7 @@ order, or relying on `mkBefore` and `mkAfter`, but may impact users calling `mkOrder n` with n ≤ 400. -- X keyboard extension (XKB) options have been reorganized into a single attribute set, `services.xserver.xkb`. Specifically, `services.xserver.layout` is now `services.xserver.xkb.layout`, `services.xserver.xkbModel` is now `services.xserver.xkb.model`, `services.xserver.xkbOptions` is now `services.xserver.xkb.options`, `services.xserver.xkbVariant` is now `services.xserver.xkb.variant`, and `services.xserver.xkbDir` is now `services.xserver.xkb.dir`. +- X keyboard extension (XKB) options have been reorganized into a single attribute set, `services.xserver.xkb`. Specifically, `services.xserver.layout` is now `services.xserver.xkb.layout`, `services.xserver.extraLayouts` is now `services.xserver.xkb.extraLayouts`, `services.xserver.xkbModel` is now `services.xserver.xkb.model`, `services.xserver.xkbOptions` is now `services.xserver.xkb.options`, `services.xserver.xkbVariant` is now `services.xserver.xkb.variant`, and `services.xserver.xkbDir` is now `services.xserver.xkb.dir`. - `networking.networkmanager.firewallBackend` was removed as NixOS is now using iptables-nftables-compat even when using iptables, therefore Networkmanager now uses the nftables backend unconditionally. @@ -337,6 +339,8 @@ - The `services.mtr-exporter.target` has been removed in favor of `services.mtr-exporter.jobs` which allows specifying multiple targets. +- `blender-with-packages` has been deprecated in favor of `blender.withPackages`, for example `blender.withPackages (ps: [ps.bpycv])`. It behaves similarly to `python3.withPackages`. + - Setting `nixpkgs.config` options while providing an external `pkgs` instance will now raise an error instead of silently ignoring the options. NixOS modules no longer set `nixpkgs.config` to accomodate this. This specifically affects `services.locate`, `services.xserver.displayManager.lightdm.greeters.tiny` and `programs.firefox` NixOS modules. No manual intervention should be required in most cases, however, configurations relying on those modules affecting packages outside the system environment should switch to explicit overlays. - `service.borgmatic.settings.location` and `services.borgmatic.configurations.<name>.location` are deprecated, please move your options out of sections to the global scope. diff --git a/nixos/lib/make-btrfs-fs.nix b/nixos/lib/make-btrfs-fs.nix index 225666f9a50e..277ff6a4dca8 100644 --- a/nixos/lib/make-btrfs-fs.nix +++ b/nixos/lib/make-btrfs-fs.nix @@ -15,6 +15,8 @@ , volumeLabel , uuid ? "44444444-4444-4444-8888-888888888888" , btrfs-progs +, libfaketime +, fakeroot }: let @@ -23,7 +25,7 @@ in pkgs.stdenv.mkDerivation { name = "btrfs-fs.img${lib.optionalString compressImage ".zst"}"; - nativeBuildInputs = [ btrfs-progs ] ++ lib.optional compressImage zstd; + nativeBuildInputs = [ btrfs-progs libfaketime fakeroot ] ++ lib.optional compressImage zstd; buildCommand = '' @@ -50,7 +52,7 @@ pkgs.stdenv.mkDerivation { cp ${sdClosureInfo}/registration ./rootImage/nix-path-registration touch $img - mkfs.btrfs -L ${volumeLabel} -U ${uuid} -r ./rootImage --shrink $img + faketime -f "1970-01-01 00:00:01" fakeroot mkfs.btrfs -L ${volumeLabel} -U ${uuid} -r ./rootImage --shrink $img if ! btrfs check $img; then echo "--- 'btrfs check' failed for BTRFS image ---" diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix index 08141bb0e87b..6f58e848b38a 100644 --- a/nixos/modules/hardware/all-firmware.nix +++ b/nixos/modules/hardware/all-firmware.nix @@ -18,29 +18,16 @@ in { options = { - hardware.enableAllFirmware = mkOption { - default = false; - type = types.bool; - description = lib.mdDoc '' - Turn on this option if you want to enable all the firmware. - ''; - }; + hardware.enableAllFirmware = mkEnableOption "all firmware regardless of license"; - hardware.enableRedistributableFirmware = mkOption { + hardware.enableRedistributableFirmware = mkEnableOption "firmware with a license allowing redistribution" // { default = config.hardware.enableAllFirmware; defaultText = lib.literalExpression "config.hardware.enableAllFirmware"; - type = types.bool; - description = lib.mdDoc '' - Turn on this option if you want to enable all the firmware with a license allowing redistribution. - ''; }; - hardware.wirelessRegulatoryDatabase = mkOption { - default = false; - type = types.bool; - description = lib.mdDoc '' - Load the wireless regulatory database at boot. - ''; + hardware.wirelessRegulatoryDatabase = mkEnableOption "loading the wireless regulatory database at boot" // { + default = cfg.enableRedistributableFirmware || cfg.enableAllFirmware; + defaultText = literalMD "Enabled if proprietary firmware is allowed via {option}`enableRedistributableFirmware` or {option}`enableAllFirmware`."; }; }; @@ -65,7 +52,6 @@ in { ++ optionals (versionOlder config.boot.kernelPackages.kernel.version "4.13") [ rtl8723bs-firmware ]; - hardware.wirelessRegulatoryDatabase = true; }) (mkIf cfg.enableAllFirmware { assertions = [{ diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 2a6ca202024b..6679e5bb7c65 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -267,6 +267,7 @@ ./programs/udevil.nix ./programs/usbtop.nix ./programs/vim.nix + ./programs/virt-manager.nix ./programs/wavemon.nix ./programs/wayland/cardboard.nix ./programs/wayland/river.nix @@ -563,6 +564,7 @@ ./services/home-automation/home-assistant.nix ./services/home-automation/homeassistant-satellite.nix ./services/home-automation/zigbee2mqtt.nix + ./services/home-automation/zwave-js.nix ./services/logging/SystemdJournal2Gelf.nix ./services/logging/awstats.nix ./services/logging/filebeat.nix @@ -1506,6 +1508,7 @@ ./virtualisation/docker.nix ./virtualisation/ecs-agent.nix ./virtualisation/hyperv-guest.nix + ./virtualisation/incus.nix ./virtualisation/kvmgt.nix ./virtualisation/libvirtd.nix ./virtualisation/lxc.nix diff --git a/nixos/modules/programs/firefox.nix b/nixos/modules/programs/firefox.nix index 85f47530cf5a..1edf935d1649 100644 --- a/nixos/modules/programs/firefox.nix +++ b/nixos/modules/programs/firefox.nix @@ -90,7 +90,7 @@ in description = mdDoc '' Group policies to install. - See [Mozilla's documentation](https://github.com/mozilla/policy-templates/blob/master/README.md) + See [Mozilla's documentation](https://mozilla.github.io/policy-templates/) for a list of available options. This can be used to install extensions declaratively! Check out the diff --git a/nixos/modules/programs/fish.nix b/nixos/modules/programs/fish.nix index e6ac6e9957ba..a4c20560bc9b 100644 --- a/nixos/modules/programs/fish.nix +++ b/nixos/modules/programs/fish.nix @@ -268,7 +268,7 @@ in '' mkdir -p $out if [ -d $package/share/man ]; then - find $package/share/man -type f | xargs ${pkgs.python3.pythonForBuild.interpreter} ${patchedGenerator}/create_manpage_completions.py --directory $out >/dev/null + find $package/share/man -type f | xargs ${pkgs.python3.pythonOnBuildForHost.interpreter} ${patchedGenerator}/create_manpage_completions.py --directory $out >/dev/null fi ''; in diff --git a/nixos/modules/programs/wayland/sway.nix b/nixos/modules/programs/wayland/sway.nix index de739faabee9..698d9c2b46c4 100644 --- a/nixos/modules/programs/wayland/sway.nix +++ b/nixos/modules/programs/wayland/sway.nix @@ -42,11 +42,6 @@ in { <https://github.com/swaywm/sway/wiki> and "man 5 sway" for more information''); - enableRealtime = mkEnableOption (lib.mdDoc '' - add CAP_SYS_NICE capability on `sway` binary for realtime scheduling - privileges. This may improve latency and reduce stuttering, specially in - high load scenarios'') // { default = true; }; - package = mkOption { type = with types; nullOr package; default = defaultSwayPackage; @@ -154,14 +149,6 @@ in { "sway/config".source = mkOptionDefault "${cfg.package}/etc/sway/config"; }; }; - security.wrappers = mkIf (cfg.enableRealtime && cfg.package != null) { - sway = { - owner = "root"; - group = "root"; - source = "${cfg.package}/bin/sway"; - capabilities = "cap_sys_nice+ep"; - }; - }; # To make a Sway session available if a display manager like SDDM is enabled: services.xserver.displayManager.sessionPackages = optionals (cfg.package != null) [ cfg.package ]; } (import ./wayland-session.nix { inherit lib pkgs; }) diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix index d225442773c6..c665c15242a5 100644 --- a/nixos/modules/security/sudo.nix +++ b/nixos/modules/security/sudo.nix @@ -6,8 +6,6 @@ let cfg = config.security.sudo; - inherit (pkgs) sudo; - toUserString = user: if (isInt user) then "#${toString user}" else "${user}"; toGroupString = group: if (isInt group) then "%#${toString group}" else "%${group}"; @@ -247,7 +245,7 @@ in }; }; - environment.systemPackages = [ sudo ]; + environment.systemPackages = [ cfg.package ]; security.pam.services.sudo = { sshAgentAuth = true; usshAuth = true; }; diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix index 49a55d056014..fcdd3082f5a6 100644 --- a/nixos/modules/services/backup/restic.nix +++ b/nixos/modules/services/backup/restic.nix @@ -345,7 +345,7 @@ in } // optionalAttrs (backup.environmentFile != null) { EnvironmentFile = backup.environmentFile; }; - } // optionalAttrs (backup.initialize || backup.dynamicFilesFrom != null || backup.backupPrepareCommand != null) { + } // optionalAttrs (backup.initialize || doBackup || backup.backupPrepareCommand != null) { preStart = '' ${optionalString (backup.backupPrepareCommand != null) '' ${pkgs.writeScript "backupPrepareCommand" backup.backupPrepareCommand} @@ -360,12 +360,12 @@ in ${pkgs.writeScript "dynamicFilesFromScript" backup.dynamicFilesFrom} >> ${filesFromTmpFile} ''} ''; - } // optionalAttrs (backup.dynamicFilesFrom != null || backup.backupCleanupCommand != null) { + } // optionalAttrs (doBackup || backup.backupCleanupCommand != null) { postStop = '' ${optionalString (backup.backupCleanupCommand != null) '' ${pkgs.writeScript "backupCleanupCommand" backup.backupCleanupCommand} ''} - ${optionalString (backup.dynamicFilesFrom != null) '' + ${optionalString doBackup '' rm ${filesFromTmpFile} ''} ''; diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix index 0f375455e7ed..1a1df38617b5 100644 --- a/nixos/modules/services/backup/syncoid.nix +++ b/nixos/modules/services/backup/syncoid.nix @@ -369,7 +369,7 @@ in PrivateDevices = true; PrivateMounts = true; PrivateNetwork = mkDefault false; - PrivateUsers = true; + PrivateUsers = false; # Enabling this breaks on zfs-2.2.0 ProtectClock = true; ProtectControlGroups = true; ProtectHome = true; diff --git a/nixos/modules/services/display-managers/greetd.nix b/nixos/modules/services/display-managers/greetd.nix index 3a0f59f62afb..89cb81f3a78f 100644 --- a/nixos/modules/services/display-managers/greetd.nix +++ b/nixos/modules/services/display-managers/greetd.nix @@ -59,6 +59,7 @@ in security.pam.services.greetd = { allowNullPassword = true; startSession = true; + enableGnomeKeyring = mkDefault config.services.gnome.gnome-keyring.enable; }; # This prevents nixos-rebuild from killing greetd by activating getty again diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix index 4e5913fd2751..7a938459d0cb 100644 --- a/nixos/modules/services/hardware/fwupd.nix +++ b/nixos/modules/services/hardware/fwupd.nix @@ -181,7 +181,18 @@ in { # required to update the firmware of disks services.udisks2.enable = true; - systemd.packages = [ cfg.package ]; + systemd = { + packages = [ cfg.package ]; + + # fwupd-refresh expects a user that we do not create, so just run with DynamicUser + # instead and ensure we take ownership of /var/lib/fwupd + services.fwupd-refresh.serviceConfig = { + DynamicUser = true; + StateDirectory = "fwupd"; + }; + + timers.fwupd-refresh.wantedBy = [ "timers.target" ]; + }; security.polkit.enable = true; }; diff --git a/nixos/modules/services/hardware/throttled.nix b/nixos/modules/services/hardware/throttled.nix index 9fa495886119..0f1f00348ee8 100644 --- a/nixos/modules/services/hardware/throttled.nix +++ b/nixos/modules/services/hardware/throttled.nix @@ -27,6 +27,7 @@ in { then pkgs.writeText "throttled.conf" cfg.extraConfig else "${pkgs.throttled}/etc/throttled.conf"; + hardware.cpu.x86.msr.enable = true; # Kernel 5.9 spams warnings whenever userspace writes to CPU MSRs. # See https://github.com/erpalma/throttled/issues/215 hardware.cpu.x86.msr.settings.allow-writes = diff --git a/nixos/modules/services/home-automation/zwave-js.nix b/nixos/modules/services/home-automation/zwave-js.nix new file mode 100644 index 000000000000..87c9b8f1ac81 --- /dev/null +++ b/nixos/modules/services/home-automation/zwave-js.nix @@ -0,0 +1,152 @@ +{config, pkgs, lib, ...}: + +with lib; + +let + cfg = config.services.zwave-js; + mergedConfigFile = "/run/zwave-js/config.json"; + settingsFormat = pkgs.formats.json {}; +in { + options.services.zwave-js = { + enable = mkEnableOption (mdDoc "the zwave-js server on boot"); + + package = mkPackageOptionMD pkgs "zwave-js-server" { }; + + port = mkOption { + type = types.port; + default = 3000; + description = mdDoc '' + Port for the server to listen on. + ''; + }; + + serialPort = mkOption { + type = types.path; + description = mdDoc '' + Serial port device path for Z-Wave controller. + ''; + example = "/dev/ttyUSB0"; + }; + + secretsConfigFile = mkOption { + type = types.path; + description = mdDoc '' + JSON file containing secret keys. A dummy example: + + ``` + { + "securityKeys": { + "S0_Legacy": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "S2_Unauthenticated": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", + "S2_Authenticated": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", + "S2_AccessControl": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" + } + } + ``` + + See + <https://zwave-js.github.io/node-zwave-js/#/getting-started/security-s2> + for details. This file will be merged with the module-generated config + file (taking precedence). + + Z-Wave keys can be generated with: + + {command}`< /dev/urandom tr -dc A-F0-9 | head -c32 ;echo` + + + ::: {.warning} + A file in the nix store should not be used since it will be readable to + all users. + ::: + ''; + example = "/secrets/zwave-js-keys.json"; + }; + + settings = mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + + options = { + storage = { + cacheDir = mkOption { + type = types.path; + default = "/var/cache/zwave-js"; + readOnly = true; + description = lib.mdDoc "Cache directory"; + }; + }; + }; + }; + default = {}; + description = mdDoc '' + Configuration settings for the generated config + file. + ''; + }; + + extraFlags = lib.mkOption { + type = with lib.types; listOf str; + default = [ ]; + example = [ "--mock-driver" ]; + description = lib.mdDoc '' + Extra flags to pass to command + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.zwave-js = let + configFile = settingsFormat.generate "zwave-js-config.json" cfg.settings; + in { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + description = "Z-Wave JS Server"; + serviceConfig = { + ExecStartPre = '' + /bin/sh -c "${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${configFile} ${cfg.secretsConfigFile} > ${mergedConfigFile}" + ''; + ExecStart = lib.concatStringsSep " " [ + "${cfg.package}/bin/zwave-server" + "--config ${mergedConfigFile}" + "--port ${toString cfg.port}" + cfg.serialPort + (escapeShellArgs cfg.extraFlags) + ]; + Restart = "on-failure"; + User = "zwave-js"; + SupplementaryGroups = [ "dialout" ]; + CacheDirectory = "zwave-js"; + RuntimeDirectory = "zwave-js"; + + # Hardening + CapabilityBoundingSet = ""; + DeviceAllow = [cfg.serialPort]; + DevicePolicy = "closed"; + DynamicUser = true; + LockPersonality = true; + MemoryDenyWriteExecute = false; + NoNewPrivileges = true; + PrivateUsers = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + RemoveIPC = true; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service @pkey" + "~@privileged @resources" + ]; + UMask = "0077"; + }; + }; + }; + + meta.maintainers = with lib.maintainers; [ graham33 ]; +} diff --git a/nixos/modules/services/matrix/appservice-discord.nix b/nixos/modules/services/matrix/appservice-discord.nix index f579c2529c0a..6ce8718c35d8 100644 --- a/nixos/modules/services/matrix/appservice-discord.nix +++ b/nixos/modules/services/matrix/appservice-discord.nix @@ -100,9 +100,9 @@ in { serviceDependencies = mkOption { type = with types; listOf str; - default = optional config.services.matrix-synapse.enable "matrix-synapse.service"; + default = optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; defaultText = literalExpression '' - optional config.services.matrix-synapse.enable "matrix-synapse.service" + optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit ''; description = lib.mdDoc '' List of Systemd services to require and wait for when starting the application service, diff --git a/nixos/modules/services/matrix/matrix-sliding-sync.nix b/nixos/modules/services/matrix/matrix-sliding-sync.nix index 7e464d6ed589..9807cde40919 100644 --- a/nixos/modules/services/matrix/matrix-sliding-sync.nix +++ b/nixos/modules/services/matrix/matrix-sliding-sync.nix @@ -80,8 +80,11 @@ in } ]; }; - systemd.services.matrix-sliding-sync = { - after = lib.optional cfg.createDatabase "postgresql.service"; + systemd.services.matrix-sliding-sync = rec { + after = + lib.optional cfg.createDatabase "postgresql.service" + ++ lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; + wants = after; wantedBy = [ "multi-user.target" ]; environment = cfg.settings; serviceConfig = { @@ -90,6 +93,8 @@ in ExecStart = lib.getExe cfg.package; StateDirectory = "matrix-sliding-sync"; WorkingDirectory = "%S/matrix-sliding-sync"; + Restart = "on-failure"; + RestartSec = "1s"; }; }; }; diff --git a/nixos/modules/services/matrix/mautrix-facebook.nix b/nixos/modules/services/matrix/mautrix-facebook.nix index bab6865496dd..671040500df8 100644 --- a/nixos/modules/services/matrix/mautrix-facebook.nix +++ b/nixos/modules/services/matrix/mautrix-facebook.nix @@ -145,7 +145,7 @@ in { wantedBy = [ "multi-user.target" ]; wants = [ "network-online.target" - ] ++ optional config.services.matrix-synapse.enable "matrix-synapse.service" + ] ++ optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit ++ optional cfg.configurePostgresql "postgresql.service"; after = wants; diff --git a/nixos/modules/services/matrix/mautrix-telegram.nix b/nixos/modules/services/matrix/mautrix-telegram.nix index 97a6ba858e00..168c8bf436ac 100644 --- a/nixos/modules/services/matrix/mautrix-telegram.nix +++ b/nixos/modules/services/matrix/mautrix-telegram.nix @@ -122,9 +122,9 @@ in { serviceDependencies = mkOption { type = with types; listOf str; - default = optional config.services.matrix-synapse.enable "matrix-synapse.service"; + default = optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; defaultText = literalExpression '' - optional config.services.matrix-synapse.enable "matrix-synapse.service" + optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit ''; description = lib.mdDoc '' List of Systemd services to require and wait for when starting the application service. diff --git a/nixos/modules/services/matrix/mautrix-whatsapp.nix b/nixos/modules/services/matrix/mautrix-whatsapp.nix index c4dc48213495..4b561a4b07a3 100644 --- a/nixos/modules/services/matrix/mautrix-whatsapp.nix +++ b/nixos/modules/services/matrix/mautrix-whatsapp.nix @@ -100,9 +100,9 @@ in { serviceDependencies = lib.mkOption { type = with lib.types; listOf str; - default = lib.optional config.services.matrix-synapse.enable "matrix-synapse.service"; + default = lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; defaultText = lib.literalExpression '' - optional config.services.matrix-synapse.enable "matrix-synapse.service" + optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnits ''; description = lib.mdDoc '' List of Systemd services to require and wait for when starting the application service. diff --git a/nixos/modules/services/matrix/mx-puppet-discord.nix b/nixos/modules/services/matrix/mx-puppet-discord.nix index 36c9f8b122ea..70828804b556 100644 --- a/nixos/modules/services/matrix/mx-puppet-discord.nix +++ b/nixos/modules/services/matrix/mx-puppet-discord.nix @@ -66,9 +66,9 @@ in { }; serviceDependencies = mkOption { type = with types; listOf str; - default = optional config.services.matrix-synapse.enable "matrix-synapse.service"; + default = optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; defaultText = literalExpression '' - optional config.services.matrix-synapse.enable "matrix-synapse.service" + optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit ''; description = lib.mdDoc '' List of Systemd services to require and wait for when starting the application service. diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix index 12e27ef26ff3..9cc769c2d0db 100644 --- a/nixos/modules/services/matrix/synapse.nix +++ b/nixos/modules/services/matrix/synapse.nix @@ -296,6 +296,18 @@ in { services.matrix-synapse = { enable = mkEnableOption (lib.mdDoc "matrix.org synapse"); + serviceUnit = lib.mkOption { + type = lib.types.str; + readOnly = true; + description = lib.mdDoc '' + The systemd unit (a service or a target) for other services to depend on if they + need to be started after matrix-synapse. + + This option is useful as the actual parent unit for all matrix-synapse processes + changes when configuring workers. + ''; + }; + configFile = mkOption { type = types.path; readOnly = true; @@ -1021,6 +1033,7 @@ in { port = 9093; }); + services.matrix-synapse.serviceUnit = if hasWorkers then "matrix-synapse.target" else "matrix-synapse.service"; services.matrix-synapse.configFile = configFile; services.matrix-synapse.package = wrapped; diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix index 1e654cad5dd2..8b79ac0e0c1e 100644 --- a/nixos/modules/services/monitoring/smartd.nix +++ b/nixos/modules/services/monitoring/smartd.nix @@ -19,7 +19,7 @@ let { ${pkgs.coreutils}/bin/cat << EOF From: smartd on ${host} <${nm.sender}> - To: undisclosed-recipients:; + To: ${nm.recipient} Subject: $SMARTD_SUBJECT $SMARTD_FULLMESSAGE diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix index ffb154463053..5bd8e1d4d7a0 100644 --- a/nixos/modules/services/networking/hostapd.nix +++ b/nixos/modules/services/networking/hostapd.nix @@ -899,25 +899,6 @@ in { ''; }; }; - - managementFrameProtection = mkOption { - default = "required"; - type = types.enum ["disabled" "optional" "required"]; - apply = x: - getAttr x { - "disabled" = 0; - "optional" = 1; - "required" = 2; - }; - description = mdDoc '' - Management frame protection (MFP) authenticates management frames - to prevent deauthentication (or related) attacks. - - - {var}`"disabled"`: No management frame protection - - {var}`"optional"`: Use MFP if a connection allows it - - {var}`"required"`: Force MFP for all clients - ''; - }; }; config = let @@ -943,7 +924,8 @@ in { # IEEE 802.11i (authentication) related configuration # Encrypt management frames to protect against deauthentication and similar attacks - ieee80211w = bssCfg.managementFrameProtection; + ieee80211w = mkDefault 1; + sae_require_mfp = mkDefault 1; # Only allow WPA by default and disable insecure WEP auth_algs = mkDefault 1; @@ -1185,14 +1167,6 @@ in { message = ''hostapd radio ${radio} bss ${bss}: bssid must be specified manually (for now) since this radio uses multiple BSS.''; } { - assertion = auth.mode == "wpa3-sae" -> bssCfg.managementFrameProtection == 2; - message = ''hostapd radio ${radio} bss ${bss}: uses WPA3-SAE which requires managementFrameProtection="required"''; - } - { - assertion = auth.mode == "wpa3-sae-transition" -> bssCfg.managementFrameProtection != 0; - message = ''hostapd radio ${radio} bss ${bss}: uses WPA3-SAE in transition mode with WPA2-SHA256, which requires managementFrameProtection="optional" or ="required"''; - } - { assertion = countWpaPasswordDefinitions <= 1; message = ''hostapd radio ${radio} bss ${bss}: must use at most one WPA password option (wpaPassword, wpaPasswordFile, wpaPskFile)''; } diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix index 0066c77438f4..038d574bd878 100644 --- a/nixos/modules/services/networking/prosody.nix +++ b/nixos/modules/services/networking/prosody.nix @@ -779,9 +779,6 @@ in admins = ${toLua cfg.admins} - -- we already build with libevent, so we can just enable it for a more performant server - use_libevent = true - modules_enabled = { ${ lib.concatStringsSep "\n " (lib.mapAttrsToList diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index 279b26bb8957..25367f8e61d4 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -108,6 +108,13 @@ let containsGutenprint = pkgs: length (filterGutenprint pkgs) > 0; getGutenprint = pkgs: head (filterGutenprint pkgs); + parsePorts = addresses: let + splitAddress = addr: lib.strings.splitString ":" addr; + extractPort = addr: builtins.elemAt (builtins.tail (splitAddress addr)) 0; + toInt = str: lib.strings.toInt str; + in + builtins.map (address: toInt (extractPort address)) addresses; + in { @@ -172,6 +179,15 @@ in ''; }; + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Whether to open the firewall for TCP/UDP ports specified in + listenAdrresses option. + ''; + }; + bindirCmds = mkOption { type = types.lines; internal = true; @@ -463,6 +479,13 @@ in security.pam.services.cups = {}; + networking.firewall = let + listenPorts = parsePorts cfg.listenAddresses; + in mkIf cfg.openFirewall { + allowedTCPPorts = listenPorts; + allowedUDPPorts = listenPorts; + }; + }; meta.maintainers = with lib.maintainers; [ matthewbauer ]; diff --git a/nixos/modules/services/web-apps/freshrss.nix b/nixos/modules/services/web-apps/freshrss.nix index ffc05d0e41f8..8b4ea2aa53c9 100644 --- a/nixos/modules/services/web-apps/freshrss.nix +++ b/nixos/modules/services/web-apps/freshrss.nix @@ -220,7 +220,7 @@ in "catch_workers_output" = true; }; phpEnv = { - FRESHRSS_DATA_PATH = "${cfg.dataDir}"; + DATA_PATH = "${cfg.dataDir}"; }; }; }; @@ -267,7 +267,7 @@ in WorkingDirectory = cfg.package; }; environment = { - FRESHRSS_DATA_PATH = cfg.dataDir; + DATA_PATH = cfg.dataDir; }; script = @@ -302,7 +302,7 @@ in wantedBy = [ "multi-user.target" ]; startAt = "*:0/5"; environment = { - FRESHRSS_DATA_PATH = cfg.dataDir; + DATA_PATH = cfg.dataDir; }; serviceConfig = defaultServiceConfig //{ ExecStart = "${cfg.package}/app/actualize_script.php"; diff --git a/nixos/modules/services/web-apps/mediawiki.nix b/nixos/modules/services/web-apps/mediawiki.nix index c5fb03766899..8b494b7c1208 100644 --- a/nixos/modules/services/web-apps/mediawiki.nix +++ b/nixos/modules/services/web-apps/mediawiki.nix @@ -493,6 +493,8 @@ in services.phpfpm.pools.mediawiki = { inherit user group; phpEnv.MEDIAWIKI_CONFIG = "${mediawikiConfig}"; + # https://www.mediawiki.org/wiki/Compatibility + phpPackage = pkgs.php81; settings = (if (cfg.webserver == "apache") then { "listen.owner" = config.services.httpd.user; "listen.group" = config.services.httpd.group; @@ -552,24 +554,20 @@ in deny all; ''; # MediaWiki assets (usually images) - "~ ^/w/resources/(assets|lib|src)" = { - tryFiles = "$uri =404"; - extraConfig = '' - add_header Cache-Control "public"; - expires 7d; - ''; - }; + "~ ^/w/resources/(assets|lib|src)".extraConfig = '' + rewrite ^/w(/.*) $1 break; + add_header Cache-Control "public"; + expires 7d; + ''; # Assets, scripts and styles from skins and extensions - "~ ^/w/(skins|extensions)/.+\\.(css|js|gif|jpg|jpeg|png|svg|wasm|ttf|woff|woff2)$" = { - tryFiles = "$uri =404"; - extraConfig = '' - add_header Cache-Control "public"; - expires 7d; - ''; - }; + "~ ^/w/(skins|extensions)/.+\\.(css|js|gif|jpg|jpeg|png|svg|wasm|ttf|woff|woff2)$".extraConfig = '' + rewrite ^/w(/.*) $1 break; + add_header Cache-Control "public"; + expires 7d; + ''; # Handling for Mediawiki REST API, see [[mw:API:REST_API]] - "/w/rest.php".tryFiles = "$uri $uri/ /rest.php?$query_string"; + "/w/rest.php/".tryFiles = "$uri $uri/ /w/rest.php?$query_string"; # Handling for the article path (pretty URLs) "/wiki/".extraConfig = '' diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index fc3287045710..361dbe879a18 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -29,7 +29,7 @@ let libsForQt5 = pkgs.plasma5Packages; inherit (libsForQt5) kdeGear kdeFrameworks plasma5; inherit (lib) - getBin optionalString literalExpression + getBin optionalAttrs optionalString literalExpression mkRemovedOptionModule mkRenamedOptionModule mkDefault mkIf mkMerge mkOption mkPackageOptionMD types; @@ -178,7 +178,7 @@ in capabilities = "cap_sys_nice+ep"; source = "${getBin plasma5.kwin}/bin/kwin_wayland"; }; - } // mkIf (!cfg.runUsingSystemd) { + } // optionalAttrs (!cfg.runUsingSystemd) { start_kdeinit = { setuid = true; owner = "root"; diff --git a/nixos/modules/services/x11/extra-layouts.nix b/nixos/modules/services/x11/extra-layouts.nix index 3941f50b7550..ab7e39739eeb 100644 --- a/nixos/modules/services/x11/extra-layouts.nix +++ b/nixos/modules/services/x11/extra-layouts.nix @@ -3,7 +3,7 @@ with lib; let - layouts = config.services.xserver.extraLayouts; + layouts = config.services.xserver.xkb.extraLayouts; layoutOpts = { options = { @@ -15,10 +15,10 @@ let languages = mkOption { type = types.listOf types.str; description = - lib.mdDoc '' - A list of languages provided by the layout. - (Use ISO 639-2 codes, for example: "eng" for english) - ''; + lib.mdDoc '' + A list of languages provided by the layout. + (Use ISO 639-2 codes, for example: "eng" for english) + ''; }; compatFile = mkOption { @@ -80,29 +80,37 @@ let }; xkb_patched = pkgs.xorg.xkeyboardconfig_custom { - layouts = config.services.xserver.extraLayouts; + layouts = config.services.xserver.xkb.extraLayouts; }; in { + imports = [ + (lib.mkRenamedOptionModuleWith { + sinceRelease = 2311; + from = [ "services" "xserver" "extraLayouts" ]; + to = [ "services" "xserver" "xkb" "extraLayouts" ]; + }) + ]; + ###### interface - options.services.xserver = { + options.services.xserver.xkb = { extraLayouts = mkOption { type = types.attrsOf (types.submodule layoutOpts); - default = {}; + default = { }; example = literalExpression - '' - { - mine = { - description = "My custom xkb layout."; - languages = [ "eng" ]; - symbolsFile = /path/to/my/layout; - }; - } - ''; + '' + { + mine = { + description = "My custom xkb layout."; + languages = [ "eng" ]; + symbolsFile = /path/to/my/layout; + }; + } + ''; description = lib.mdDoc '' Extra custom layouts that will be included in the xkb configuration. Information on how to create a new layout can be found here: diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix index 6f0a62d0ea89..1086ab80b14f 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix @@ -67,6 +67,8 @@ let ''; in { + meta.maintainers = with lib.maintainers; [ julienmalka ]; + imports = [ (mkRenamedOptionModule [ "boot" "loader" "gummiboot" "enable" ] [ "boot" "loader" "systemd-boot" "enable" ]) ]; diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index bc2fc7f7b108..bac354b4724b 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -253,9 +253,6 @@ done @setHostId@ # Load the required kernel modules. -mkdir -p /lib -ln -s @modulesClosure@/lib/modules /lib/modules -ln -s @modulesClosure@/lib/firmware /lib/firmware echo @extraUtils@/bin/modprobe > /proc/sys/kernel/modprobe for i in @kernelModules@; do info "loading module $(basename $i)..." diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index a3551f68dbe8..f139902cdc85 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -307,7 +307,7 @@ let ${pkgs.buildPackages.busybox}/bin/ash -n $target ''; - inherit linkUnits udevRules extraUtils modulesClosure; + inherit linkUnits udevRules extraUtils; inherit (config.boot) resumeDevice; @@ -349,6 +349,9 @@ let [ { object = bootStage1; symlink = "/init"; } + { object = "${modulesClosure}/lib"; + symlink = "/lib"; + } { object = pkgs.runCommand "initrd-kmod-blacklist-ubuntu" { src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf"; preferLocalBuild = true; diff --git a/nixos/modules/system/boot/systemd/journald.nix b/nixos/modules/system/boot/systemd/journald.nix index 773163bbcb81..7e62a4c9bfed 100644 --- a/nixos/modules/system/boot/systemd/journald.nix +++ b/nixos/modules/system/boot/systemd/journald.nix @@ -28,6 +28,15 @@ in { ''; }; + services.journald.storage = mkOption { + default = "persistent"; + type = types.enum [ "persistent" "volatile" "auto" "none" ]; + description = mdDoc '' + Controls where to store journal data. See + {manpage}`journald.conf(5)` for further information. + ''; + }; + services.journald.rateLimitBurst = mkOption { default = 10000; type = types.int; @@ -100,7 +109,7 @@ in { environment.etc = { "systemd/journald.conf".text = '' [Journal] - Storage=persistent + Storage=${cfg.storage} RateLimitInterval=${cfg.rateLimitInterval} RateLimitBurst=${toString cfg.rateLimitBurst} ${optionalString (cfg.console != "") '' diff --git a/nixos/modules/virtualisation/incus.nix b/nixos/modules/virtualisation/incus.nix new file mode 100644 index 000000000000..3a4f0d7157a0 --- /dev/null +++ b/nixos/modules/virtualisation/incus.nix @@ -0,0 +1,236 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.virtualisation.incus; + preseedFormat = pkgs.formats.yaml { }; +in +{ + meta.maintainers = [ lib.maintainers.adamcstephens ]; + + options = { + virtualisation.incus = { + enable = lib.mkEnableOption (lib.mdDoc '' + incusd, a daemon that manages containers and virtual machines. + + Users in the "incus-admin" group can interact with + the daemon (e.g. to start or stop containers) using the + {command}`incus` command line tool, among others. + ''); + + package = lib.mkPackageOptionMD pkgs "incus" { }; + + lxcPackage = lib.mkPackageOptionMD pkgs "lxc" { }; + + preseed = lib.mkOption { + type = lib.types.nullOr ( + lib.types.submodule { freeformType = preseedFormat.type; } + ); + + default = null; + + description = lib.mdDoc '' + Configuration for Incus preseed, see + <https://linuxcontainers.org/incus/docs/main/howto/initialize/#non-interactive-configuration> + for supported values. + + Changes to this will be re-applied to Incus which will overwrite existing entities or create missing ones, + but entities will *not* be removed by preseed. + ''; + + example = { + networks = [ + { + name = "incusbr0"; + type = "bridge"; + config = { + "ipv4.address" = "10.0.100.1/24"; + "ipv4.nat" = "true"; + }; + } + ]; + profiles = [ + { + name = "default"; + devices = { + eth0 = { + name = "eth0"; + network = "incusbr0"; + type = "nic"; + }; + root = { + path = "/"; + pool = "default"; + size = "35GiB"; + type = "disk"; + }; + }; + } + ]; + storage_pools = [ + { + name = "default"; + driver = "dir"; + config = { + source = "/var/lib/incus/storage-pools/default"; + }; + } + ]; + }; + }; + + socketActivation = lib.mkEnableOption ( + lib.mdDoc '' + socket-activation for starting incus.service. Enabling this option + will stop incus.service from starting automatically on boot. + '' + ); + + startTimeout = lib.mkOption { + type = lib.types.ints.unsigned; + default = 600; + apply = toString; + description = lib.mdDoc '' + Time to wait (in seconds) for incusd to become ready to process requests. + If incusd does not reply within the configured time, `incus.service` will be + considered failed and systemd will attempt to restart it. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + # https://github.com/lxc/incus/blob/f145309929f849b9951658ad2ba3b8f10cbe69d1/doc/reference/server_settings.md + boot.kernel.sysctl = { + "fs.aio-max-nr" = lib.mkDefault 524288; + "fs.inotify.max_queued_events" = lib.mkDefault 1048576; + "fs.inotify.max_user_instances" = lib.mkOverride 1050 1048576; # override in case conflict nixos/modules/services/x11/xserver.nix + "fs.inotify.max_user_watches" = lib.mkOverride 1050 1048576; # override in case conflict nixos/modules/services/x11/xserver.nix + "kernel.dmesg_restrict" = lib.mkDefault 1; + "kernel.keys.maxbytes" = lib.mkDefault 2000000; + "kernel.keys.maxkeys" = lib.mkDefault 2000; + "net.core.bpf_jit_limit" = lib.mkDefault 1000000000; + "net.ipv4.neigh.default.gc_thresh3" = lib.mkDefault 8192; + "net.ipv6.neigh.default.gc_thresh3" = lib.mkDefault 8192; + # vm.max_map_count is set higher in nixos/modules/config/sysctl.nix + }; + + boot.kernelModules = [ + "veth" + "xt_comment" + "xt_CHECKSUM" + "xt_MASQUERADE" + "vhost_vsock" + ] ++ lib.optionals (!config.networking.nftables.enable) [ "iptable_mangle" ]; + + environment.systemPackages = [ cfg.package ]; + + # Note: the following options are also declared in virtualisation.lxc, but + # the latter can't be simply enabled to reuse the formers, because it + # does a bunch of unrelated things. + systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ]; + + security.apparmor = { + packages = [ cfg.lxcPackage ]; + policies = { + "bin.lxc-start".profile = '' + include ${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start + ''; + "lxc-containers".profile = '' + include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers + ''; + }; + }; + + systemd.services.incus = { + description = "Incus Container and Virtual Machine Management Daemon"; + + wantedBy = lib.mkIf (!cfg.socketActivation) [ "multi-user.target" ]; + after = [ + "network-online.target" + "lxcfs.service" + ] ++ (lib.optional cfg.socketActivation "incus.socket"); + requires = [ + "lxcfs.service" + ] ++ (lib.optional cfg.socketActivation "incus.socket"); + wants = [ + "network-online.target" + ]; + + path = lib.mkIf config.boot.zfs.enabled [ config.boot.zfs.package ]; + + environment = { + # Override Path to the LXC template configuration directory + INCUS_LXC_TEMPLATE_CONFIG = "${pkgs.lxcfs}/share/lxc/config"; + }; + + serviceConfig = { + ExecStart = "${cfg.package}/bin/incusd --group incus-admin"; + ExecStartPost = "${cfg.package}/bin/incusd waitready --timeout=${cfg.startTimeout}"; + ExecStop = "${cfg.package}/bin/incus admin shutdown"; + + KillMode = "process"; # when stopping, leave the containers alone + Delegate = "yes"; + LimitMEMLOCK = "infinity"; + LimitNOFILE = "1048576"; + LimitNPROC = "infinity"; + TasksMax = "infinity"; + + Restart = "on-failure"; + TimeoutStartSec = "${cfg.startTimeout}s"; + TimeoutStopSec = "30s"; + }; + }; + + systemd.sockets.incus = lib.mkIf cfg.socketActivation { + description = "Incus UNIX socket"; + wantedBy = [ "sockets.target" ]; + + socketConfig = { + ListenStream = "/var/lib/incus/unix.socket"; + SocketMode = "0660"; + SocketGroup = "incus-admin"; + Service = "incus.service"; + }; + }; + + systemd.services.incus-preseed = lib.mkIf (cfg.preseed != null) { + description = "Incus initialization with preseed file"; + + wantedBy = ["incus.service"]; + after = ["incus.service"]; + bindsTo = ["incus.service"]; + partOf = ["incus.service"]; + + script = '' + ${cfg.package}/bin/incus admin init --preseed <${ + preseedFormat.generate "incus-preseed.yaml" cfg.preseed + } + ''; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + + users.groups.incus-admin = { }; + + users.users.root = { + # match documented default ranges https://linuxcontainers.org/incus/docs/main/userns-idmap/#allowed-ranges + subUidRanges = [ + { + startUid = 1000000; + count = 1000000000; + } + ]; + subGidRanges = [ + { + startGid = 1000000; + count = 1000000000; + } + ]; + }; + + virtualisation.lxc.lxcfs.enable = true; + }; +} diff --git a/nixos/modules/virtualisation/oci-containers.nix b/nixos/modules/virtualisation/oci-containers.nix index 65e97d53724f..a4a40346f093 100644 --- a/nixos/modules/virtualisation/oci-containers.nix +++ b/nixos/modules/virtualisation/oci-containers.nix @@ -214,6 +214,13 @@ let ''; }; + hostname = mkOption { + type = with types; nullOr str; + default = null; + description = lib.mdDoc "The hostname of the container."; + example = "hello-world"; + }; + extraOptions = mkOption { type = with types; listOf str; default = []; @@ -245,11 +252,10 @@ let text = '' ${cfg.backend} rm -f ${name} || true ${optionalString (isValidLogin container.login) '' - cat ${container.login.passwordFile} | \ ${cfg.backend} login \ ${container.login.registry} \ --username ${container.login.username} \ - --password-stdin + --password-stdin < ${container.login.passwordFile} ''} ${optionalString (container.imageFile != null) '' ${cfg.backend} load -i ${container.imageFile} @@ -280,6 +286,8 @@ let "--log-driver=${container.log-driver}" ] ++ optional (container.entrypoint != null) "--entrypoint=${escapeShellArg container.entrypoint}" + ++ optional (container.hostname != null) + "--hostname=${escapeShellArg container.hostname}" ++ lib.optionals (cfg.backend == "podman") [ "--cidfile=/run/podman-${escapedName}.ctr-id" "--cgroups=no-conmon" diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index e625c6322d9c..6f275baf60dc 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -997,7 +997,7 @@ in virtualisation.memorySize is above 2047, but qemu is only able to allocate 2047MB RAM on 32bit max. ''; } - { assertion = cfg.directBoot.initrd != options.virtualisation.directBoot.initrd.default -> cfg.directBoot.enable; + { assertion = cfg.directBoot.enable || cfg.directBoot.initrd == options.virtualisation.directBoot.initrd.default; message = '' You changed the default of `virtualisation.directBoot.initrd` but you are not diff --git a/nixos/modules/virtualisation/vagrant-guest.nix b/nixos/modules/virtualisation/vagrant-guest.nix index 263b1ebca086..2fad376086e3 100644 --- a/nixos/modules/virtualisation/vagrant-guest.nix +++ b/nixos/modules/virtualisation/vagrant-guest.nix @@ -55,4 +55,5 @@ in }; security.sudo.wheelNeedsPassword = false; + security.sudo-rs.wheelNeedsPassword = false; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 979eb3e1aa77..f44fcfcf54ab 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -394,6 +394,7 @@ in { icingaweb2 = handleTest ./icingaweb2.nix {}; iftop = handleTest ./iftop.nix {}; incron = handleTest ./incron.nix {}; + incus = pkgs.recurseIntoAttrs (handleTest ./incus { inherit handleTestOn; }); influxdb = handleTest ./influxdb.nix {}; influxdb2 = handleTest ./influxdb2.nix {}; initrd-network-openvpn = handleTest ./initrd-network-openvpn {}; @@ -933,4 +934,5 @@ in { zram-generator = handleTest ./zram-generator.nix {}; zrepl = handleTest ./zrepl.nix {}; zsh-history = handleTest ./zsh-history.nix {}; + zwave-js = handleTest ./zwave-js.nix {}; } diff --git a/nixos/tests/gitea.nix b/nixos/tests/gitea.nix index f574b59be545..f62c72bddddc 100644 --- a/nixos/tests/gitea.nix +++ b/nixos/tests/gitea.nix @@ -26,7 +26,7 @@ let supportedDbTypes = [ "mysql" "postgres" "sqlite3" ]; makeGiteaTest = type: nameValuePair type (makeTest { name = "${giteaPackage.pname}-${type}"; - meta.maintainers = with maintainers; [ aanderse emilylange kolaente ma27 ]; + meta.maintainers = with maintainers; [ aanderse kolaente ma27 ]; nodes = { server = { config, pkgs, ... }: { diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index e06c52a5f41c..b7deb95b2c19 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -9,13 +9,13 @@ in { nodes.hass = { pkgs, ... }: { services.postgresql = { enable = true; - ensureDatabases = [ "hass" ]; - ensureUsers = [{ - name = "hass"; - ensurePermissions = { - "DATABASE hass" = "ALL PRIVILEGES"; - }; - }]; + + # FIXME: hack for https://github.com/NixOS/nixpkgs/issues/216989 + # Should be replaced with ensureUsers again when a solution for that is found + initialScript = pkgs.writeText "hass-setup-db.sql" '' + CREATE ROLE hass WITH LOGIN; + CREATE DATABASE hass WITH OWNER hass; + ''; }; services.home-assistant = { diff --git a/nixos/tests/incus/container.nix b/nixos/tests/incus/container.nix new file mode 100644 index 000000000000..79b9e2fbabdc --- /dev/null +++ b/nixos/tests/incus/container.nix @@ -0,0 +1,77 @@ +import ../make-test-python.nix ({ pkgs, lib, ... } : + +let + releases = import ../../release.nix { + configuration = { + # Building documentation makes the test unnecessarily take a longer time: + documentation.enable = lib.mkForce false; + }; + }; + + container-image-metadata = releases.lxdContainerMeta.${pkgs.stdenv.hostPlatform.system}; + container-image-rootfs = releases.lxdContainerImage.${pkgs.stdenv.hostPlatform.system}; +in +{ + name = "incus-container"; + + meta.maintainers = with lib.maintainers; [ adamcstephens ]; + + nodes.machine = { ... }: { + virtualisation = { + # Ensure test VM has enough resources for creating and managing guests + cores = 2; + memorySize = 1024; + diskSize = 4096; + + incus.enable = true; + }; + }; + + testScript = '' + def instance_is_up(_) -> bool: + status, _ = machine.execute("incus exec container --disable-stdin --force-interactive /run/current-system/sw/bin/true") + return status == 0 + + def set_container(config): + machine.succeed(f"incus config set container {config}") + machine.succeed("incus restart container") + with machine.nested("Waiting for instance to start and be usable"): + retry(instance_is_up) + + machine.wait_for_unit("incus.service") + + # no preseed should mean no service + machine.fail("systemctl status incus-preseed.service") + + machine.succeed("incus admin init --minimal") + + with subtest("Container image can be imported"): + machine.succeed("incus image import ${container-image-metadata}/*/*.tar.xz ${container-image-rootfs}/*/*.tar.xz --alias nixos") + + with subtest("Container can be launched and managed"): + machine.succeed("incus launch nixos container") + with machine.nested("Waiting for instance to start and be usable"): + retry(instance_is_up) + machine.succeed("echo true | incus exec container /run/current-system/sw/bin/bash -") + + with subtest("Container CPU limits can be managed"): + set_container("limits.cpu 1") + cpuinfo = machine.succeed("incus exec container grep -- -c ^processor /proc/cpuinfo").strip() + assert cpuinfo == "1", f"Wrong number of CPUs reported from /proc/cpuinfo, want: 1, got: {cpuinfo}" + + set_container("limits.cpu 2") + cpuinfo = machine.succeed("incus exec container grep -- -c ^processor /proc/cpuinfo").strip() + assert cpuinfo == "2", f"Wrong number of CPUs reported from /proc/cpuinfo, want: 2, got: {cpuinfo}" + + with subtest("Container memory limits can be managed"): + set_container("limits.memory 64MB") + meminfo = machine.succeed("incus exec container grep -- MemTotal /proc/meminfo").strip() + meminfo_bytes = " ".join(meminfo.split(' ')[-2:]) + assert meminfo_bytes == "62500 kB", f"Wrong amount of memory reported from /proc/meminfo, want: '62500 kB', got: '{meminfo_bytes}'" + + set_container("limits.memory 128MB") + meminfo = machine.succeed("incus exec container grep -- MemTotal /proc/meminfo").strip() + meminfo_bytes = " ".join(meminfo.split(' ')[-2:]) + assert meminfo_bytes == "125000 kB", f"Wrong amount of memory reported from /proc/meminfo, want: '125000 kB', got: '{meminfo_bytes}'" + ''; +}) diff --git a/nixos/tests/incus/default.nix b/nixos/tests/incus/default.nix new file mode 100644 index 000000000000..c88974605e30 --- /dev/null +++ b/nixos/tests/incus/default.nix @@ -0,0 +1,14 @@ +{ + system ? builtins.currentSystem, + config ? { }, + pkgs ? import ../../.. { inherit system config; }, + handleTestOn, +}: +{ + container = import ./container.nix { inherit system pkgs; }; + preseed = import ./preseed.nix { inherit system pkgs; }; + socket-activated = import ./socket-activated.nix { inherit system pkgs; }; + virtual-machine = handleTestOn [ "x86_64-linux" ] ./virtual-machine.nix { + inherit system pkgs; + }; +} diff --git a/nixos/tests/incus/preseed.nix b/nixos/tests/incus/preseed.nix new file mode 100644 index 000000000000..47b2d0cd6228 --- /dev/null +++ b/nixos/tests/incus/preseed.nix @@ -0,0 +1,60 @@ +import ../make-test-python.nix ({ pkgs, lib, ... } : + +{ + name = "incus-preseed"; + + meta.maintainers = with lib.maintainers; [ adamcstephens ]; + + nodes.machine = { lib, ... }: { + virtualisation = { + incus.enable = true; + + incus.preseed = { + networks = [ + { + name = "nixostestbr0"; + type = "bridge"; + config = { + "ipv4.address" = "10.0.100.1/24"; + "ipv4.nat" = "true"; + }; + } + ]; + profiles = [ + { + name = "nixostest_default"; + devices = { + eth0 = { + name = "eth0"; + network = "nixostestbr0"; + type = "nic"; + }; + root = { + path = "/"; + pool = "default"; + size = "35GiB"; + type = "disk"; + }; + }; + } + ]; + storage_pools = [ + { + name = "nixostest_pool"; + driver = "dir"; + } + ]; + }; + }; + }; + + testScript = '' + machine.wait_for_unit("incus.service") + machine.wait_for_unit("incus-preseed.service") + + with subtest("Verify preseed resources created"): + machine.succeed("incus profile show nixostest_default") + machine.succeed("incus network info nixostestbr0") + machine.succeed("incus storage show nixostest_pool") + ''; +}) diff --git a/nixos/tests/incus/socket-activated.nix b/nixos/tests/incus/socket-activated.nix new file mode 100644 index 000000000000..4d25b26a15f5 --- /dev/null +++ b/nixos/tests/incus/socket-activated.nix @@ -0,0 +1,26 @@ +import ../make-test-python.nix ({ pkgs, lib, ... } : + +{ + name = "incus-socket-activated"; + + meta.maintainers = with lib.maintainers; [ adamcstephens ]; + + nodes.machine = { lib, ... }: { + virtualisation = { + incus.enable = true; + incus.socketActivation = true; + }; + }; + + testScript = '' + machine.wait_for_unit("incus.socket") + + # ensure service is not running by default + machine.fail("systemctl is-active incus.service") + machine.fail("systemctl is-active incus-preseed.service") + + # access the socket and ensure the service starts + machine.succeed("incus list") + machine.wait_for_unit("incus.service") + ''; +}) diff --git a/nixos/tests/incus/virtual-machine.nix b/nixos/tests/incus/virtual-machine.nix new file mode 100644 index 000000000000..bfa116679d43 --- /dev/null +++ b/nixos/tests/incus/virtual-machine.nix @@ -0,0 +1,55 @@ +import ../make-test-python.nix ({ pkgs, lib, ... }: + +let + releases = import ../../release.nix { + configuration = { + # Building documentation makes the test unnecessarily take a longer time: + documentation.enable = lib.mkForce false; + + # Our tests require `grep` & friends: + environment.systemPackages = with pkgs; [busybox]; + }; + }; + + vm-image-metadata = releases.lxdVirtualMachineImageMeta.${pkgs.stdenv.hostPlatform.system}; + vm-image-disk = releases.lxdVirtualMachineImage.${pkgs.stdenv.hostPlatform.system}; + + instance-name = "instance1"; +in +{ + name = "incus-virtual-machine"; + + meta.maintainers = with lib.maintainers; [ adamcstephens ]; + + nodes.machine = {...}: { + virtualisation = { + # Ensure test VM has enough resources for creating and managing guests + cores = 2; + memorySize = 1024; + diskSize = 4096; + + incus.enable = true; + }; + }; + + testScript = '' + def instance_is_up(_) -> bool: + status, _ = machine.execute("incus exec ${instance-name} --disable-stdin --force-interactive /run/current-system/sw/bin/true") + return status == 0 + + machine.wait_for_unit("incus.service") + + machine.succeed("incus admin init --minimal") + + with subtest("virtual-machine image can be imported"): + machine.succeed("incus image import ${vm-image-metadata}/*/*.tar.xz ${vm-image-disk}/nixos.qcow2 --alias nixos") + + with subtest("virtual-machine can be launched and become available"): + machine.succeed("incus launch nixos ${instance-name} --vm --config limits.memory=512MB --config security.secureboot=false") + with machine.nested("Waiting for instance to start and be usable"): + retry(instance_is_up) + + with subtest("lxd-agent is started"): + machine.succeed("incus exec ${instance-name} systemctl is-active lxd-agent") + ''; +}) diff --git a/nixos/tests/keymap.nix b/nixos/tests/keymap.nix index 0e160269304b..e8973a50f852 100644 --- a/nixos/tests/keymap.nix +++ b/nixos/tests/keymap.nix @@ -213,7 +213,7 @@ in pkgs.lib.mapAttrs mkKeyboardTest { extraConfig.console.useXkbConfig = true; extraConfig.services.xserver.xkb.layout = "us-greek"; - extraConfig.services.xserver.extraLayouts.us-greek = + extraConfig.services.xserver.xkb.extraLayouts.us-greek = { description = "US layout with alt-gr greek"; languages = [ "eng" ]; symbolsFile = pkgs.writeText "us-greek" '' diff --git a/nixos/tests/mobilizon.nix b/nixos/tests/mobilizon.nix index 2b070ca9d960..398c8530dc56 100644 --- a/nixos/tests/mobilizon.nix +++ b/nixos/tests/mobilizon.nix @@ -10,7 +10,7 @@ import ./make-test-python.nix ({ lib, ... }: meta.maintainers = with lib.maintainers; [ minijackson erictapen ]; nodes.server = - { ... }: + { pkgs, ... }: { services.mobilizon = { enable = true; @@ -25,6 +25,8 @@ import ./make-test-python.nix ({ lib, ... }: }; }; + services.postgresql.package = pkgs.postgresql_14; + security.pki.certificateFiles = [ certs.ca.cert ]; services.nginx.virtualHosts."${mobilizonDomain}" = { diff --git a/nixos/tests/printing.nix b/nixos/tests/printing.nix index 7df042e72e90..29c5d810f215 100644 --- a/nixos/tests/printing.nix +++ b/nixos/tests/printing.nix @@ -19,6 +19,7 @@ import ./make-test-python.nix ( startWhenNeeded = socket; listenAddresses = [ "*:631" ]; defaultShared = true; + openFirewall = true; extraConf = '' <Location /> Order allow,deny @@ -26,7 +27,6 @@ import ./make-test-python.nix ( </Location> ''; }; - networking.firewall.allowedTCPPorts = [ 631 ]; # Add a HP Deskjet printer connected via USB to the server. hardware.printers.ensurePrinters = [{ name = "DeskjetLocal"; diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index 7fd824967206..4bad56991cc6 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -471,7 +471,7 @@ let services.knot = { enable = true; extraArgs = [ "-v" ]; - extraConfig = '' + settingsFile = pkgs.writeText "knot.conf" '' server: listen: 127.0.0.1@53 @@ -969,7 +969,7 @@ let pgbouncer = { exporterConfig = { enable = true; - connectionString = "postgres://admin:@localhost:6432/pgbouncer?sslmode=disable"; + connectionStringFile = pkgs.writeText "connection.conf" "postgres://admin:@localhost:6432/pgbouncer?sslmode=disable"; }; metricProvider = { diff --git a/nixos/tests/restic.nix b/nixos/tests/restic.nix index 54fdc1d3995c..868ccb7efd74 100644 --- a/nixos/tests/restic.nix +++ b/nixos/tests/restic.nix @@ -4,6 +4,7 @@ import ./make-test-python.nix ( let remoteRepository = "/root/restic-backup"; remoteFromFileRepository = "/root/restic-backup-from-file"; + remoteNoInitRepository = "/root/restic-backup-no-init"; rcloneRepository = "rclone:local:/root/restic-rclone-backup"; backupPrepareCommand = '' @@ -64,6 +65,11 @@ import ./make-test-python.nix ( find /opt -mindepth 1 -maxdepth 1 ! -name a_dir # all files in /opt except for a_dir ''; }; + remote-noinit-backup = { + inherit passwordFile exclude pruneOpts paths; + initialize = false; + repository = remoteNoInitRepository; + }; rclonebackup = { inherit passwordFile paths exclude pruneOpts; initialize = true; @@ -114,6 +120,7 @@ import ./make-test-python.nix ( "cp -rT ${testDir} /opt", "touch /opt/excluded_file_1 /opt/excluded_file_2", "mkdir -p /root/restic-rclone-backup", + "restic-remote-noinit-backup init", # test that remotebackup runs custom commands and produces a snapshot "timedatectl set-time '2016-12-13 13:45'", @@ -130,6 +137,10 @@ import ./make-test-python.nix ( "systemctl start restic-backups-remote-from-file-backup.service", 'restic-remote-from-file-backup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', + # test that remote-noinit-backup produces a snapshot + "systemctl start restic-backups-remote-noinit-backup.service", + 'restic-remote-noinit-backup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', + # test that restoring that snapshot produces the same directory "mkdir /tmp/restore-2", "${pkgs.restic}/bin/restic -r ${remoteRepository} -p ${passwordFile} restore latest -t /tmp/restore-2", diff --git a/nixos/tests/shattered-pixel-dungeon.nix b/nixos/tests/shattered-pixel-dungeon.nix index a256bbdfd735..b4ac1670b5ca 100644 --- a/nixos/tests/shattered-pixel-dungeon.nix +++ b/nixos/tests/shattered-pixel-dungeon.nix @@ -21,9 +21,7 @@ import ./make-test-python.nix ({ pkgs, ... }: { machine.wait_for_x() machine.execute("shattered-pixel-dungeon >&2 &") machine.wait_for_window(r"Shattered Pixel Dungeon") - machine.sleep(5) - if "Enter" not in machine.get_screen_text(): - raise Exception("Program did not start successfully") + machine.wait_for_text("Enter") machine.screenshot("screen") ''; }) diff --git a/nixos/tests/systemd-boot.nix b/nixos/tests/systemd-boot.nix index 7d334326cca9..13007d0d80d8 100644 --- a/nixos/tests/systemd-boot.nix +++ b/nixos/tests/systemd-boot.nix @@ -18,7 +18,7 @@ in { basic = makeTest { name = "systemd-boot"; - meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer ]; + meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer julienmalka ]; nodes.machine = common; @@ -42,7 +42,7 @@ in # Check that specialisations create corresponding boot entries. specialisation = makeTest { name = "systemd-boot-specialisation"; - meta.maintainers = with pkgs.lib.maintainers; [ lukegb ]; + meta.maintainers = with pkgs.lib.maintainers; [ lukegb julienmalka ]; nodes.machine = { pkgs, lib, ... }: { imports = [ common ]; @@ -65,7 +65,7 @@ in # Boot without having created an EFI entry--instead using default "/EFI/BOOT/BOOTX64.EFI" fallback = makeTest { name = "systemd-boot-fallback"; - meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer ]; + meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer julienmalka ]; nodes.machine = { pkgs, lib, ... }: { imports = [ common ]; @@ -91,7 +91,7 @@ in update = makeTest { name = "systemd-boot-update"; - meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer ]; + meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer julienmalka ]; nodes.machine = common; @@ -113,7 +113,7 @@ in memtest86 = makeTest { name = "systemd-boot-memtest86"; - meta.maintainers = with pkgs.lib.maintainers; [ Enzime ]; + meta.maintainers = with pkgs.lib.maintainers; [ Enzime julienmalka ]; nodes.machine = { pkgs, lib, ... }: { imports = [ common ]; @@ -128,7 +128,7 @@ in netbootxyz = makeTest { name = "systemd-boot-netbootxyz"; - meta.maintainers = with pkgs.lib.maintainers; [ Enzime ]; + meta.maintainers = with pkgs.lib.maintainers; [ Enzime julienmalka ]; nodes.machine = { pkgs, lib, ... }: { imports = [ common ]; @@ -143,7 +143,7 @@ in entryFilename = makeTest { name = "systemd-boot-entry-filename"; - meta.maintainers = with pkgs.lib.maintainers; [ Enzime ]; + meta.maintainers = with pkgs.lib.maintainers; [ Enzime julienmalka ]; nodes.machine = { pkgs, lib, ... }: { imports = [ common ]; @@ -160,7 +160,7 @@ in extraEntries = makeTest { name = "systemd-boot-extra-entries"; - meta.maintainers = with pkgs.lib.maintainers; [ Enzime ]; + meta.maintainers = with pkgs.lib.maintainers; [ Enzime julienmalka ]; nodes.machine = { pkgs, lib, ... }: { imports = [ common ]; @@ -179,7 +179,7 @@ in extraFiles = makeTest { name = "systemd-boot-extra-files"; - meta.maintainers = with pkgs.lib.maintainers; [ Enzime ]; + meta.maintainers = with pkgs.lib.maintainers; [ Enzime julienmalka ]; nodes.machine = { pkgs, lib, ... }: { imports = [ common ]; @@ -196,7 +196,7 @@ in switch-test = makeTest { name = "systemd-boot-switch-test"; - meta.maintainers = with pkgs.lib.maintainers; [ Enzime ]; + meta.maintainers = with pkgs.lib.maintainers; [ Enzime julienmalka ]; nodes = { inherit common; @@ -256,7 +256,7 @@ in # itself, systems with such firmware won't boot without this fix uefiLargeFileWorkaround = makeTest { name = "uefi-large-file-workaround"; - + meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ]; nodes.machine = { pkgs, ... }: { imports = [common]; virtualisation.efi.OVMF = pkgs.OVMF.overrideAttrs (old: { diff --git a/nixos/tests/vaultwarden.nix b/nixos/tests/vaultwarden.nix index 95d00c1d8ec1..5dcd3ab39dcf 100644 --- a/nixos/tests/vaultwarden.nix +++ b/nixos/tests/vaultwarden.nix @@ -54,9 +54,8 @@ let services.postgresql = { enable = true; initialScript = pkgs.writeText "postgresql-init.sql" '' - CREATE DATABASE bitwarden; CREATE USER bitwardenuser WITH PASSWORD '${dbPassword}'; - GRANT ALL PRIVILEGES ON DATABASE bitwarden TO bitwardenuser; + CREATE DATABASE bitwarden WITH OWNER bitwardenuser; ''; }; diff --git a/nixos/tests/zwave-js.nix b/nixos/tests/zwave-js.nix new file mode 100644 index 000000000000..9239e6964fd7 --- /dev/null +++ b/nixos/tests/zwave-js.nix @@ -0,0 +1,31 @@ +import ./make-test-python.nix ({ pkgs, lib, ...} : + +let + secretsConfigFile = pkgs.writeText "secrets.json" (builtins.toJSON { + securityKeys = { + "S0_Legacy" = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + }; + }); +in { + name = "zwave-js"; + meta.maintainers = with lib.maintainers; [ graham33 ]; + + nodes = { + machine = { config, ... }: { + services.zwave-js = { + enable = true; + serialPort = "/dev/null"; + extraFlags = ["--mock-driver"]; + inherit secretsConfigFile; + }; + }; + }; + + testScript = '' + start_all() + + machine.wait_for_unit("zwave-js.service") + machine.wait_for_open_port(3000) + machine.wait_until_succeeds("journalctl --since -1m --unit zwave-js --grep 'ZwaveJS server listening'") + ''; +}) |