diff options
Diffstat (limited to 'nixos/modules')
113 files changed, 3278 insertions, 2010 deletions
diff --git a/nixos/modules/config/console.nix b/nixos/modules/config/console.nix index f5db5dc5dfc11..1e8bb78f302d6 100644 --- a/nixos/modules/config/console.nix +++ b/nixos/modules/config/console.nix @@ -21,7 +21,7 @@ let # Sadly, systemd-vconsole-setup doesn't support binary keymaps. vconsoleConf = pkgs.writeText "vconsole.conf" '' KEYMAP=${cfg.keyMap} - FONT=${cfg.font} + ${optionalString (cfg.font != null) "FONT=${cfg.font}"} ''; consoleEnv = kbd: pkgs.buildEnv { @@ -45,14 +45,19 @@ in }; font = mkOption { - type = with types; either str path; - default = "Lat2-Terminus16"; + type = with types; nullOr (either str path); + default = null; example = "LatArCyrHeb-16"; description = mdDoc '' - The font used for the virtual consoles. Leave empty to use - whatever the {command}`setfont` program considers the - default font. - Can be either a font name or a path to a PSF font file. + The font used for the virtual consoles. + Can be `null`, a font name, or a path to a PSF font file. + + Use `null` to let the kernel choose a built-in font. + The default is 8x16, and, as of Linux 5.3, Terminus 32 bold for display + resolutions of 2560x1080 and higher. + These fonts cover the [IBM437][] character set. + + [IBM437]: https://en.wikipedia.org/wiki/Code_page_437 ''; }; @@ -151,7 +156,7 @@ in printf "\033%%${if isUnicode then "G" else "@"}" >> /dev/console loadkmap < ${optimizedKeymap} - ${optionalString cfg.earlySetup '' + ${optionalString (cfg.earlySetup && cfg.font != null) '' setfont -C /dev/console $extraUtils/share/consolefonts/font.psf ''} ''); @@ -168,7 +173,7 @@ in "${config.boot.initrd.systemd.package.kbd}/bin/setfont" "${config.boot.initrd.systemd.package.kbd}/bin/loadkeys" "${config.boot.initrd.systemd.package.kbd.gzip}/bin/gzip" # Fonts and keyboard layouts are compressed - ] ++ optionals (hasPrefix builtins.storeDir cfg.font) [ + ] ++ optionals (cfg.font != null && hasPrefix builtins.storeDir cfg.font) [ "${cfg.font}" ] ++ optionals (hasPrefix builtins.storeDir cfg.keyMap) [ "${cfg.keyMap}" @@ -195,7 +200,7 @@ in ]; }) - (mkIf (cfg.earlySetup && !config.boot.initrd.systemd.enable) { + (mkIf (cfg.earlySetup && cfg.font != null && !config.boot.initrd.systemd.enable) { boot.initrd.extraUtilsCommands = '' mkdir -p $out/share/consolefonts ${if substring 0 1 cfg.font == "/" then '' diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix index f9c6e5be226b6..5781679241eff 100644 --- a/nixos/modules/config/fonts/fontconfig.nix +++ b/nixos/modules/config/fonts/fontconfig.nix @@ -7,6 +7,19 @@ This module generates a package containing configuration files and link it in /e Fontconfig reads files in folder name / file name order, so the number prepended to the configuration file name decide the order of parsing. Low number means high priority. +NOTE: Please take extreme care when adjusting the default settings of this module. +People care a lot, and I mean A LOT, about their font rendering, and you will be +The Person That Broke It if it changes in a way people don't like. + +See prior art: +- https://github.com/NixOS/nixpkgs/pull/194594 +- https://github.com/NixOS/nixpkgs/pull/222236 +- https://github.com/NixOS/nixpkgs/pull/222689 + +And do not repeat our mistakes. + +- @K900, March 2023 + */ { config, pkgs, lib, ... }: @@ -218,6 +231,8 @@ let paths = cfg.confPackages; ignoreCollisions = true; }; + + fontconfigNote = "Consider manually configuring fonts.fontconfig according to personal preference."; in { imports = [ @@ -229,6 +244,8 @@ in (mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "") (mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "") (mkRemovedOptionModule [ "fonts" "fontconfig" "dpi" ] "Use display server-specific options") + (mkRemovedOptionModule [ "hardware" "video" "hidpi" "enable" ] fontconfigNote) + (mkRemovedOptionModule [ "fonts" "optimizeForVeryHighDPI" ] fontconfigNote) ] ++ lib.forEach [ "enable" "substitutions" "preset" ] (opt: lib.mkRemovedOptionModule [ "fonts" "fontconfig" "ultimate" "${opt}" ] '' The fonts.fontconfig.ultimate module and configuration is obsolete. diff --git a/nixos/modules/config/fonts/fonts.nix b/nixos/modules/config/fonts/fonts.nix index c0619fa31a327..87cf837e7c80c 100644 --- a/nixos/modules/config/fonts/fonts.nix +++ b/nixos/modules/config/fonts/fonts.nix @@ -3,29 +3,7 @@ with lib; let - # A scalable variant of the X11 "core" cursor - # - # If not running a fancy desktop environment, the cursor is likely set to - # the default `cursor.pcf` bitmap font. This is 17px wide, so it's very - # small and almost invisible on 4K displays. - fontcursormisc_hidpi = pkgs.xorg.fontxfree86type1.overrideAttrs (old: - let - # The scaling constant is 230/96: the scalable `left_ptr` glyph at - # about 23 points is rendered as 17px, on a 96dpi display. - # Note: the XLFD font size is in decipoints. - size = 2.39583 * config.services.xserver.dpi; - sizeString = builtins.head (builtins.split "\\." (toString size)); - in - { - postInstall = '' - alias='cursor -xfree86-cursor-medium-r-normal--0-${sizeString}-0-0-p-0-adobe-fontspecific' - echo "$alias" > $out/lib/X11/fonts/Type1/fonts.alias - ''; - }); - - hasHidpi = - config.hardware.video.hidpi.enable && - config.services.xserver.dpi != null; + cfg = config.fonts; defaultFonts = [ pkgs.dejavu_fonts @@ -35,14 +13,7 @@ let pkgs.unifont pkgs.noto-fonts-emoji ]; - - defaultXFonts = - [ (if hasHidpi then fontcursormisc_hidpi else pkgs.xorg.fontcursormisc) - pkgs.xorg.fontmiscmisc - ]; - in - { imports = [ (mkRemovedOptionModule [ "fonts" "enableCoreFonts" ] "Use fonts.fonts = [ pkgs.corefonts ]; instead.") @@ -68,14 +39,9 @@ in and families and reasonable coverage of Unicode. ''; }; - }; }; - config = mkMerge [ - { fonts.fonts = mkIf config.fonts.enableDefaultFonts defaultFonts; } - { fonts.fonts = mkIf config.services.xserver.enable defaultXFonts; } - ]; - + config = { fonts.fonts = mkIf cfg.enableDefaultFonts defaultFonts; }; } diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index ee4692fc6a6a6..852f0a22f3aea 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -539,7 +539,9 @@ in { ###### implementation - config = { + config = let + cryptSchemeIdPatternGroup = "(${lib.concatStringsSep "|" pkgs.libxcrypt.enabledCryptSchemeIds})"; + in { users.users = { root = { @@ -601,15 +603,16 @@ in { text = '' users=() while IFS=: read -r user hash tail; do - if [[ "$hash" = "$"* && ! "$hash" =~ ^\$(y|gy|7|2b|2y|2a|6)\$ ]]; then + if [[ "$hash" = "$"* && ! "$hash" =~ ^\''$${cryptSchemeIdPatternGroup}\$ ]]; then users+=("$user") fi done </etc/shadow if (( "''${#users[@]}" )); then echo " - WARNING: The following user accounts rely on password hashes that will - be removed in NixOS 23.05. They should be renewed as soon as possible." + WARNING: The following user accounts rely on password hashing algorithms + that have been removed. They need to be renewed as soon as possible, as + they do prevent their users from logging in." printf ' - %s\n' "''${users[@]}" fi ''; @@ -699,7 +702,20 @@ in { users.groups.${user.name} = {}; ''; } - ] + ] ++ (map (shell: { + assertion = (user.shell == pkgs.${shell}) -> (config.programs.${shell}.enable == true); + message = '' + users.users.${user.name}.shell is set to ${shell}, but + programs.${shell}.enable is not true. This will cause the ${shell} + shell to lack the basic nix directories in its PATH and might make + logging in as that user impossible. You can fix it with: + programs.${shell}.enable = true; + ''; + }) [ + "fish" + "xonsh" + "zsh" + ]) )); warnings = @@ -716,7 +732,7 @@ in { let sep = "\\$"; base64 = "[a-zA-Z0-9./]+"; - id = "[a-z0-9-]+"; + id = cryptSchemeIdPatternGroup; value = "[a-zA-Z0-9/+.-]+"; options = "${id}(=${value})?(,${id}=${value})*"; scheme = "${id}(${sep}${options})?"; diff --git a/nixos/modules/config/zram.nix b/nixos/modules/config/zram.nix index 4df646cf27966..991387ea9b2bd 100644 --- a/nixos/modules/config/zram.nix +++ b/nixos/modules/config/zram.nix @@ -82,12 +82,30 @@ in {command}`cat /sys/class/block/zram*/comp_algorithm` ''; }; + + writebackDevice = lib.mkOption { + default = null; + example = "/dev/zvol/tarta-zoot/swap-writeback"; + type = lib.types.nullOr lib.types.path; + description = lib.mdDoc '' + Write incompressible pages to this device, + as there's no gain from keeping them in RAM. + ''; + }; }; }; config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.writebackDevice == null || cfg.swapDevices <= 1; + message = "A single writeback device cannot be shared among multiple zram devices"; + } + ]; + + system.requiredKernelConfig = with config.lib.kernelConfig; [ (isModule "ZRAM") ]; @@ -112,6 +130,8 @@ in zram-size = if cfg.memoryMax != null then "min(${size}, ${toString cfg.memoryMax} / 1024 / 1024)" else size; compression-algorithm = cfg.algorithm; swap-priority = cfg.priority; + } // lib.optionalAttrs (cfg.writebackDevice != null) { + writeback-device = cfg.writebackDevice; }; }) devices)); diff --git a/nixos/modules/hardware/device-tree.nix b/nixos/modules/hardware/device-tree.nix index 2807313a5a9c4..c568f52ab677d 100644 --- a/nixos/modules/hardware/device-tree.nix +++ b/nixos/modules/hardware/device-tree.nix @@ -65,7 +65,7 @@ let }; }; - filterDTBs = src: if isNull cfg.filter + filterDTBs = src: if cfg.filter == null then "${src}/dtbs" else pkgs.runCommand "dtbs-filtered" {} '' @@ -93,8 +93,8 @@ let # Fill in `dtboFile` for each overlay if not set already. # Existence of one of these is guarded by assertion below withDTBOs = xs: flip map xs (o: o // { dtboFile = - if isNull o.dtboFile then - if !isNull o.dtsFile then compileDTS o.name o.dtsFile + if o.dtboFile == null then + if o.dtsFile != null then compileDTS o.name o.dtsFile else compileDTS o.name (pkgs.writeText "dts" o.dtsText) else o.dtboFile; } ); @@ -181,7 +181,7 @@ in config = mkIf (cfg.enable) { assertions = let - invalidOverlay = o: isNull o.dtsFile && isNull o.dtsText && isNull o.dtboFile; + invalidOverlay = o: (o.dtsFile == null) && (o.dtsText == null) && (o.dtboFile == null); in lib.singleton { assertion = lib.all (o: !invalidOverlay o) cfg.overlays; message = '' diff --git a/nixos/modules/hardware/nitrokey.nix b/nixos/modules/hardware/nitrokey.nix index fa9dd4d6d8f99..e2e88a8eade49 100644 --- a/nixos/modules/hardware/nitrokey.nix +++ b/nixos/modules/hardware/nitrokey.nix @@ -22,6 +22,6 @@ in }; config = mkIf cfg.enable { - services.udev.packages = [ pkgs.nitrokey-udev-rules ]; + services.udev.packages = [ pkgs.libnitrokey ]; }; } diff --git a/nixos/modules/hardware/opengl.nix b/nixos/modules/hardware/opengl.nix index 9108bcbd1652a..7b5e669d47f4f 100644 --- a/nixos/modules/hardware/opengl.nix +++ b/nixos/modules/hardware/opengl.nix @@ -69,19 +69,48 @@ in package = mkOption { type = types.package; internal = true; + default = cfg.mesaPackage; description = lib.mdDoc '' The package that provides the OpenGL implementation. + + The default is Mesa's drivers which should cover all OpenGL-capable + hardware. If you want to use another Mesa version, adjust + {option}`mesaPackage`. ''; }; - package32 = mkOption { type = types.package; internal = true; + default = cfg.mesaPackage32; + description = lib.mdDoc '' + Same as {option}`package` but for the 32-bit OpenGL implementation on + 64-bit systems. Used when {option}`driSupport32Bit` is set. + ''; + }; + + mesaPackage = mkOption { + type = types.package; + default = pkgs.mesa; + defaultText = literalExpression "pkgs.mesa"; + example = literalExpression "pkgs.mesa_22"; description = lib.mdDoc '' - The package that provides the 32-bit OpenGL implementation on - 64-bit systems. Used when {option}`driSupport32Bit` is - set. + The Mesa driver package used for rendering support on the system. + + You should only need to adjust this if you require a newer Mesa + version for your hardware or because you need to patch a bug. ''; + apply = mesa: mesa.drivers or (throw "`mesa` package must have a `drivers` output."); + }; + mesaPackage32 = mkOption { + type = types.package; + default = pkgs.pkgsi686Linux.mesa; + defaultText = literalExpression "pkgs.pkgsi686Linux.mesa"; + example = literalExpression "pkgs.pkgsi686Linux.mesa_22"; + description = lib.mdDoc '' + Same as {option}`mesaPackage` but for the 32-bit Mesa on 64-bit + systems. Used when {option}`driSupport32Bit` is set. + ''; + apply = mesa: mesa.drivers or (throw "`mesa` package must have a `drivers` output."); }; extraPackages = mkOption { @@ -97,7 +126,6 @@ in ::: ''; }; - extraPackages32 = mkOption { type = types.listOf types.package; default = []; @@ -153,9 +181,6 @@ in environment.sessionVariables.LD_LIBRARY_PATH = mkIf cfg.setLdLibraryPath ([ "/run/opengl-driver/lib" ] ++ optional cfg.driSupport32Bit "/run/opengl-driver-32/lib"); - hardware.opengl.package = mkDefault pkgs.mesa.drivers; - hardware.opengl.package32 = mkDefault pkgs.pkgsi686Linux.mesa.drivers; - boot.extraModulePackages = optional (elem "virtualbox" videoDrivers) kernelPackages.virtualboxGuestAdditions; }; } diff --git a/nixos/modules/hardware/video/hidpi.nix b/nixos/modules/hardware/video/hidpi.nix deleted file mode 100644 index 8c8f8bc0c2652..0000000000000 --- a/nixos/modules/hardware/video/hidpi.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ lib, pkgs, config, ...}: -with lib; - -{ - options.hardware.video.hidpi.enable = mkEnableOption (lib.mdDoc "Font/DPI configuration optimized for HiDPI displays"); - - config = mkIf config.hardware.video.hidpi.enable { - console.font = lib.mkDefault "${pkgs.terminus_font}/share/consolefonts/ter-v32n.psf.gz"; - - # Needed when typing in passwords for full disk encryption - console.earlySetup = mkDefault true; - boot.loader.systemd-boot.consoleMode = mkDefault "1"; - - - # Grayscale anti-aliasing for fonts - fonts.fontconfig.antialias = mkDefault true; - fonts.fontconfig.subpixel = { - rgba = mkDefault "none"; - lcdfilter = mkDefault "none"; - }; - - # TODO Find reasonable defaults X11 & wayland - }; -} diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index 434931ccae5a7..79a3ab6baaab2 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -462,8 +462,7 @@ in boot.kernelParams = optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1" ++ optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1" ++ optional cfg.open "nvidia.NVreg_OpenRmEnableUnsupportedGpus=1" - # proprietary driver is not compiled with support for X86_KERNEL_IBT - ++ optional (!cfg.open && config.boot.kernelPackages.kernel.kernelAtLeast "6.2") "ibt=off"; + ++ optional (!cfg.open && config.boot.kernelPackages.kernel.kernelAtLeast "6.2" && lib.versionOlder nvidia_x11.version "530") "ibt=off"; services.udev.extraRules = '' diff --git a/nixos/modules/i18n/input-method/default.md b/nixos/modules/i18n/input-method/default.md index 05ae12065c34c..42cb8a8d7b6a7 100644 --- a/nixos/modules/i18n/input-method/default.md +++ b/nixos/modules/i18n/input-method/default.md @@ -9,7 +9,7 @@ than there are keys on the keyboard. The following input methods are available in NixOS: - IBus: The intelligent input bus. - - Fcitx: A customizable lightweight input method. + - Fcitx5: The next generation of fcitx, addons (including engines, dictionaries, skins) can be added using `i18n.inputMethod.fcitx5.addons`. - Nabi: A Korean input method based on XIM. - Uim: The universal input method, is a library with a XIM bridge. - Hime: An extremely easy-to-use input method framework. @@ -67,38 +67,40 @@ application in the Nix store. The `glib` packages must match exactly. If they do not, uninstalling and reinstalling the application is a likely fix. -## Fcitx {#module-services-input-methods-fcitx} +## Fcitx5 {#module-services-input-methods-fcitx} -Fcitx is an input method framework with extension support. It has three +Fcitx5 is an input method framework with extension support. It has three built-in Input Method Engine, Pinyin, QuWei and Table-based input methods. The following snippet can be used to configure Fcitx: ``` i18n.inputMethod = { - enabled = "fcitx"; - fcitx.engines = with pkgs.fcitx-engines; [ mozc hangul m17n ]; + enabled = "fcitx5"; + fcitx5.addons = with pkgs; [ fcitx5-mozc fcitx5-hangul fcitx5-m17n ]; }; ``` -`i18n.inputMethod.fcitx.engines` is optional and can be -used to add extra Fcitx engines. +`i18n.inputMethod.fcitx5.addons` is optional and can be +used to add extra Fcitx5 addons. -Available extra Fcitx engines are: +Available extra Fcitx5 addons are: - - Anthy (`fcitx-engines.anthy`): Anthy is a system for + - Anthy (`fcitx5-anthy`): Anthy is a system for Japanese input method. It converts Hiragana text to Kana Kanji mixed text. - - Chewing (`fcitx-engines.chewing`): Chewing is an + - Chewing (`fcitx5-chewing`): Chewing is an intelligent Zhuyin input method. It is one of the most popular input methods among Traditional Chinese Unix users. - - Hangul (`fcitx-engines.hangul`): Korean input method. - - Unikey (`fcitx-engines.unikey`): Vietnamese input method. - - m17n (`fcitx-engines.m17n`): m17n is an input method that + - Hangul (`fcitx5-hangul`): Korean input method. + - Unikey (`fcitx5-unikey`): Vietnamese input method. + - m17n (`fcitx5-m17n`): m17n is an input method that uses input methods and corresponding icons in the m17n database. - - mozc (`fcitx-engines.mozc`): A Japanese input method from + - mozc (`fcitx5-mozc`): A Japanese input method from Google. - - table-others (`fcitx-engines.table-others`): Various + - table-others (`fcitx5-table-other`): Various table-based input methods. + - chinese-addons (`fcitx5-chinese-addons`): Various chinese input methods. + - rime (`fcitx5-rime`): RIME support for fcitx5. ## Nabi {#module-services-input-methods-nabi} diff --git a/nixos/modules/i18n/input-method/default.nix b/nixos/modules/i18n/input-method/default.nix index 5f803b4f2ee79..d967d4335c70c 100644 --- a/nixos/modules/i18n/input-method/default.nix +++ b/nixos/modules/i18n/input-method/default.nix @@ -29,9 +29,9 @@ in options.i18n = { inputMethod = { enabled = mkOption { - type = types.nullOr (types.enum [ "ibus" "fcitx" "fcitx5" "nabi" "uim" "hime" "kime" ]); + type = types.nullOr (types.enum [ "ibus" "fcitx5" "nabi" "uim" "hime" "kime" ]); default = null; - example = "fcitx"; + example = "fcitx5"; description = lib.mdDoc '' Select the enabled input method. Input methods is a software to input symbols that are not available on standard input devices. @@ -40,7 +40,6 @@ in Currently the following input methods are available in NixOS: - ibus: The intelligent input bus, extra input engines can be added using `i18n.inputMethod.ibus.engines`. - - fcitx: A customizable lightweight input method, extra input engines can be added using `i18n.inputMethod.fcitx.engines`. - fcitx5: The next generation of fcitx, addons (including engines, dictionaries, skins) can be added using `i18n.inputMethod.fcitx5.addons`. - nabi: A Korean input method based on XIM. Nabi doesn't support Qt 5. - uim: The universal input method, is a library with a XIM bridge. uim mainly support Chinese, Japanese and Korean. diff --git a/nixos/modules/i18n/input-method/fcitx.nix b/nixos/modules/i18n/input-method/fcitx.nix deleted file mode 100644 index 043ec3d55c1f6..0000000000000 --- a/nixos/modules/i18n/input-method/fcitx.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.i18n.inputMethod.fcitx; - fcitxPackage = pkgs.fcitx.override { plugins = cfg.engines; }; - fcitxEngine = types.package // { - name = "fcitx-engine"; - check = x: (lib.types.package.check x) && (attrByPath ["meta" "isFcitxEngine"] false x); - }; -in -{ - options = { - - i18n.inputMethod.fcitx = { - engines = mkOption { - type = with types; listOf fcitxEngine; - default = []; - example = literalExpression "with pkgs.fcitx-engines; [ mozc hangul ]"; - description = - let - enginesDrv = filterAttrs (const isDerivation) pkgs.fcitx-engines; - engines = concatStringsSep ", " - (map (name: "`${name}`") (attrNames enginesDrv)); - in - lib.mdDoc "Enabled Fcitx engines. Available engines are: ${engines}."; - }; - }; - - }; - - config = mkIf (config.i18n.inputMethod.enabled == "fcitx") { - i18n.inputMethod.package = fcitxPackage; - - environment.variables = { - GTK_IM_MODULE = "fcitx"; - QT_IM_MODULE = "fcitx"; - XMODIFIERS = "@im=fcitx"; - }; - services.xserver.displayManager.sessionCommands = "${fcitxPackage}/bin/fcitx"; - }; - - # uses attributes of the linked package - meta.buildDocsInSandbox = false; -} diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix index 3f92b779d60a2..3c7c7e30a0bf2 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix @@ -21,6 +21,9 @@ with lib; # ISO naming. isoImage.isoName = "${config.isoImage.isoBaseName}-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}.iso"; + # BIOS booting + isoImage.makeBiosBootable = true; + # EFI booting isoImage.makeEfiBootable = true; diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index 86c2cd1a8c73e..8fa070b03db31 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -535,10 +535,17 @@ in ''; }; + isoImage.makeBiosBootable = mkOption { + default = false; + description = lib.mdDoc '' + Whether the ISO image should be a BIOS-bootable disk. + ''; + }; + isoImage.makeEfiBootable = mkOption { default = false; description = lib.mdDoc '' - Whether the ISO image should be an efi-bootable volume. + Whether the ISO image should be an EFI-bootable volume. ''; }; @@ -693,7 +700,7 @@ in boot.loader.grub.enable = false; environment.systemPackages = [ grubPkgs.grub2 grubPkgs.grub2_efi ] - ++ optional canx86BiosBoot pkgs.syslinux + ++ optional (config.isoImage.makeBiosBootable && canx86BiosBoot) pkgs.syslinux ; # In stage 1 of the boot, mount the CD as the root FS by label so @@ -744,7 +751,7 @@ in { source = pkgs.writeText "version" config.system.nixos.label; target = "/version.txt"; } - ] ++ optionals canx86BiosBoot [ + ] ++ optionals (config.isoImage.makeBiosBootable && canx86BiosBoot) [ { source = config.isoImage.splashImage; target = "/isolinux/background.png"; } @@ -771,7 +778,7 @@ in { source = config.isoImage.efiSplashImage; target = "/EFI/boot/efi-background.png"; } - ] ++ optionals (config.boot.loader.grub.memtest86.enable && canx86BiosBoot) [ + ] ++ optionals (config.boot.loader.grub.memtest86.enable && config.isoImage.makeBiosBootable && canx86BiosBoot) [ { source = "${pkgs.memtest86plus}/memtest.bin"; target = "/boot/memtest.bin"; } @@ -786,10 +793,10 @@ in # Create the ISO image. system.build.isoImage = pkgs.callPackage ../../../lib/make-iso9660-image.nix ({ inherit (config.isoImage) isoName compressImage volumeID contents; - bootable = canx86BiosBoot; + bootable = config.isoImage.makeBiosBootable && canx86BiosBoot; bootImage = "/isolinux/isolinux.bin"; - syslinux = if canx86BiosBoot then pkgs.syslinux else null; - } // optionalAttrs (config.isoImage.makeUsbBootable && canx86BiosBoot) { + syslinux = if config.isoImage.makeBiosBootable && canx86BiosBoot then pkgs.syslinux else null; + } // optionalAttrs (config.isoImage.makeUsbBootable && config.isoImage.makeBiosBootable && canx86BiosBoot) { usbBootable = true; isohybridMbrImage = "${pkgs.syslinux}/share/syslinux/isohdpfx.bin"; } // optionalAttrs config.isoImage.makeEfiBootable { diff --git a/nixos/modules/installer/netboot/netboot-minimal.nix b/nixos/modules/installer/netboot/netboot-minimal.nix index 91065d52faf47..5ca255acf35f4 100644 --- a/nixos/modules/installer/netboot/netboot-minimal.nix +++ b/nixos/modules/installer/netboot/netboot-minimal.nix @@ -9,4 +9,7 @@ ]; documentation.man.enable = lib.mkOverride 500 true; + hardware.enableRedistributableFirmware = lib.mkOverride 70 false; + system.extraDependencies = lib.mkOverride 70 []; + networking.wireless.enable = lib.mkOverride 500 false; } diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index db530533e4283..946e73dac5864 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -518,21 +518,6 @@ EOF } } -# For lack of a better way to determine it, guess whether we should use a -# bigger font for the console from the display mode on the first -# framebuffer. A way based on the physical size/actual DPI reported by -# the monitor would be nice, but I don't know how to do this without X :) -my $fb_modes_file = "/sys/class/graphics/fb0/modes"; -if (-f $fb_modes_file && -r $fb_modes_file) { - my $modes = read_file($fb_modes_file); - $modes =~ m/([0-9]+)x([0-9]+)/; - my $console_width = $1, my $console_height = $2; - if ($console_width > 1920) { - push @attrs, "# high-resolution display"; - push @attrs, 'hardware.video.hidpi.enable = lib.mkDefault true;'; - } -} - # Generate the hardware configuration file. diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index c2cca03e433ca..08278d3943f39 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -159,10 +159,7 @@ in $desktopConfiguration # Configure keymap in X11 # services.xserver.layout = "us"; - # services.xserver.xkbOptions = { - # "eurosign:e"; - # "caps:escape" # map caps to escape. - # }; + # services.xserver.xkbOptions = "eurosign:e,caps:escape"; # Enable CUPS to print documents. # services.printing.enable = true; diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 17ea04cb4ecb5..bed50b81604da 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -338,7 +338,7 @@ in lidarr = 306; slurm = 307; kapacitor = 308; - solr = 309; + # solr = 309; removed 2023-03-16 alerta = 310; minetest = 311; rss2email = 312; @@ -648,7 +648,7 @@ in lidarr = 306; slurm = 307; kapacitor = 308; - solr = 309; + # solr = 309; removed 2023-03-16 alerta = 310; minetest = 311; rss2email = 312; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 60f3bbc98c0c7..abd88d285a998 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -95,7 +95,6 @@ ./hardware/video/bumblebee.nix ./hardware/video/capture/mwprocapture.nix ./hardware/video/displaylink.nix - ./hardware/video/hidpi.nix ./hardware/video/nvidia.nix ./hardware/video/switcheroo-control.nix ./hardware/video/uvcvideo/default.nix @@ -104,7 +103,6 @@ ./hardware/xone.nix ./hardware/xpadneo.nix ./i18n/input-method/default.nix - ./i18n/input-method/fcitx.nix ./i18n/input-method/fcitx5.nix ./i18n/input-method/hime.nix ./i18n/input-method/ibus.nix @@ -220,6 +218,7 @@ ./programs/proxychains.nix ./programs/qdmr.nix ./programs/qt5ct.nix + ./programs/regreet.nix ./programs/rog-control-center.nix ./programs/rust-motd.nix ./programs/screen.nix @@ -377,6 +376,8 @@ ./services/continuous-integration/jenkins/default.nix ./services/continuous-integration/jenkins/job-builder.nix ./services/continuous-integration/jenkins/slave.nix + ./services/continuous-integration/woodpecker/agents.nix + ./services/continuous-integration/woodpecker/server.nix ./services/databases/aerospike.nix ./services/databases/cassandra.nix ./services/databases/clickhouse.nix @@ -429,7 +430,6 @@ ./services/desktops/gvfs.nix ./services/desktops/malcontent.nix ./services/desktops/neard.nix - ./services/desktops/pipewire/pipewire-media-session.nix ./services/desktops/pipewire/pipewire.nix ./services/desktops/pipewire/wireplumber.nix ./services/desktops/profile-sync-daemon.nix @@ -509,6 +509,7 @@ ./services/hardware/usbmuxd.nix ./services/hardware/usbrelayd.nix ./services/hardware/vdr.nix + ./services/hardware/keyd.nix ./services/home-automation/evcc.nix ./services/home-automation/home-assistant.nix ./services/home-automation/zigbee2mqtt.nix @@ -732,6 +733,7 @@ ./services/monitoring/nagios.nix ./services/monitoring/netdata.nix ./services/monitoring/parsedmarc.nix + ./services/monitoring/prometheus/alertmanager-irc-relay.nix ./services/monitoring/prometheus/alertmanager.nix ./services/monitoring/prometheus/default.nix ./services/monitoring/prometheus/exporters.nix @@ -948,6 +950,7 @@ ./services/networking/owamp.nix ./services/networking/pdns-recursor.nix ./services/networking/pdnsd.nix + ./services/networking/peroxide.nix ./services/networking/pixiecore.nix ./services/networking/pleroma.nix ./services/networking/polipo.nix @@ -1059,8 +1062,8 @@ ./services/search/meilisearch.nix ./services/search/opensearch.nix ./services/search/qdrant.nix - ./services/search/solr.nix ./services/security/aesmd.nix + ./services/security/authelia.nix ./services/security/certmgr.nix ./services/security/cfssl.nix ./services/security/clamav.nix @@ -1130,7 +1133,6 @@ ./services/web-apps/atlassian/confluence.nix ./services/web-apps/atlassian/crowd.nix ./services/web-apps/atlassian/jira.nix - ./services/web-apps/baget.nix ./services/web-apps/bookstack.nix ./services/web-apps/calibre-web.nix ./services/web-apps/coder.nix diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix index 518a1f8d0b304..9f32f85a61ec2 100644 --- a/nixos/modules/profiles/base.nix +++ b/nixos/modules/profiles/base.nix @@ -1,5 +1,5 @@ # This module defines the software packages included in the "minimal" -# installation CD. It might be useful elsewhere. +# installation CD. It might be useful elsewhere. { config, lib, pkgs, ... }: @@ -17,7 +17,6 @@ pkgs.ddrescue pkgs.ccrypt pkgs.cryptsetup # needed for dm-crypt volumes - pkgs.mkpasswd # for generating password files # Some text editors. (pkgs.vim.customize { @@ -32,7 +31,6 @@ pkgs.fuse pkgs.fuse3 pkgs.sshfs-fuse - pkgs.rsync pkgs.socat pkgs.screen pkgs.tcpdump @@ -45,22 +43,14 @@ pkgs.usbutils pkgs.nvme-cli - # Tools to create / manipulate filesystems. - pkgs.ntfsprogs # for resizing NTFS partitions - pkgs.dosfstools - pkgs.mtools - pkgs.xfsprogs.bin - pkgs.jfsutils - pkgs.f2fs-tools - # Some compression/archiver tools. pkgs.unzip pkgs.zip ]; - # Include support for various filesystems. + # Include support for various filesystems and tools to create / manipulate them. boot.supportedFilesystems = - [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" ] ++ + [ "btrfs" "cifs" "f2fs" "jfs" "ntfs" "reiserfs" "vfat" "xfs" ] ++ lib.optional (lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package) "zfs"; # Configure host id for ZFS to work diff --git a/nixos/modules/programs/ccache.nix b/nixos/modules/programs/ccache.nix index 19fb7ca3294e8..567c853e8c7de 100644 --- a/nixos/modules/programs/ccache.nix +++ b/nixos/modules/programs/ccache.nix @@ -17,7 +17,7 @@ in { type = types.listOf types.str; description = lib.mdDoc "Nix top-level packages to be compiled using CCache"; default = []; - example = [ "wxGTK30" "ffmpeg" "libav_all" ]; + example = [ "wxGTK32" "ffmpeg" "libav_all" ]; }; }; diff --git a/nixos/modules/programs/regreet.nix b/nixos/modules/programs/regreet.nix new file mode 100644 index 0000000000000..89b93737f4a27 --- /dev/null +++ b/nixos/modules/programs/regreet.nix @@ -0,0 +1,75 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.programs.regreet; + settingsFormat = pkgs.formats.toml { }; +in +{ + options.programs.regreet = { + enable = lib.mkEnableOption null // { + description = lib.mdDoc '' + Enable ReGreet, a clean and customizable greeter for greetd. + + To use ReGreet, {option}`services.greetd` has to be enabled and + {option}`services.greetd.settings.default_session` should contain the + appropriate configuration to launch + {option}`config.programs.regreet.package`. For examples, see the + [ReGreet Readme](https://github.com/rharish101/ReGreet#set-as-default-session). + + A minimal configuration that launches ReGreet in {command}`cage` is + enabled by this module by default. + ''; + }; + + package = lib.mkPackageOptionMD pkgs [ "greetd" "regreet" ] { }; + + settings = lib.mkOption { + type = lib.types.either lib.types.path settingsFormat.type; + default = { }; + description = lib.mdDoc '' + ReGreet configuration file. Refer + <https://github.com/rharish101/ReGreet/blob/main/regreet.sample.toml> + for options. + ''; + }; + + extraCss = lib.mkOption { + type = lib.types.either lib.types.path lib.types.lines; + default = ""; + description = lib.mdDoc '' + Extra CSS rules to apply on top of the GTK theme. Refer to + [GTK CSS Properties](https://docs.gtk.org/gtk4/css-properties.html) for + modifiable properties. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.greetd = { + enable = lib.mkDefault true; + settings.default_session.command = lib.mkDefault "${lib.getExe pkgs.cage} -s -- ${lib.getExe cfg.package}"; + }; + + environment.etc = { + "greetd/regreet.css" = + if lib.isPath cfg.extraCss + then {source = cfg.extraCss;} + else {text = cfg.extraCss;}; + + "greetd/regreet.toml".source = + if lib.isPath cfg.settings + then cfg.settings + else settingsFormat.generate "regreet.toml" cfg.settings; + }; + + systemd.tmpfiles.rules = let + user = config.services.greetd.settings.default_session.user; + in [ + "d /var/log/regreet 0755 greeter ${user} - -" + "d /var/cache/regreet 0755 greeter ${user} - -" + ]; + }; +} diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix index 3b8da78e2af5e..1ec698820a8b0 100644 --- a/nixos/modules/programs/ssh.nix +++ b/nixos/modules/programs/ssh.nix @@ -240,7 +240,7 @@ in [ ./known_hosts (writeText "github.keys" ''' - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl ''') diff --git a/nixos/modules/programs/starship.nix b/nixos/modules/programs/starship.nix index b56c0b2561649..cacad8eafe3da 100644 --- a/nixos/modules/programs/starship.nix +++ b/nixos/modules/programs/starship.nix @@ -9,10 +9,27 @@ let settingsFile = settingsFormat.generate "starship.toml" cfg.settings; -in { + initOption = + if cfg.interactiveOnly then + "promptInit" + else + "shellInit"; + +in +{ options.programs.starship = { enable = mkEnableOption (lib.mdDoc "the Starship shell prompt"); + interactiveOnly = mkOption { + default = true; + example = false; + type = types.bool; + description = lib.mdDoc '' + Whether to enable starship only when the shell is interactive. + Some plugins require this to be set to false to function correctly. + ''; + }; + settings = mkOption { inherit (settingsFormat) type; default = { }; @@ -25,21 +42,21 @@ in { }; config = mkIf cfg.enable { - programs.bash.promptInit = '' + programs.bash.${initOption} = '' if [[ $TERM != "dumb" && (-z $INSIDE_EMACS || $INSIDE_EMACS == "vterm") ]]; then export STARSHIP_CONFIG=${settingsFile} eval "$(${pkgs.starship}/bin/starship init bash)" fi ''; - programs.fish.promptInit = '' + programs.fish.${initOption} = '' if test "$TERM" != "dumb" -a \( -z "$INSIDE_EMACS" -o "$INSIDE_EMACS" = "vterm" \) set -x STARSHIP_CONFIG ${settingsFile} eval (${pkgs.starship}/bin/starship init fish) end ''; - programs.zsh.promptInit = '' + programs.zsh.${initOption} = '' if [[ $TERM != "dumb" && (-z $INSIDE_EMACS || $INSIDE_EMACS == "vterm") ]]; then export STARSHIP_CONFIG=${settingsFile} eval "$(${pkgs.starship}/bin/starship init zsh)" diff --git a/nixos/modules/programs/steam.nix b/nixos/modules/programs/steam.nix index 98269f6250dbf..fc63f0f187e87 100644 --- a/nixos/modules/programs/steam.nix +++ b/nixos/modules/programs/steam.nix @@ -9,23 +9,36 @@ in { enable = mkEnableOption (lib.mdDoc "steam"); package = mkOption { - type = types.package; - default = pkgs.steam.override { - extraLibraries = pkgs: with config.hardware.opengl; - if pkgs.stdenv.hostPlatform.is64bit - then [ package ] ++ extraPackages - else [ package32 ] ++ extraPackages32; - }; - defaultText = literalExpression '' - pkgs.steam.override { - extraLibraries = pkgs: with config.hardware.opengl; + type = types.package; + default = pkgs.steam; + defaultText = literalExpression "pkgs.steam"; + example = literalExpression '' + pkgs.steam-small.override { + extraEnv = { + MANGOHUD = true; + OBS_VKCAPTURE = true; + RADV_TEX_ANISO = 16; + }; + extraLibraries = p: with p; [ + atk + ]; + } + ''; + apply = steam: steam.override (prev: { + extraLibraries = pkgs: let + prevLibs = if prev ? extraLibraries then prev.extraLibraries pkgs else [ ]; + additionalLibs = with config.hardware.opengl; if pkgs.stdenv.hostPlatform.is64bit then [ package ] ++ extraPackages else [ package32 ] ++ extraPackages32; - } - ''; + in prevLibs ++ additionalLibs; + }); description = lib.mdDoc '' - steam package to use. + The Steam package to use. Additional libraries are added from the system + configuration to ensure graphics work properly. + + Use this option to customise the Steam package rather than adding your + custom Steam to {option}`environment.systemPackages` yourself. ''; }; diff --git a/nixos/modules/programs/wireshark.nix b/nixos/modules/programs/wireshark.nix index 088c2bb7958aa..834b0ba356955 100644 --- a/nixos/modules/programs/wireshark.nix +++ b/nixos/modules/programs/wireshark.nix @@ -33,7 +33,7 @@ in { security.wrappers.dumpcap = { source = "${wireshark}/bin/dumpcap"; - capabilities = "cap_net_raw+p"; + capabilities = "cap_net_raw,cap_net_admin+eip"; owner = "root"; group = "wireshark"; permissions = "u+rx,g+x"; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index d8a18cfcc6dc1..158c7934195be 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -44,6 +44,7 @@ with lib; The hidepid module was removed, since the underlying machinery is broken when using cgroups-v2. '') + (mkRemovedOptionModule [ "services" "baget" "enable" ] "The baget module was removed due to the upstream package being unmaintained.") (mkRemovedOptionModule [ "services" "beegfs" ] "The BeeGFS module has been removed") (mkRemovedOptionModule [ "services" "beegfsEnable" ] "The BeeGFS module has been removed") (mkRemovedOptionModule [ "services" "cgmanager" "enable"] "cgmanager was deprecated by lxc and therefore removed from nixpkgs.") @@ -106,6 +107,8 @@ with lib; (mkRemovedOptionModule [ "services" "riak" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "cryptpad" ] "The corresponding package was removed from nixpkgs.") + (mkRemovedOptionModule [ "i18n" "inputMethod" "fcitx" ] "The fcitx module has been removed. Plesae use fcitx5 instead") + # Do NOT add any option renames here, see top of the file ]; } diff --git a/nixos/modules/security/doas.nix b/nixos/modules/security/doas.nix index 4d15ed9a80259..115ca33efb5c5 100644 --- a/nixos/modules/security/doas.nix +++ b/nixos/modules/security/doas.nix @@ -19,7 +19,7 @@ let ]; mkArgs = rule: - if (isNull rule.args) then "" + if (rule.args == null) then "" else if (length rule.args == 0) then "args" else "args ${concatStringsSep " " rule.args}"; @@ -27,9 +27,9 @@ let let opts = mkOpts rule; - as = optionalString (!isNull rule.runAs) "as ${rule.runAs}"; + as = optionalString (rule.runAs != null) "as ${rule.runAs}"; - cmd = optionalString (!isNull rule.cmd) "cmd ${rule.cmd}"; + cmd = optionalString (rule.cmd != null) "cmd ${rule.cmd}"; args = mkArgs rule; in @@ -75,7 +75,9 @@ in {file}`/etc/doas.conf` file. More specific rules should come after more general ones in order to yield the expected behavior. You can use `mkBefore` and/or `mkAfter` to ensure - this is the case when configuration options are merged. + this is the case when configuration options are merged. Be aware that + this option cannot be used to override the behaviour allowing + passwordless operation for root. ''; example = literalExpression '' [ @@ -224,7 +226,9 @@ in type = with types; lines; default = ""; description = lib.mdDoc '' - Extra configuration text appended to {file}`doas.conf`. + Extra configuration text appended to {file}`doas.conf`. Be aware that + this option cannot be used to override the behaviour allowing + passwordless operation for root. ''; }; }; @@ -266,14 +270,14 @@ in # completely replace the contents of this file, use # `environment.etc."doas.conf"`. - # "root" is allowed to do anything. - permit nopass keepenv root - # extraRules ${concatStringsSep "\n" (lists.flatten (map mkRule cfg.extraRules))} # extraConfig ${cfg.extraConfig} + + # "root" is allowed to do anything. + permit nopass keepenv root ''; preferLocalBuild = true; } diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 4224722f8792c..6e8be412de83c 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -620,7 +620,7 @@ let optionalString config.services.homed.enable '' password sufficient ${config.systemd.package}/lib/security/pam_systemd_home.so '' + '' - password sufficient pam_unix.so nullok sha512 + password sufficient pam_unix.so nullok yescrypt '' + optionalString config.security.pam.enableEcryptfs '' password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so @@ -793,7 +793,7 @@ let }; })); - motd = if isNull config.users.motdFile + motd = if config.users.motdFile == null then pkgs.writeText "motd" config.users.motd else config.users.motdFile; @@ -1233,7 +1233,7 @@ in config = { assertions = [ { - assertion = isNull config.users.motd || isNull config.users.motdFile; + assertion = config.users.motd == null || config.users.motdFile == null; message = '' Only one of users.motd and users.motdFile can be set. ''; diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix index bc24e13aa050e..ca796cf7797e6 100644 --- a/nixos/modules/services/backup/restic.nix +++ b/nixos/modules/services/backup/restic.nix @@ -303,8 +303,8 @@ in then if (backup.paths != null) then concatStringsSep " " backup.paths else "" else "--files-from ${filesFromTmpFile}"; pruneCmd = optionals (builtins.length backup.pruneOpts > 0) [ - (resticCmd + " forget --prune --cache-dir=%C/restic-backups-${name} " + (concatStringsSep " " backup.pruneOpts)) - (resticCmd + " check --cache-dir=%C/restic-backups-${name} " + (concatStringsSep " " backup.checkOpts)) + (resticCmd + " forget --prune " + (concatStringsSep " " backup.pruneOpts)) + (resticCmd + " check " + (concatStringsSep " " backup.checkOpts)) ]; # Helper functions for rclone remotes rcloneRemoteName = builtins.elemAt (splitString ":" backup.repository) 1; @@ -314,6 +314,7 @@ in in nameValuePair "restic-backups-${name}" ({ environment = { + RESTIC_CACHE_DIR = "%C/restic-backups-${name}"; RESTIC_PASSWORD_FILE = backup.passwordFile; RESTIC_REPOSITORY = backup.repository; RESTIC_REPOSITORY_FILE = backup.repositoryFile; @@ -332,7 +333,7 @@ in restartIfChanged = false; serviceConfig = { Type = "oneshot"; - ExecStart = (optionals (backupPaths != "") [ "${resticCmd} backup --cache-dir=%C/restic-backups-${name} ${concatStringsSep " " (backup.extraBackupArgs ++ excludeFlags)} ${backupPaths}" ]) + ExecStart = (optionals (backupPaths != "") [ "${resticCmd} backup ${concatStringsSep " " (backup.extraBackupArgs ++ excludeFlags)} ${backupPaths}" ]) ++ pruneCmd; User = backup.user; RuntimeDirectory = "restic-backups-${name}"; diff --git a/nixos/modules/services/cluster/hadoop/hbase.nix b/nixos/modules/services/cluster/hadoop/hbase.nix index 97951ebfe3343..a39da2a84ecad 100644 --- a/nixos/modules/services/cluster/hadoop/hbase.nix +++ b/nixos/modules/services/cluster/hadoop/hbase.nix @@ -5,11 +5,95 @@ let cfg = config.services.hadoop; hadoopConf = "${import ./conf.nix { inherit cfg pkgs lib; }}/"; mkIfNotNull = x: mkIf (x != null) x; + # generic hbase role options + hbaseRoleOption = name: extraOpts: { + enable = mkEnableOption (mdDoc "HBase ${name}"); + + openFirewall = mkOption { + type = types.bool; + default = false; + description = mdDoc "Open firewall ports for HBase ${name}."; + }; + + restartIfChanged = mkOption { + type = types.bool; + default = false; + description = mdDoc "Restart ${name} con config change."; + }; + + extraFlags = mkOption { + type = with types; listOf str; + default = []; + example = literalExpression ''[ "--backup" ]''; + description = mdDoc "Extra flags for the ${name} service."; + }; + + environment = mkOption { + type = with types; attrsOf str; + default = {}; + example = literalExpression '' + { + HBASE_MASTER_OPTS = "-Dcom.sun.management.jmxremote.ssl=true"; + } + ''; + description = mdDoc "Environment variables passed to ${name}."; + }; + } // extraOpts; + # generic hbase role configs + hbaseRoleConfig = name: ports: (mkIf cfg.hbase."${name}".enable { + services.hadoop.gatewayRole = { + enable = true; + enableHbaseCli = mkDefault true; + }; + + systemd.services."hbase-${toLower name}" = { + description = "HBase ${name}"; + wantedBy = [ "multi-user.target" ]; + path = with cfg; [ hbase.package ] ++ optional + (with cfg.hbase.master; enable && initHDFS) package; + preStart = mkIf (with cfg.hbase.master; enable && initHDFS) + (concatStringsSep "\n" ( + map (x: "HADOOP_USER_NAME=hdfs hdfs --config /etc/hadoop-conf ${x}")[ + "dfsadmin -safemode wait" + "dfs -mkdir -p ${cfg.hbase.rootdir}" + "dfs -chown hbase ${cfg.hbase.rootdir}" + ] + )); + + inherit (cfg.hbase."${name}") environment; + script = concatStringsSep " " ( + [ + "hbase --config /etc/hadoop-conf/" + "${toLower name} start" + ] + ++ cfg.hbase."${name}".extraFlags + ++ map (x: "--${toLower x} ${toString cfg.hbase.${name}.${x}}") + (filter (x: hasAttr x cfg.hbase.${name}) ["port" "infoPort"]) + ); + + serviceConfig = { + User = "hbase"; + SyslogIdentifier = "hbase-${toLower name}"; + Restart = "always"; + }; + }; + + services.hadoop.hbaseSiteInternal."hbase.rootdir" = cfg.hbase.rootdir; + + networking = { + firewall.allowedTCPPorts = mkIf cfg.hbase."${name}".openFirewall ports; + hosts = mkIf (with cfg.hbase.regionServer; enable && overrideHosts) { + "127.0.0.2" = mkForce [ ]; + "::1" = mkForce [ ]; + }; + }; + + }); in { options.services.hadoop = { - gatewayRole.enableHbaseCli = mkEnableOption (lib.mdDoc "HBase CLI tools"); + gatewayRole.enableHbaseCli = mkEnableOption (mdDoc "HBase CLI tools"); hbaseSiteDefault = mkOption { default = { @@ -21,7 +105,7 @@ in "hbase.cluster.distributed" = "true"; }; type = types.attrsOf types.anything; - description = lib.mdDoc '' + description = mdDoc '' Default options for hbase-site.xml ''; }; @@ -29,8 +113,12 @@ in default = {}; type = with types; attrsOf anything; example = literalExpression '' + { + "hbase.hregion.max.filesize" = 20*1024*1024*1024; + "hbase.table.normalization.enabled" = "true"; + } ''; - description = lib.mdDoc '' + description = mdDoc '' Additional options and overrides for hbase-site.xml <https://github.com/apache/hbase/blob/rel/2.4.11/hbase-common/src/main/resources/hbase-default.xml> ''; @@ -39,7 +127,7 @@ in default = {}; type = with types; attrsOf anything; internal = true; - description = lib.mdDoc '' + description = mdDoc '' Internal option to add configs to hbase-site.xml based on module options ''; }; @@ -50,11 +138,11 @@ in type = types.package; default = pkgs.hbase; defaultText = literalExpression "pkgs.hbase"; - description = lib.mdDoc "HBase package"; + description = mdDoc "HBase package"; }; rootdir = mkOption { - description = lib.mdDoc '' + description = mdDoc '' This option will set "hbase.rootdir" in hbase-site.xml and determine the directory shared by region servers and into which HBase persists. The URL should be 'fully-qualified' to include the filesystem scheme. @@ -68,7 +156,7 @@ in default = "/hbase"; }; zookeeperQuorum = mkOption { - description = lib.mdDoc '' + description = mdDoc '' This option will set "hbase.zookeeper.quorum" in hbase-site.xml. Comma separated list of servers in the ZooKeeper ensemble. ''; @@ -76,107 +164,36 @@ in example = "zk1.internal,zk2.internal,zk3.internal"; default = null; }; - master = { - enable = mkEnableOption (lib.mdDoc "HBase Master"); - initHDFS = mkEnableOption (lib.mdDoc "initialization of the hbase directory on HDFS"); - - openFirewall = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Open firewall ports for HBase master. - ''; + } // (let + ports = port: infoPort: { + port = mkOption { + type = types.int; + default = port; + description = mdDoc "RPC port"; }; - }; - regionServer = { - enable = mkEnableOption (lib.mdDoc "HBase RegionServer"); - - overrideHosts = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Remove /etc/hosts entries for "127.0.0.2" and "::1" defined in nixos/modules/config/networking.nix - Regionservers must be able to resolve their hostnames to their IP addresses, through PTR records - or /etc/hosts entries. - - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Open firewall ports for HBase master. - ''; + infoPort = mkOption { + type = types.int; + default = infoPort; + description = mdDoc "web UI port"; }; }; - }; - }; - - config = mkMerge [ - (mkIf cfg.hbase.master.enable { - services.hadoop.gatewayRole = { - enable = true; - enableHbaseCli = mkDefault true; - }; - - systemd.services.hbase-master = { - description = "HBase master"; - wantedBy = [ "multi-user.target" ]; - - preStart = mkIf cfg.hbase.master.initHDFS '' - HADOOP_USER_NAME=hdfs ${cfg.package}/bin/hdfs --config ${hadoopConf} dfsadmin -safemode wait - HADOOP_USER_NAME=hdfs ${cfg.package}/bin/hdfs --config ${hadoopConf} dfs -mkdir -p ${cfg.hbase.rootdir} - HADOOP_USER_NAME=hdfs ${cfg.package}/bin/hdfs --config ${hadoopConf} dfs -chown hbase ${cfg.hbase.rootdir} + in mapAttrs hbaseRoleOption { + master.initHDFS = mkEnableOption (mdDoc "initialization of the hbase directory on HDFS"); + regionServer.overrideHosts = mkOption { + type = types.bool; + default = true; + description = mdDoc '' + Remove /etc/hosts entries for "127.0.0.2" and "::1" defined in nixos/modules/config/networking.nix + Regionservers must be able to resolve their hostnames to their IP addresses, through PTR records + or /etc/hosts entries. ''; - - serviceConfig = { - User = "hbase"; - SyslogIdentifier = "hbase-master"; - ExecStart = "${cfg.hbase.package}/bin/hbase --config ${hadoopConf} " + - "master start"; - Restart = "always"; - }; - }; - - services.hadoop.hbaseSiteInternal."hbase.rootdir" = cfg.hbase.rootdir; - - networking.firewall.allowedTCPPorts = mkIf cfg.hbase.master.openFirewall [ - 16000 16010 - ]; - - }) - - (mkIf cfg.hbase.regionServer.enable { - services.hadoop.gatewayRole = { - enable = true; - enableHbaseCli = mkDefault true; - }; - - systemd.services.hbase-regionserver = { - description = "HBase RegionServer"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "hbase"; - SyslogIdentifier = "hbase-regionserver"; - ExecStart = "${cfg.hbase.package}/bin/hbase --config /etc/hadoop-conf/ " + - "regionserver start"; - Restart = "always"; - }; }; + thrift = ports 9090 9095; + rest = ports 8080 8085; + }); + }; - services.hadoop.hbaseSiteInternal."hbase.rootdir" = cfg.hbase.rootdir; - - networking = { - firewall.allowedTCPPorts = mkIf cfg.hbase.regionServer.openFirewall [ - 16020 16030 - ]; - hosts = mkIf cfg.hbase.regionServer.overrideHosts { - "127.0.0.2" = mkForce [ ]; - "::1" = mkForce [ ]; - }; - }; - }) + config = mkMerge ([ (mkIf cfg.gatewayRole.enable { @@ -192,5 +209,10 @@ in isSystemUser = true; }; }) - ]; + ] ++ (mapAttrsToList hbaseRoleConfig { + master = [ 16000 16010 ]; + regionServer = [ 16020 16030 ]; + thrift = with cfg.hbase.thrift; [ port infoPort ]; + rest = with cfg.hbase.rest; [ port infoPort ]; + })); } diff --git a/nixos/modules/services/cluster/kubernetes/addons/dns.nix b/nixos/modules/services/cluster/kubernetes/addons/dns.nix index 3d41b5f008537..1c00329e6ccff 100644 --- a/nixos/modules/services/cluster/kubernetes/addons/dns.nix +++ b/nixos/modules/services/cluster/kubernetes/addons/dns.nix @@ -3,7 +3,7 @@ with lib; let - version = "1.7.1"; + version = "1.10.1"; cfg = config.services.kubernetes.addons.dns; ports = { dns = 10053; @@ -59,9 +59,9 @@ in { type = types.attrs; default = { imageName = "coredns/coredns"; - imageDigest = "sha256:4a6e0769130686518325b21b0c1d0688b54e7c79244d48e1b15634e98e40c6ef"; + imageDigest = "sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e"; finalImageTag = version; - sha256 = "02r440xcdsgi137k5lmmvp0z5w5fmk8g9mysq5pnysq1wl8sj6mw"; + sha256 = "0wg696920smmal7552a2zdhfncndn5kfammfa8bk8l7dz9bhk0y1"; }; }; @@ -136,6 +136,11 @@ in { resources = [ "nodes" ]; verbs = [ "get" ]; } + { + apiGroups = [ "discovery.k8s.io" ]; + resources = [ "endpointslices" ]; + verbs = [ "list" "watch" ]; + } ]; }; diff --git a/nixos/modules/services/cluster/kubernetes/pki.nix b/nixos/modules/services/cluster/kubernetes/pki.nix index 26fe0f5e9e097..38682701ea151 100644 --- a/nixos/modules/services/cluster/kubernetes/pki.nix +++ b/nixos/modules/services/cluster/kubernetes/pki.nix @@ -270,7 +270,7 @@ in ''; })]); - environment.etc.${cfg.etcClusterAdminKubeconfig}.source = mkIf (!isNull cfg.etcClusterAdminKubeconfig) + environment.etc.${cfg.etcClusterAdminKubeconfig}.source = mkIf (cfg.etcClusterAdminKubeconfig != null) clusterAdminKubeconfig; environment.systemPackages = mkIf (top.kubelet.enable || top.proxy.enable) [ diff --git a/nixos/modules/services/continuous-integration/woodpecker/agents.nix b/nixos/modules/services/continuous-integration/woodpecker/agents.nix new file mode 100644 index 0000000000000..caf6c85093424 --- /dev/null +++ b/nixos/modules/services/continuous-integration/woodpecker/agents.nix @@ -0,0 +1,144 @@ +{ config +, lib +, pkgs +, ... +}: + +let + cfg = config.services.woodpecker-agents; + + agentModule = lib.types.submodule { + options = { + enable = lib.mkEnableOption (lib.mdDoc "this Woodpecker-Agent. Agents execute tasks generated by a Server, every install will need one server and at least one agent"); + + package = lib.mkPackageOptionMD pkgs "woodpecker-agent" { }; + + environment = lib.mkOption { + default = { }; + type = lib.types.attrsOf lib.types.str; + example = lib.literalExpression '' + { + WOODPECKER_SERVER = "localhost:9000"; + WOODPECKER_BACKEND = "docker"; + DOCKER_HOST = "unix:///run/podman/podman.sock"; + } + ''; + description = lib.mdDoc "woodpecker-agent config envrionment variables, for other options read the [documentation](https://woodpecker-ci.org/docs/administration/agent-config)"; + }; + + extraGroups = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ "podman" ]; + description = lib.mdDoc '' + Additional groups for the systemd service. + ''; + }; + + environmentFile = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = [ ]; + example = [ "/var/secrets/woodpecker-agent.env" ]; + description = lib.mdDoc '' + File to load environment variables + from. This is helpful for specifying secrets. + Example content of environmentFile: + ``` + WOODPECKER_AGENT_SECRET=your-shared-secret-goes-here + ``` + ''; + }; + }; + }; + + mkAgentService = name: agentCfg: { + name = "woodpecker-agent-${name}"; + value = { + description = "Woodpecker-Agent Service - ${name}"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + serviceConfig = { + DynamicUser = true; + SupplementaryGroups = agentCfg.extraGroups; + EnvironmentFile = agentCfg.environmentFile; + ExecStart = lib.getExe agentCfg.package; + Restart = "on-failure"; + RestartSec = 15; + CapabilityBoundingSet = ""; + NoNewPrivileges = true; + ProtectSystem = "strict"; + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = true; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ "AF_UNIX AF_INET AF_INET6" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + PrivateMounts = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "~@clock @privileged @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @setuid @swap"; + BindReadOnlyPaths = [ + "-/etc/resolv.conf" + "-/etc/nsswitch.conf" + "-/etc/ssl/certs" + "-/etc/static/ssl/certs" + "-/etc/hosts" + "-/etc/localtime" + ]; + }; + inherit (agentCfg) environment; + }; + }; +in +{ + meta.maintainers = with lib.maintainers; [ janik ambroisie ]; + + options = { + services.woodpecker-agents = { + agents = lib.mkOption { + default = { }; + type = lib.types.attrsOf agentModule; + example = { + docker = { + environment = { + WOODPECKER_SERVER = "localhost:9000"; + WOODPECKER_BACKEND = "docker"; + DOCKER_HOST = "unix:///run/podman/podman.sock"; + }; + + extraGroups = [ "docker" ]; + + environmentFile = "/run/secrets/woodpecker/agent-secret.txt"; + }; + + exec = { + environment = { + WOODPECKER_SERVER = "localhost:9000"; + WOODPECKER_BACKEND = "exec"; + }; + + environmentFile = "/run/secrets/woodpecker/agent-secret.txt"; + }; + }; + description = lib.mdDoc "woodpecker-agents configurations"; + }; + }; + }; + + config = { + systemd.services = + let + mkServices = lib.mapAttrs' mkAgentService; + enabledAgents = lib.filterAttrs (_: agent: agent.enable) cfg.agents; + in + mkServices enabledAgents; + }; +} diff --git a/nixos/modules/services/continuous-integration/woodpecker/server.nix b/nixos/modules/services/continuous-integration/woodpecker/server.nix new file mode 100644 index 0000000000000..be7786da8505f --- /dev/null +++ b/nixos/modules/services/continuous-integration/woodpecker/server.nix @@ -0,0 +1,98 @@ +{ config +, lib +, pkgs +, ... +}: + +let + cfg = config.services.woodpecker-server; +in +{ + meta.maintainers = with lib.maintainers; [ janik ambroisie ]; + + + options = { + services.woodpecker-server = { + enable = lib.mkEnableOption (lib.mdDoc "the Woodpecker-Server, a CI/CD application for automatic builds, deployments and tests"); + package = lib.mkPackageOptionMD pkgs "woodpecker-server" { }; + environment = lib.mkOption { + default = { }; + type = lib.types.attrsOf lib.types.str; + example = lib.literalExpression + '' + { + WOODPECKER_HOST = "https://woodpecker.example.com"; + WOODPECKER_OPEN = "true"; + WOODPECKER_GITEA = "true"; + WOODPECKER_GITEA_CLIENT = "ffffffff-ffff-ffff-ffff-ffffffffffff"; + WOODPECKER_GITEA_URL = "https://git.example.com"; + } + ''; + description = lib.mdDoc "woodpecker-server config envrionment variables, for other options read the [documentation](https://woodpecker-ci.org/docs/administration/server-config)"; + }; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/root/woodpecker-server.env"; + description = lib.mdDoc '' + File to load environment variables + from. This is helpful for specifying secrets. + Example content of environmentFile: + ``` + WOODPECKER_AGENT_SECRET=your-shared-secret-goes-here + WOODPECKER_GITEA_SECRET=gto_************************************** + ``` + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services = { + woodpecker-server = { + description = "Woodpecker-Server Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + serviceConfig = { + DynamicUser = true; + WorkingDirectory = "%S/woodpecker-server"; + StateDirectory = "woodpecker-server"; + StateDirectoryMode = "0700"; + UMask = "0007"; + ConfigurationDirectory = "woodpecker-server"; + EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile; + ExecStart = "${cfg.package}/bin/woodpecker-server"; + Restart = "on-failure"; + RestartSec = 15; + CapabilityBoundingSet = ""; + # Security + NoNewPrivileges = true; + # Sandboxing + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = true; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ "AF_UNIX AF_INET AF_INET6" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + PrivateMounts = true; + # System Call Filtering + SystemCallArchitectures = "native"; + SystemCallFilter = "~@clock @privileged @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @setuid @swap"; + }; + inherit (cfg) environment; + }; + }; + }; +} + diff --git a/nixos/modules/services/databases/dgraph.nix b/nixos/modules/services/databases/dgraph.nix index 887164fa5b943..7f005a9971a69 100644 --- a/nixos/modules/services/databases/dgraph.nix +++ b/nixos/modules/services/databases/dgraph.nix @@ -12,7 +12,7 @@ let '' mkdir -p $out/bin makeWrapper ${cfg.package}/bin/dgraph $out/bin/dgraph \ - --set PATH '${lib.makeBinPath [ pkgs.nodejs ]}:$PATH' \ + --prefix PATH : "${lib.makeBinPath [ pkgs.nodejs ]}" \ ''; securityOptions = { NoNewPrivileges = true; diff --git a/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json b/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json deleted file mode 100644 index c204606193af5..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "context.properties": { - "log.level": 0 - }, - "context.spa-libs": { - "audio.convert.*": "audioconvert/libspa-audioconvert", - "support.*": "support/libspa-support" - }, - "context.modules": [ - { - "name": "libpipewire-module-rt", - "args": {}, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-client-device" - }, - { - "name": "libpipewire-module-adapter" - }, - { - "name": "libpipewire-module-metadata" - }, - { - "name": "libpipewire-module-session-manager" - } - ], - "filter.properties": {}, - "stream.properties": {}, - "alsa.properties": {}, - "alsa.rules": [ - { - "matches": [ - { - "application.process.binary": "resolve" - } - ], - "actions": { - "update-props": { - "alsa.buffer-bytes": 131072 - } - } - } - ] -} diff --git a/nixos/modules/services/desktops/pipewire/daemon/client.conf.json b/nixos/modules/services/desktops/pipewire/daemon/client.conf.json deleted file mode 100644 index 71294a0e78a2d..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/client.conf.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "context.properties": { - "log.level": 0 - }, - "context.spa-libs": { - "audio.convert.*": "audioconvert/libspa-audioconvert", - "support.*": "support/libspa-support" - }, - "context.modules": [ - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-client-device" - }, - { - "name": "libpipewire-module-adapter" - }, - { - "name": "libpipewire-module-metadata" - }, - { - "name": "libpipewire-module-session-manager" - } - ], - "filter.properties": {}, - "stream.properties": {} -} diff --git a/nixos/modules/services/desktops/pipewire/daemon/filter-chain.conf.json b/nixos/modules/services/desktops/pipewire/daemon/filter-chain.conf.json deleted file mode 100644 index 689fca88359ba..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/filter-chain.conf.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "context.properties": { - "log.level": 0 - }, - "context.spa-libs": { - "audio.convert.*": "audioconvert/libspa-audioconvert", - "support.*": "support/libspa-support" - }, - "context.modules": [ - { - "name": "libpipewire-module-rt", - "args": {}, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-adapter" - } - ] -} diff --git a/nixos/modules/services/desktops/pipewire/daemon/jack.conf.json b/nixos/modules/services/desktops/pipewire/daemon/jack.conf.json deleted file mode 100644 index f2e396dd28d76..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/jack.conf.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "context.properties": { - "log.level": 0 - }, - "context.spa-libs": { - "support.*": "support/libspa-support" - }, - "context.modules": [ - { - "name": "libpipewire-module-rt", - "args": {}, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-metadata" - } - ], - "jack.properties": {}, - "jack.rules": [ - { - "matches": [ - {} - ], - "actions": { - "update-props": {} - } - }, - { - "matches": [ - { - "application.process.binary": "jack_bufsize" - } - ], - "actions": { - "update-props": { - "jack.global-buffer-size": true - } - } - }, - { - "matches": [ - { - "application.process.binary": "qsynth" - } - ], - "actions": { - "update-props": { - "node.pause-on-idle": false, - "node.passive": true - } - } - }, - { - "matches": [ - { - "client.name": "Mixxx" - } - ], - "actions": { - "update-props": { - "jack.merge-monitor": false - } - } - } - ] -} diff --git a/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json b/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json deleted file mode 100644 index 0f1ebe5749c67..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "context.properties": { - "link.max-buffers": 16, - "core.daemon": true, - "core.name": "pipewire-0", - "settings.check-quantum": true, - "settings.check-rate": true, - "vm.overrides": { - "default.clock.min-quantum": 1024 - } - }, - "context.spa-libs": { - "audio.convert.*": "audioconvert/libspa-audioconvert", - "api.alsa.*": "alsa/libspa-alsa", - "support.*": "support/libspa-support" - }, - "context.modules": [ - { - "name": "libpipewire-module-rt", - "args": { - "nice.level": -11 - }, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-profiler" - }, - { - "name": "libpipewire-module-metadata" - }, - { - "name": "libpipewire-module-spa-node-factory" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-access", - "args": {} - }, - { - "name": "libpipewire-module-adapter" - }, - { - "name": "libpipewire-module-link-factory" - } - ], - "context.objects": [ - { - "factory": "metadata", - "args": { - "metadata.name": "default" - } - }, - { - "factory": "spa-node-factory", - "args": { - "factory.name": "support.node.driver", - "node.name": "Dummy-Driver", - "node.group": "pipewire.dummy", - "priority.driver": 20000 - } - }, - { - "factory": "spa-node-factory", - "args": { - "factory.name": "support.node.driver", - "node.name": "Freewheel-Driver", - "priority.driver": 19000, - "node.group": "pipewire.freewheel", - "node.freewheel": true - } - }, - { - "factory": "adapter", - "args": { - "factory.name": "api.alsa.pcm.source", - "node.name": "system", - "node.description": "system", - "media.class": "Audio/Source", - "api.alsa.path": "hw:0", - "node.suspend-on-idle": true, - "resample.disable": true, - "channelmix.disable": true, - "adapter.auto-port-config": { - "mode": "dsp", - "monitor": false, - "control": false, - "position": "unknown" - } - } - }, - { - "factory": "adapter", - "args": { - "factory.name": "api.alsa.pcm.sink", - "node.name": "system", - "node.description": "system", - "media.class": "Audio/Sink", - "api.alsa.path": "hw:0", - "node.suspend-on-idle": true, - "resample.disable": true, - "channelmix.disable": true, - "adapter.auto-port-config": { - "mode": "dsp", - "monitor": false, - "control": false, - "position": "unknown" - } - } - } - ], - "context.exec": [] -} diff --git a/nixos/modules/services/desktops/pipewire/daemon/pipewire-aes67.conf.json b/nixos/modules/services/desktops/pipewire/daemon/pipewire-aes67.conf.json deleted file mode 100644 index aaffa93ca964c..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/pipewire-aes67.conf.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "context.properties": {}, - "context.modules": [ - { - "name": "libpipewire-module-rt", - "args": { - "nice.level": -11 - }, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-adapter" - }, - { - "name": "libpipewire-module-rtp-source", - "args": { - "sap.ip": "239.255.255.255", - "sap.port": 9875, - "sess.latency.msec": 10, - "local.ifname": "eth0", - "stream.props": { - "media.class": "Audio/Source", - "node.virtual": false, - "device.api": "aes67" - } - } - } - ] -} diff --git a/nixos/modules/services/desktops/pipewire/daemon/pipewire-avb.conf.json b/nixos/modules/services/desktops/pipewire/daemon/pipewire-avb.conf.json deleted file mode 100644 index 4f669895d87b6..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/pipewire-avb.conf.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "context.properties": {}, - "context.spa-libs": { - "audio.convert.*": "audioconvert/libspa-audioconvert", - "support.*": "support/libspa-support" - }, - "context.modules": [ - { - "name": "libpipewire-module-rt", - "args": { - "nice.level": -11 - }, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-adapter" - }, - { - "name": "libpipewire-module-avb", - "args": {} - } - ], - "context.exec": [], - "stream.properties": {}, - "avb.properties": { - "ifname": "enp3s0", - "vm.overrides": {} - } -} diff --git a/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json b/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json deleted file mode 100644 index b1a864853325c..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "context.properties": {}, - "context.spa-libs": { - "audio.convert.*": "audioconvert/libspa-audioconvert", - "support.*": "support/libspa-support" - }, - "context.modules": [ - { - "name": "libpipewire-module-rt", - "args": { - "nice.level": -11 - }, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-adapter" - }, - { - "name": "libpipewire-module-metadata" - }, - { - "name": "libpipewire-module-protocol-pulse", - "args": {} - } - ], - "context.exec": [], - "pulse.cmd": [ - { - "cmd": "load-module", - "args": "module-always-sink", - "flags": [] - } - ], - "stream.properties": {}, - "pulse.properties": { - "server.address": [ - "unix:native" - ], - "vm.overrides": { - "pulse.min.quantum": "1024/48000" - } - }, - "pulse.rules": [ - { - "matches": [ - {} - ], - "actions": { - "update-props": {} - } - }, - { - "matches": [ - { - "application.process.binary": "teams" - }, - { - "application.process.binary": "teams-insiders" - }, - { - "application.process.binary": "skypeforlinux" - } - ], - "actions": { - "quirks": [ - "force-s16-info" - ] - } - }, - { - "matches": [ - { - "application.process.binary": "firefox" - } - ], - "actions": { - "quirks": [ - "remove-capture-dont-move" - ] - } - }, - { - "matches": [ - { - "application.name": "~speech-dispatcher.*" - } - ], - "actions": { - "update-props": { - "pulse.min.req": "512/48000", - "pulse.min.quantum": "512/48000", - "pulse.idle.timeout": 5 - } - } - } - ] -} diff --git a/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json b/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json deleted file mode 100644 index a47abe2213d94..0000000000000 --- a/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "context.properties": { - "link.max-buffers": 16, - "core.daemon": true, - "core.name": "pipewire-0", - "vm.overrides": { - "default.clock.min-quantum": 1024 - }, - "module.x11.bell": true - }, - "context.spa-libs": { - "audio.convert.*": "audioconvert/libspa-audioconvert", - "avb.*": "avb/libspa-avb", - "api.alsa.*": "alsa/libspa-alsa", - "api.v4l2.*": "v4l2/libspa-v4l2", - "api.libcamera.*": "libcamera/libspa-libcamera", - "api.bluez5.*": "bluez5/libspa-bluez5", - "api.vulkan.*": "vulkan/libspa-vulkan", - "api.jack.*": "jack/libspa-jack", - "support.*": "support/libspa-support" - }, - "context.modules": [ - { - "name": "libpipewire-module-rt", - "args": { - "nice.level": -11 - }, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-profiler" - }, - { - "name": "libpipewire-module-metadata" - }, - { - "name": "libpipewire-module-spa-device-factory" - }, - { - "name": "libpipewire-module-spa-node-factory" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-client-device" - }, - { - "name": "libpipewire-module-portal", - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-access", - "args": {} - }, - { - "name": "libpipewire-module-adapter" - }, - { - "name": "libpipewire-module-link-factory" - }, - { - "name": "libpipewire-module-session-manager" - }, - { - "name": "libpipewire-module-x11-bell", - "args": {}, - "flags": [ - "ifexists", - "nofail" - ], - "condition": [ - { - "module.x11.bell": true - } - ] - } - ], - "context.objects": [ - { - "factory": "spa-node-factory", - "args": { - "factory.name": "support.node.driver", - "node.name": "Dummy-Driver", - "node.group": "pipewire.dummy", - "priority.driver": 20000 - } - }, - { - "factory": "spa-node-factory", - "args": { - "factory.name": "support.node.driver", - "node.name": "Freewheel-Driver", - "priority.driver": 19000, - "node.group": "pipewire.freewheel", - "node.freewheel": true - } - } - ], - "context.exec": [] -} diff --git a/nixos/modules/services/desktops/pipewire/media-session/alsa-monitor.conf.json b/nixos/modules/services/desktops/pipewire/media-session/alsa-monitor.conf.json deleted file mode 100644 index 53fc9cc96343b..0000000000000 --- a/nixos/modules/services/desktops/pipewire/media-session/alsa-monitor.conf.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "properties": {}, - "rules": [ - { - "matches": [ - { - "device.name": "~alsa_card.*" - } - ], - "actions": { - "update-props": { - "api.alsa.use-acp": true, - "api.acp.auto-profile": false, - "api.acp.auto-port": false - } - } - }, - { - "matches": [ - { - "node.name": "~alsa_input.*" - }, - { - "node.name": "~alsa_output.*" - } - ], - "actions": { - "update-props": { - "node.pause-on-idle": false - } - } - } - ] -} diff --git a/nixos/modules/services/desktops/pipewire/media-session/bluez-monitor.conf.json b/nixos/modules/services/desktops/pipewire/media-session/bluez-monitor.conf.json deleted file mode 100644 index 6d1c23e825699..0000000000000 --- a/nixos/modules/services/desktops/pipewire/media-session/bluez-monitor.conf.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "properties": {}, - "rules": [ - { - "matches": [ - { - "device.name": "~bluez_card.*" - } - ], - "actions": { - "update-props": { - "bluez5.auto-connect": [ - "hfp_hf", - "hsp_hs", - "a2dp_sink" - ] - } - } - }, - { - "matches": [ - { - "node.name": "~bluez_input.*" - }, - { - "node.name": "~bluez_output.*" - } - ], - "actions": { - "update-props": { - "node.pause-on-idle": false - } - } - } - ] -} diff --git a/nixos/modules/services/desktops/pipewire/media-session/media-session.conf.json b/nixos/modules/services/desktops/pipewire/media-session/media-session.conf.json deleted file mode 100644 index 4b4e302af3876..0000000000000 --- a/nixos/modules/services/desktops/pipewire/media-session/media-session.conf.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "context.properties": {}, - "context.spa-libs": { - "api.bluez5.*": "bluez5/libspa-bluez5", - "api.alsa.*": "alsa/libspa-alsa", - "api.v4l2.*": "v4l2/libspa-v4l2", - "api.libcamera.*": "libcamera/libspa-libcamera" - }, - "context.modules": [ - { - "name": "libpipewire-module-rtkit", - "args": {}, - "flags": [ - "ifexists", - "nofail" - ] - }, - { - "name": "libpipewire-module-protocol-native" - }, - { - "name": "libpipewire-module-client-node" - }, - { - "name": "libpipewire-module-client-device" - }, - { - "name": "libpipewire-module-adapter" - }, - { - "name": "libpipewire-module-metadata" - }, - { - "name": "libpipewire-module-session-manager" - } - ], - "session.modules": { - "default": [ - "flatpak", - "portal", - "v4l2", - "suspend-node", - "policy-node" - ], - "with-audio": [ - "metadata", - "default-nodes", - "default-profile", - "default-routes", - "alsa-seq", - "alsa-monitor" - ], - "with-alsa": [ - "with-audio" - ], - "with-jack": [ - "with-audio" - ], - "with-pulseaudio": [ - "with-audio", - "bluez5", - "bluez5-autoswitch", - "logind", - "restore-stream", - "streams-follow-default" - ] - } -} diff --git a/nixos/modules/services/desktops/pipewire/media-session/v4l2-monitor.conf.json b/nixos/modules/services/desktops/pipewire/media-session/v4l2-monitor.conf.json deleted file mode 100644 index b08cba1b604b5..0000000000000 --- a/nixos/modules/services/desktops/pipewire/media-session/v4l2-monitor.conf.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "properties": {}, - "rules": [ - { - "matches": [ - { - "device.name": "~v4l2_device.*" - } - ], - "actions": { - "update-props": {} - } - }, - { - "matches": [ - { - "node.name": "~v4l2_input.*" - }, - { - "node.name": "~v4l2_output.*" - } - ], - "actions": { - "update-props": { - "node.pause-on-idle": false - } - } - } - ] -} diff --git a/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix b/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix deleted file mode 100644 index 203139294c6b5..0000000000000 --- a/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix +++ /dev/null @@ -1,141 +0,0 @@ -# pipewire example session manager. -{ config, lib, pkgs, ... }: - -with lib; - -let - json = pkgs.formats.json {}; - cfg = config.services.pipewire.media-session; - enable32BitAlsaPlugins = cfg.alsa.support32Bit - && pkgs.stdenv.isx86_64 - && pkgs.pkgsi686Linux.pipewire != null; - - # Use upstream config files passed through spa-json-dump as the base - # Patched here as necessary for them to work with this module - defaults = { - alsa-monitor = lib.importJSON ./media-session/alsa-monitor.conf.json; - bluez-monitor = lib.importJSON ./media-session/bluez-monitor.conf.json; - media-session = lib.importJSON ./media-session/media-session.conf.json; - v4l2-monitor = lib.importJSON ./media-session/v4l2-monitor.conf.json; - }; - - configs = { - alsa-monitor = recursiveUpdate defaults.alsa-monitor cfg.config.alsa-monitor; - bluez-monitor = recursiveUpdate defaults.bluez-monitor cfg.config.bluez-monitor; - media-session = recursiveUpdate defaults.media-session cfg.config.media-session; - v4l2-monitor = recursiveUpdate defaults.v4l2-monitor cfg.config.v4l2-monitor; - }; -in { - - meta = { - maintainers = teams.freedesktop.members; - # uses attributes of the linked package - buildDocsInSandbox = false; - }; - - ###### interface - options = { - services.pipewire.media-session = { - enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Whether to enable the deprecated example Pipewire session manager"; - }; - - package = mkOption { - type = types.package; - default = pkgs.pipewire-media-session; - defaultText = literalExpression "pkgs.pipewire-media-session"; - description = lib.mdDoc '' - The pipewire-media-session derivation to use. - ''; - }; - - config = { - media-session = mkOption { - type = json.type; - description = lib.mdDoc '' - Configuration for the media session core. For details see - https://gitlab.freedesktop.org/pipewire/media-session/-/blob/${cfg.package.version}/src/daemon/media-session.d/media-session.conf - ''; - default = defaults.media-session; - }; - - alsa-monitor = mkOption { - type = json.type; - description = lib.mdDoc '' - Configuration for the alsa monitor. For details see - https://gitlab.freedesktop.org/pipewire/media-session/-/blob/${cfg.package.version}/src/daemon/media-session.d/alsa-monitor.conf - ''; - default = defaults.alsa-monitor; - }; - - bluez-monitor = mkOption { - type = json.type; - description = lib.mdDoc '' - Configuration for the bluez5 monitor. For details see - https://gitlab.freedesktop.org/pipewire/media-session/-/blob/${cfg.package.version}/src/daemon/media-session.d/bluez-monitor.conf - ''; - default = defaults.bluez-monitor; - }; - - v4l2-monitor = mkOption { - type = json.type; - description = lib.mdDoc '' - Configuration for the V4L2 monitor. For details see - https://gitlab.freedesktop.org/pipewire/media-session/-/blob/${cfg.package.version}/src/daemon/media-session.d/v4l2-monitor.conf - ''; - default = defaults.v4l2-monitor; - }; - }; - }; - }; - - ###### implementation - config = mkIf cfg.enable { - environment.systemPackages = [ cfg.package ]; - systemd.packages = [ cfg.package ]; - - # Enable either system or user units. - systemd.services.pipewire-media-session.enable = config.services.pipewire.systemWide; - systemd.user.services.pipewire-media-session.enable = !config.services.pipewire.systemWide; - - systemd.services.pipewire-media-session.wantedBy = [ "pipewire.service" ]; - systemd.user.services.pipewire-media-session.wantedBy = [ "pipewire.service" ]; - - environment.etc."pipewire/media-session.d/media-session.conf" = { - source = json.generate "media-session.conf" configs.media-session; - }; - environment.etc."pipewire/media-session.d/v4l2-monitor.conf" = { - source = json.generate "v4l2-monitor.conf" configs.v4l2-monitor; - }; - - environment.etc."pipewire/media-session.d/with-audio" = - mkIf config.services.pipewire.audio.enable { - text = ""; - }; - - environment.etc."pipewire/media-session.d/with-alsa" = - mkIf config.services.pipewire.alsa.enable { - text = ""; - }; - environment.etc."pipewire/media-session.d/alsa-monitor.conf" = - mkIf config.services.pipewire.alsa.enable { - source = json.generate "alsa-monitor.conf" configs.alsa-monitor; - }; - - environment.etc."pipewire/media-session.d/with-pulseaudio" = - mkIf config.services.pipewire.pulse.enable { - text = ""; - }; - environment.etc."pipewire/media-session.d/bluez-monitor.conf" = - mkIf config.services.pipewire.pulse.enable { - source = json.generate "bluez-monitor.conf" configs.bluez-monitor; - }; - - environment.etc."pipewire/media-session.d/with-jack" = - mkIf config.services.pipewire.jack.enable { - text = ""; - }; - }; -} diff --git a/nixos/modules/services/desktops/pipewire/pipewire.nix b/nixos/modules/services/desktops/pipewire/pipewire.nix index 09cec9a791091..ae695baf42c60 100644 --- a/nixos/modules/services/desktops/pipewire/pipewire.nix +++ b/nixos/modules/services/desktops/pipewire/pipewire.nix @@ -4,7 +4,6 @@ with lib; let - json = pkgs.formats.json {}; cfg = config.services.pipewire; enable32BitAlsaPlugins = cfg.alsa.support32Bit && pkgs.stdenv.isx86_64 @@ -18,34 +17,8 @@ let mkdir -p "$out/lib" ln -s "${cfg.package.jack}/lib" "$out/lib/pipewire" ''; - - # Use upstream config files passed through spa-json-dump as the base - # Patched here as necessary for them to work with this module - defaults = { - client = lib.importJSON ./daemon/client.conf.json; - client-rt = lib.importJSON ./daemon/client-rt.conf.json; - jack = lib.importJSON ./daemon/jack.conf.json; - minimal = lib.importJSON ./daemon/minimal.conf.json; - pipewire = lib.importJSON ./daemon/pipewire.conf.json; - pipewire-pulse = lib.importJSON ./daemon/pipewire-pulse.conf.json; - }; - - useSessionManager = cfg.wireplumber.enable || cfg.media-session.enable; - - configs = { - client = recursiveUpdate defaults.client cfg.config.client; - client-rt = recursiveUpdate defaults.client-rt cfg.config.client-rt; - jack = recursiveUpdate defaults.jack cfg.config.jack; - pipewire = recursiveUpdate (if useSessionManager then defaults.pipewire else defaults.minimal) cfg.config.pipewire; - pipewire-pulse = recursiveUpdate defaults.pipewire-pulse cfg.config.pipewire-pulse; - }; in { - - meta = { - maintainers = teams.freedesktop.members ++ [ lib.maintainers.k900 ]; - # uses attributes of the linked package - buildDocsInSandbox = false; - }; + meta.maintainers = teams.freedesktop.members ++ [ lib.maintainers.k900 ]; ###### interface options = { @@ -69,53 +42,6 @@ in { ''; }; - config = { - client = mkOption { - type = json.type; - default = {}; - description = lib.mdDoc '' - Configuration for pipewire clients. For details see - https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/${cfg.package.version}/src/daemon/client.conf.in - ''; - }; - - client-rt = mkOption { - type = json.type; - default = {}; - description = lib.mdDoc '' - Configuration for realtime pipewire clients. For details see - https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/${cfg.package.version}/src/daemon/client-rt.conf.in - ''; - }; - - jack = mkOption { - type = json.type; - default = {}; - description = lib.mdDoc '' - Configuration for the pipewire daemon's jack module. For details see - https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/${cfg.package.version}/src/daemon/jack.conf.in - ''; - }; - - pipewire = mkOption { - type = json.type; - default = {}; - description = lib.mdDoc '' - Configuration for the pipewire daemon. For details see - https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/${cfg.package.version}/src/daemon/pipewire.conf.in - ''; - }; - - pipewire-pulse = mkOption { - type = json.type; - default = {}; - description = lib.mdDoc '' - Configuration for the pipewire-pulse daemon. For details see - https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/${cfg.package.version}/src/daemon/pipewire-pulse.conf.in - ''; - }; - }; - audio = { enable = lib.mkOption { type = lib.types.bool; @@ -153,10 +79,20 @@ in { https://github.com/PipeWire/pipewire/blob/master/NEWS ''; }; - }; }; + imports = [ + (lib.mkRemovedOptionModule ["services" "pipewire" "config"] '' + Overriding default Pipewire configuration through NixOS options never worked correctly and is no longer supported. + Please create drop-in files in /etc/pipewire/pipewire.conf.d/ to make the desired setting changes instead. + '') + + (lib.mkRemovedOptionModule ["services" "pipewire" "media-session"] '' + pipewire-media-session is no longer supported upstream and has been removed. + Please switch to `services.pipewire.wireplumber` instead. + '') + ]; ###### implementation config = mkIf cfg.enable { @@ -222,22 +158,6 @@ in { source = "${cfg.package}/share/alsa/alsa.conf.d/99-pipewire-default.conf"; }; - environment.etc."pipewire/client.conf" = { - source = json.generate "client.conf" configs.client; - }; - environment.etc."pipewire/client-rt.conf" = { - source = json.generate "client-rt.conf" configs.client-rt; - }; - environment.etc."pipewire/jack.conf" = { - source = json.generate "jack.conf" configs.jack; - }; - environment.etc."pipewire/pipewire.conf" = { - source = json.generate "pipewire.conf" configs.pipewire; - }; - environment.etc."pipewire/pipewire-pulse.conf" = mkIf cfg.pulse.enable { - source = json.generate "pipewire-pulse.conf" configs.pipewire-pulse; - }; - environment.sessionVariables.LD_LIBRARY_PATH = lib.mkIf cfg.jack.enable [ "${cfg.package.jack}/lib" ]; @@ -256,12 +176,5 @@ in { }; groups.pipewire.gid = config.ids.gids.pipewire; }; - - # https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/464#note_723554 - systemd.services.pipewire.environment."PIPEWIRE_LINK_PASSIVE" = "1"; - systemd.user.services.pipewire.environment."PIPEWIRE_LINK_PASSIVE" = "1"; - - # pipewire-pulse default config expects pactl to be in PATH - systemd.user.services.pipewire-pulse.path = lib.mkIf cfg.pulse.enable [ pkgs.pulseaudio ]; }; } diff --git a/nixos/modules/services/desktops/pipewire/wireplumber.nix b/nixos/modules/services/desktops/pipewire/wireplumber.nix index 4b36b99aa7c1e..95a7ece26c5d2 100644 --- a/nixos/modules/services/desktops/pipewire/wireplumber.nix +++ b/nixos/modules/services/desktops/pipewire/wireplumber.nix @@ -29,10 +29,6 @@ in config = lib.mkIf cfg.enable { assertions = [ { - assertion = !config.services.pipewire.media-session.enable; - message = "WirePlumber and pipewire-media-session can't be enabled at the same time."; - } - { assertion = !config.hardware.bluetooth.hsphfpd.enable; message = "Using Wireplumber conflicts with hsphfpd, as it provides the same functionality. `hardware.bluetooth.hsphfpd.enable` needs be set to false"; } diff --git a/nixos/modules/services/hardware/kanata.nix b/nixos/modules/services/hardware/kanata.nix index bb730037277b8..7d544050130b9 100644 --- a/nixos/modules/services/hardware/kanata.nix +++ b/nixos/modules/services/hardware/kanata.nix @@ -86,6 +86,7 @@ let mkService = name: keyboard: nameValuePair (mkName name) { wantedBy = [ "multi-user.target" ]; serviceConfig = { + Type = "notify"; ExecStart = '' ${getExe cfg.package} \ --cfg ${mkConfig name keyboard} \ @@ -123,8 +124,7 @@ let ProtectKernelModules = true; ProtectKernelTunables = true; ProtectProc = "invisible"; - RestrictAddressFamilies = - if (keyboard.port == null) then "none" else [ "AF_INET" ]; + RestrictAddressFamilies = [ "AF_UNIX" ] ++ optional (keyboard.port != null) "AF_INET"; RestrictNamespaces = true; RestrictRealtime = true; SystemCallArchitectures = [ "native" ]; diff --git a/nixos/modules/services/hardware/keyd.nix b/nixos/modules/services/hardware/keyd.nix new file mode 100644 index 0000000000000..64c769405fabc --- /dev/null +++ b/nixos/modules/services/hardware/keyd.nix @@ -0,0 +1,112 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.keyd; + settingsFormat = pkgs.formats.ini { }; +in +{ + options = { + services.keyd = { + enable = mkEnableOption (lib.mdDoc "keyd, a key remapping daemon"); + + ids = mkOption { + type = types.listOf types.string; + default = [ "*" ]; + example = [ "*" "-0123:0456" ]; + description = lib.mdDoc '' + Device identifiers, as shown by {manpage}`keyd(1)`. + ''; + }; + + settings = mkOption { + type = settingsFormat.type; + default = { }; + example = { + main = { + capslock = "overload(control, esc)"; + rightalt = "layer(rightalt)"; + }; + + rightalt = { + j = "down"; + k = "up"; + h = "left"; + l = "right"; + }; + }; + description = lib.mdDoc '' + Configuration, except `ids` section, that is written to {file}`/etc/keyd/default.conf`. + See <https://github.com/rvaiya/keyd> how to configure. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + environment.etc."keyd/default.conf".source = pkgs.runCommand "default.conf" + { + ids = '' + [ids] + ${concatStringsSep "\n" cfg.ids} + ''; + passAsFile = [ "ids" ]; + } '' + cat $idsPath <(echo) ${settingsFormat.generate "keyd-main.conf" cfg.settings} >$out + ''; + + hardware.uinput.enable = lib.mkDefault true; + + systemd.services.keyd = { + description = "Keyd remapping daemon"; + documentation = [ "man:keyd(1)" ]; + + wantedBy = [ "multi-user.target" ]; + + restartTriggers = [ + config.environment.etc."keyd/default.conf".source + ]; + + # this is configurable in 2.4.2, later versions seem to remove this option. + # post-2.4.2 may need to set makeFlags in the derivation: + # + # makeFlags = [ "SOCKET_PATH/run/keyd/keyd.socket" ]; + environment.KEYD_SOCKET = "/run/keyd/keyd.sock"; + + serviceConfig = { + ExecStart = "${pkgs.keyd}/bin/keyd"; + Restart = "always"; + + DynamicUser = true; + SupplementaryGroups = [ + config.users.groups.input.name + config.users.groups.uinput.name + ]; + + RuntimeDirectory = "keyd"; + + # Hardening + CapabilityBoundingSet = ""; + DeviceAllow = [ + "char-input rw" + "/dev/uinput rw" + ]; + ProtectClock = true; + PrivateNetwork = true; + ProtectHome = true; + ProtectHostname = true; + PrivateUsers = true; + PrivateMounts = true; + RestrictNamespaces = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectControlGroups = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + LockPersonality = true; + ProtectProc = "noaccess"; + UMask = "0077"; + }; + }; + }; +} diff --git a/nixos/modules/services/hardware/supergfxd.nix b/nixos/modules/services/hardware/supergfxd.nix index df339e4ba011f..5ea05ac277167 100644 --- a/nixos/modules/services/hardware/supergfxd.nix +++ b/nixos/modules/services/hardware/supergfxd.nix @@ -32,6 +32,7 @@ in systemd.packages = [ pkgs.supergfxctl ]; systemd.services.supergfxd.wantedBy = [ "multi-user.target" ]; + systemd.services.supergfxd.path = [ pkgs.kmod ]; services.dbus.packages = [ pkgs.supergfxctl ]; services.udev.packages = [ pkgs.supergfxctl ]; diff --git a/nixos/modules/services/hardware/undervolt.nix b/nixos/modules/services/hardware/undervolt.nix index c49d944cdc188..944777475401b 100644 --- a/nixos/modules/services/hardware/undervolt.nix +++ b/nixos/modules/services/hardware/undervolt.nix @@ -5,8 +5,8 @@ let cfg = config.services.undervolt; mkPLimit = limit: window: - if (isNull limit && isNull window) then null - else assert asserts.assertMsg (!isNull limit && !isNull window) "Both power limit and window must be set"; + if (limit == null && window == null) then null + else assert asserts.assertMsg (limit != null && window != null) "Both power limit and window must be set"; "${toString limit} ${toString window}"; cliArgs = lib.cli.toGNUCommandLine {} { inherit (cfg) diff --git a/nixos/modules/services/home-automation/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix index 6adc58ec58ec4..cea8a2b14cc22 100644 --- a/nixos/modules/services/home-automation/home-assistant.nix +++ b/nixos/modules/services/home-automation/home-assistant.nix @@ -362,7 +362,7 @@ in { config = mkIf cfg.enable { assertions = [ { - assertion = cfg.openFirewall -> !isNull cfg.config; + assertion = cfg.openFirewall -> cfg.config != null; message = "openFirewall can only be used with a declarative config"; } ]; diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix index 1799e9282b3b0..b056f96c3630b 100644 --- a/nixos/modules/services/logging/logrotate.nix +++ b/nixos/modules/services/logging/logrotate.nix @@ -187,7 +187,7 @@ in A configuration file automatically generated by NixOS. ''; description = lib.mdDoc '' - Override the configuration file used by MySQL. By default, + Override the configuration file used by logrotate. By default, NixOS generates one automatically from [](#opt-services.logrotate.settings). ''; example = literalExpression '' diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix index 95dc2f6aa2c92..7b6d82219298c 100644 --- a/nixos/modules/services/mail/roundcube.nix +++ b/nixos/modules/services/mail/roundcube.nix @@ -132,6 +132,8 @@ in $config['plugins'] = [${concatMapStringsSep "," (p: "'${p}'") cfg.plugins}]; $config['des_key'] = file_get_contents('/var/lib/roundcube/des_key'); $config['mime_types'] = '${pkgs.nginx}/conf/mime.types'; + # Roundcube uses PHP-FPM which has `PrivateTmp = true;` + $config['temp_dir'] = '/tmp'; $config['enable_spellcheck'] = ${if cfg.dicts == [] then "false" else "true"}; # by default, spellchecking uses a third-party cloud services $config['spellcheck_engine'] = 'pspell'; diff --git a/nixos/modules/services/matrix/synapse.md b/nixos/modules/services/matrix/synapse.md index 7a9ddf8c9daf3..cad91ebf58d56 100644 --- a/nixos/modules/services/matrix/synapse.md +++ b/nixos/modules/services/matrix/synapse.md @@ -27,10 +27,7 @@ please refer to the { pkgs, lib, config, ... }: let fqdn = "${config.networking.hostName}.${config.networking.domain}"; - clientConfig = { - "m.homeserver".base_url = "https://${fqdn}"; - "m.identity_server" = {}; - }; + clientConfig."m.homeserver".base_url = "https://${fqdn}"; serverConfig."m.server" = "${fqdn}:443"; mkWellKnown = data: '' add_header Content-Type application/json; diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix index aee275dab1ec1..b6b51b21c796f 100644 --- a/nixos/modules/services/matrix/synapse.nix +++ b/nixos/modules/services/matrix/synapse.nix @@ -60,7 +60,7 @@ in { '') (mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] '' Database configuration must be done manually. An exemplary setup is demonstrated in - <nixpkgs/nixos/tests/matrix-synapse.nix> + <nixpkgs/nixos/tests/matrix/synapse.nix> '') (mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "") (mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] '' @@ -711,7 +711,7 @@ in { If you - try to deploy a fresh synapse, you need to configure the database yourself. An example - for this can be found in <nixpkgs/nixos/tests/matrix-synapse.nix> + for this can be found in <nixpkgs/nixos/tests/matrix/synapse.nix> - update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true` to your configuration. diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix index 014c5b16097c9..e019e431a1890 100644 --- a/nixos/modules/services/misc/gitea.nix +++ b/nixos/modules/services/misc/gitea.nix @@ -365,6 +365,8 @@ in ]; services.gitea.settings = { + "cron.update_checker".ENABLED = lib.mkDefault false; + database = mkMerge [ { DB_TYPE = cfg.database.type; diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index c7299c1ccad86..d278b571a6410 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -156,7 +156,7 @@ let }; extra = {}; uploads.storage_path = cfg.statePath; - pages = { + pages = optionalAttrs cfg.pages.enable { enabled = cfg.pages.enable; port = 8090; host = cfg.pages.settings.pages-domain; diff --git a/nixos/modules/services/misc/portunus.nix b/nixos/modules/services/misc/portunus.nix index f60cbe3477132..5504fb942968f 100644 --- a/nixos/modules/services/misc/portunus.nix +++ b/nixos/modules/services/misc/portunus.nix @@ -238,7 +238,7 @@ in PORTUNUS_SERVER_BINARY = "${cfg.package}/bin/portunus-server"; PORTUNUS_SERVER_GROUP = cfg.group; PORTUNUS_SERVER_USER = cfg.user; - PORTUNUS_SERVER_HTTP_LISTEN = "[::]:${toString cfg.port}"; + PORTUNUS_SERVER_HTTP_LISTEN = "127.0.0.1:${toString cfg.port}"; PORTUNUS_SERVER_STATE_DIR = cfg.stateDir; PORTUNUS_SLAPD_BINARY = "${cfg.ldap.package}/libexec/slapd"; PORTUNUS_SLAPD_GROUP = cfg.ldap.group; diff --git a/nixos/modules/services/misc/sssd.nix b/nixos/modules/services/misc/sssd.nix index edd5750a4a478..7c7a3b464a836 100644 --- a/nixos/modules/services/misc/sssd.nix +++ b/nixos/modules/services/misc/sssd.nix @@ -77,6 +77,10 @@ in { }; config = mkMerge [ (mkIf cfg.enable { + # For `sssctl` to work. + environment.etc."sssd/sssd.conf".source = settingsFile; + environment.etc."sssd/conf.d".source = "${dataDir}/conf.d"; + systemd.services.sssd = { description = "System Security Services Daemon"; wantedBy = [ "multi-user.target" ]; @@ -101,6 +105,7 @@ in { EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; }; preStart = '' + mkdir -p "${dataDir}/conf.d" [ -f ${settingsFile} ] && rm -f ${settingsFile} old_umask=$(umask) umask 0177 diff --git a/nixos/modules/services/misc/zoneminder.nix b/nixos/modules/services/misc/zoneminder.nix index 109415a20ee63..11722979851c2 100644 --- a/nixos/modules/services/misc/zoneminder.nix +++ b/nixos/modules/services/misc/zoneminder.nix @@ -283,7 +283,8 @@ in { phpfpm = lib.mkIf useNginx { pools.zoneminder = { inherit user group; - phpPackage = pkgs.php.withExtensions ({ enabled, all }: enabled ++ [ all.apcu ]); + phpPackage = pkgs.php.withExtensions ( + { enabled, all }: enabled ++ [ all.apcu all.sysvsem ]); phpOptions = '' date.timezone = "${config.time.timeZone}" ''; @@ -326,6 +327,15 @@ in { fi ${zoneminder}/bin/zmupdate.pl -nointeractive + ${zoneminder}/bin/zmupdate.pl --nointeractive -f + + # Update ZM's Nix store path in the configuration table. Do nothing if the config doesn't + # contain ZM's Nix store path. + ${config.services.mysql.package}/bin/mysql -u zoneminder zm << EOF + UPDATE Config + SET Value = REGEXP_REPLACE(Value, "^/nix/store/[^-/]+-zoneminder-[^/]+", "${pkgs.zoneminder}") + WHERE Name = "ZM_FONT_FILE_LOCATION"; + EOF ''; serviceConfig = { User = user; diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index ba3f89e24dd45..5a8c65b9dc3fb 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -1300,7 +1300,7 @@ in { SystemCallFilter = [ "@system-service" "~@privileged" - ] ++ lib.optional (cfg.settings.server.protocol == "socket") [ "@chown" ]; + ] ++ lib.optionals (cfg.settings.server.protocol == "socket") [ "@chown" ]; UMask = "0027"; }; preStart = '' diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager-irc-relay.nix b/nixos/modules/services/monitoring/prometheus/alertmanager-irc-relay.nix new file mode 100644 index 0000000000000..b81d5f6db5e08 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/alertmanager-irc-relay.nix @@ -0,0 +1,107 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.prometheus.alertmanagerIrcRelay; + + configFormat = pkgs.formats.yaml { }; + configFile = configFormat.generate "alertmanager-irc-relay.yml" cfg.settings; +in +{ + options.services.prometheus.alertmanagerIrcRelay = { + enable = mkEnableOption (mdDoc "Alertmanager IRC Relay"); + + package = mkOption { + type = types.package; + default = pkgs.alertmanager-irc-relay; + defaultText = literalExpression "pkgs.alertmanager-irc-relay"; + description = mdDoc "Alertmanager IRC Relay package to use."; + }; + + extraFlags = mkOption { + type = types.listOf types.str; + default = []; + description = mdDoc "Extra command line options to pass to alertmanager-irc-relay."; + }; + + settings = mkOption { + type = configFormat.type; + example = literalExpression '' + { + http_host = "localhost"; + http_port = 8000; + + irc_host = "irc.example.com"; + irc_port = 7000; + irc_nickname = "myalertbot"; + + irc_channels = [ + { name = "#mychannel"; } + ]; + } + ''; + description = mdDoc '' + Configuration for Alertmanager IRC Relay as a Nix attribute set. + For a reference, check out the + [example configuration](https://github.com/google/alertmanager-irc-relay#configuring-and-running-the-bot) + and the + [source code](https://github.com/google/alertmanager-irc-relay/blob/master/config.go). + + Note: The webhook's URL MUST point to the IRC channel where the message + should be posted. For `#mychannel` from the example, this would be + `http://localhost:8080/mychannel`. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.alertmanager-irc-relay = { + description = "Alertmanager IRC Relay"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + + serviceConfig = { + ExecStart = '' + ${cfg.package}/bin/alertmanager-irc-relay \ + -config ${configFile} \ + ${escapeShellArgs cfg.extraFlags} + ''; + + DynamicUser = true; + NoNewPrivileges = true; + + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ProtectHome = "tmpfs"; + + PrivateTmp = true; + PrivateDevices = true; + PrivateIPC = true; + + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictRealtime = true; + RestrictSUIDSGID = true; + + SystemCallFilter = [ + "@system-service" + "~@cpu-emulation" + "~@privileged" + "~@reboot" + "~@setuid" + "~@swap" + ]; + }; + }; + }; + + meta.maintainers = [ maintainers.oxzi ]; +} diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix index 4f197b9b5820e..fb3bab7963ea8 100644 --- a/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixos/modules/services/monitoring/prometheus/default.nix @@ -31,7 +31,7 @@ let if checkConfigEnabled then pkgs.runCommandLocal "${name}-${replaceStrings [" "] [""] what}-checked" - { buildInputs = [ cfg.package ]; } '' + { buildInputs = [ cfg.package.cli ]; } '' ln -s ${file} $out promtool ${what} $out '' else file; diff --git a/nixos/modules/services/network-filesystems/kubo.nix b/nixos/modules/services/network-filesystems/kubo.nix index 4d423c9059866..0cb0e126d4c50 100644 --- a/nixos/modules/services/network-filesystems/kubo.nix +++ b/nixos/modules/services/network-filesystems/kubo.nix @@ -171,7 +171,11 @@ in "/ip4/0.0.0.0/tcp/4001" "/ip6/::/tcp/4001" "/ip4/0.0.0.0/udp/4001/quic" + "/ip4/0.0.0.0/udp/4001/quic-v1" + "/ip4/0.0.0.0/udp/4001/quic-v1/webtransport" "/ip6/::/udp/4001/quic" + "/ip6/::/udp/4001/quic-v1" + "/ip6/::/udp/4001/quic-v1/webtransport" ]; description = lib.mdDoc "Where Kubo listens for incoming p2p connections"; }; diff --git a/nixos/modules/services/networking/avahi-daemon.nix b/nixos/modules/services/networking/avahi-daemon.nix index 103f73fdaa685..3a7519c7230b3 100644 --- a/nixos/modules/services/networking/avahi-daemon.nix +++ b/nixos/modules/services/networking/avahi-daemon.nix @@ -5,7 +5,7 @@ with lib; let cfg = config.services.avahi; - yesNo = yes : if yes then "yes" else "no"; + yesNo = yes: if yes then "yes" else "no"; avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" '' [server] @@ -17,7 +17,8 @@ let browse-domains=${concatStringsSep ", " browseDomains} use-ipv4=${yesNo ipv4} use-ipv6=${yesNo ipv6} - ${optionalString (interfaces!=null) "allow-interfaces=${concatStringsSep "," interfaces}"} + ${optionalString (allowInterfaces!=null) "allow-interfaces=${concatStringsSep "," allowInterfaces}"} + ${optionalString (denyInterfaces!=null) "deny-interfaces=${concatStringsSep "," denyInterfaces}"} ${optionalString (domainName!=null) "domain-name=${domainName}"} allow-point-to-point=${yesNo allowPointToPoint} ${optionalString (cacheEntriesMax!=null) "cache-entries-max=${toString cacheEntriesMax}"} @@ -39,6 +40,10 @@ let ''; in { + imports = [ + (lib.mkRenamedOptionModule [ "services" "avahi" "interfaces" ] [ "services" "avahi" "allowInterfaces" ]) + ]; + options.services.avahi = { enable = mkOption { type = types.bool; @@ -91,7 +96,7 @@ in description = lib.mdDoc "Whether to use IPv6."; }; - interfaces = mkOption { + allowInterfaces = mkOption { type = types.nullOr (types.listOf types.str); default = null; description = lib.mdDoc '' @@ -101,6 +106,17 @@ in ''; }; + denyInterfaces = mkOption { + type = types.nullOr (types.listOf types.str); + default = null; + description = lib.mdDoc '' + List of network interfaces that should be ignored by the + {command}`avahi-daemon`. Other unspecified interfaces will be used, + unless {option}`allowInterfaces` is set. This option takes precedence + over {option}`allowInterfaces`. + ''; + }; + openFirewall = mkOption { type = types.bool; default = true; @@ -134,7 +150,7 @@ in extraServiceFiles = mkOption { type = with types; attrsOf (either str path); - default = {}; + default = { }; example = literalExpression '' { ssh = "''${pkgs.avahi}/etc/avahi/services/ssh.service"; @@ -236,7 +252,7 @@ in isSystemUser = true; }; - users.groups.avahi = {}; + users.groups.avahi = { }; system.nssModules = optional cfg.nssmdns pkgs.nssmdns; system.nssDatabases.hosts = optionals cfg.nssmdns (mkMerge [ @@ -246,10 +262,12 @@ in environment.systemPackages = [ pkgs.avahi ]; - environment.etc = (mapAttrs' (n: v: nameValuePair - "avahi/services/${n}.service" - { ${if types.path.check v then "source" else "text"} = v; } - ) cfg.extraServiceFiles); + environment.etc = (mapAttrs' + (n: v: nameValuePair + "avahi/services/${n}.service" + { ${if types.path.check v then "source" else "text"} = v; } + ) + cfg.extraServiceFiles); systemd.sockets.avahi-daemon = { description = "Avahi mDNS/DNS-SD Stack Activation Socket"; diff --git a/nixos/modules/services/networking/firewall-nftables.nix b/nixos/modules/services/networking/firewall-nftables.nix index 0ed3c228075d3..452dd97d89d29 100644 --- a/nixos/modules/services/networking/firewall-nftables.nix +++ b/nixos/modules/services/networking/firewall-nftables.nix @@ -94,7 +94,13 @@ in ${optionalString (ifaceSet != "") ''iifname { ${ifaceSet} } accept comment "trusted interfaces"''} # Some ICMPv6 types like NDP is untracked - ct state vmap { invalid : drop, established : accept, related : accept, * : jump input-allow } comment "*: new and untracked" + ct state vmap { + invalid : drop, + established : accept, + related : accept, + new : jump input-allow, + untracked: jump input-allow, + } ${optionalString cfg.logRefusedConnections '' tcp flags syn / fin,syn,rst,ack log level info prefix "refused connection: " @@ -143,7 +149,13 @@ in chain forward { type filter hook forward priority filter; policy drop; - ct state vmap { invalid : drop, established : accept, related : accept, * : jump forward-allow } comment "*: new and untracked" + ct state vmap { + invalid : drop, + established : accept, + related : accept, + new : jump forward-allow, + untracked : jump forward-allow, + } } diff --git a/nixos/modules/services/networking/headscale.nix b/nixos/modules/services/networking/headscale.nix index 390a448ab5842..d2851e72a0dd6 100644 --- a/nixos/modules/services/networking/headscale.nix +++ b/nixos/modules/services/networking/headscale.nix @@ -291,11 +291,11 @@ in { ''; }; - client_secret_file = mkOption { + client_secret_path = mkOption { type = types.nullOr types.path; default = null; description = lib.mdDoc '' - Path to OpenID Connect client secret file. + Path to OpenID Connect client secret file. Expands environment variables in format ''${VAR}. ''; }; @@ -425,7 +425,7 @@ in { (mkRenamedOptionModule ["services" "headscale" "dns" "baseDomain"] ["services" "headscale" "settings" "dns_config" "base_domain"]) (mkRenamedOptionModule ["services" "headscale" "openIdConnect" "issuer"] ["services" "headscale" "settings" "oidc" "issuer"]) (mkRenamedOptionModule ["services" "headscale" "openIdConnect" "clientId"] ["services" "headscale" "settings" "oidc" "client_id"]) - (mkRenamedOptionModule ["services" "headscale" "openIdConnect" "clientSecretFile"] ["services" "headscale" "settings" "oidc" "client_secret_file"]) + (mkRenamedOptionModule ["services" "headscale" "openIdConnect" "clientSecretFile"] ["services" "headscale" "settings" "oidc" "client_secret_path"]) (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "hostname"] ["services" "headscale" "settings" "tls_letsencrypt_hostname"]) (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "challengeType"] ["services" "headscale" "settings" "tls_letsencrypt_challenge_type"]) (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "httpListen"] ["services" "headscale" "settings" "tls_letsencrypt_listen"]) @@ -478,9 +478,6 @@ in { export HEADSCALE_DB_PASS="$(head -n1 ${escapeShellArg cfg.settings.db_password_file})" ''} - ${optionalString (cfg.settings.oidc.client_secret_file != null) '' - export HEADSCALE_OIDC_CLIENT_SECRET="$(head -n1 ${escapeShellArg cfg.settings.oidc.client_secret_file})" - ''} exec ${cfg.package}/bin/headscale serve ''; diff --git a/nixos/modules/services/networking/jicofo.nix b/nixos/modules/services/networking/jicofo.nix index 5e97889607363..0886bbe004c46 100644 --- a/nixos/modules/services/networking/jicofo.nix +++ b/nixos/modules/services/networking/jicofo.nix @@ -4,6 +4,15 @@ with lib; let cfg = config.services.jicofo; + + # HOCON is a JSON superset that some jitsi-meet components use for configuration + toHOCON = x: if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}") + else if isAttrs x && x ? __hocon_unquoted_string then x.__hocon_unquoted_string + else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}" + else if isList x then "[${ concatMapStringsSep "," toHOCON x }]" + else builtins.toJSON x; + + configFile = pkgs.writeText "jicofo.conf" (toHOCON cfg.config); in { options.services.jicofo = with types; { @@ -68,22 +77,34 @@ in }; config = mkOption { - type = attrsOf str; + type = (pkgs.formats.json {}).type; default = { }; example = literalExpression '' { - "org.jitsi.jicofo.auth.URL" = "XMPP:jitsi-meet.example.com"; + jicofo.bridge.max-bridge-participants = 42; } ''; description = lib.mdDoc '' - Contents of the {file}`sip-communicator.properties` configuration file for jicofo. + Contents of the {file}`jicofo.conf` configuration file. ''; }; }; config = mkIf cfg.enable { - services.jicofo.config = mapAttrs (_: v: mkDefault v) { - "org.jitsi.jicofo.BRIDGE_MUC" = cfg.bridgeMuc; + services.jicofo.config = { + jicofo = { + bridge.brewery-jid = cfg.bridgeMuc; + xmpp = rec { + client = { + hostname = cfg.xmppHost; + username = cfg.userName; + domain = cfg.userDomain; + password = { __hocon_envvar = "JICOFO_AUTH_PASS"; }; + xmpp-domain = if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain; + }; + service = client; + }; + }; }; users.groups.jitsi-meet = {}; @@ -93,6 +114,7 @@ in "-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi"; "-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "jicofo"; "-Djava.util.logging.config.file" = "/etc/jitsi/jicofo/logging.properties"; + "-Dconfig.file" = configFile; }; in { @@ -101,18 +123,13 @@ in after = [ "network.target" ]; restartTriggers = [ - config.environment.etc."jitsi/jicofo/sip-communicator.properties".source + configFile ]; environment.JAVA_SYS_PROPS = concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") jicofoProps); script = '' - ${pkgs.jicofo}/bin/jicofo \ - --host=${cfg.xmppHost} \ - --domain=${if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain} \ - --secret=$(cat ${cfg.componentPasswordFile}) \ - --user_name=${cfg.userName} \ - --user_domain=${cfg.userDomain} \ - --user_password=$(cat ${cfg.userPasswordFile}) + export JICOFO_AUTH_PASS="$(<${cfg.userPasswordFile})" + exec "${pkgs.jicofo}/bin/jicofo" ''; serviceConfig = { @@ -140,10 +157,7 @@ in }; }; - environment.etc."jitsi/jicofo/sip-communicator.properties".source = - pkgs.writeText "sip-communicator.properties" ( - generators.toKeyValue {} cfg.config - ); + environment.etc."jitsi/jicofo/sip-communicator.properties".text = ""; environment.etc."jitsi/jicofo/logging.properties".source = mkDefault "${pkgs.jicofo}/etc/jitsi/jicofo/logging.properties-journal"; }; diff --git a/nixos/modules/services/networking/multipath.nix b/nixos/modules/services/networking/multipath.nix index b20ec76ddf594..bd403e109c2af 100644 --- a/nixos/modules/services/networking/multipath.nix +++ b/nixos/modules/services/networking/multipath.nix @@ -513,22 +513,22 @@ in { ${indentLines 2 devices} } - ${optionalString (!isNull defaults) '' + ${optionalString (defaults != null) '' defaults { ${indentLines 2 defaults} } ''} - ${optionalString (!isNull blacklist) '' + ${optionalString (blacklist != null) '' blacklist { ${indentLines 2 blacklist} } ''} - ${optionalString (!isNull blacklist_exceptions) '' + ${optionalString (blacklist_exceptions != null) '' blacklist_exceptions { ${indentLines 2 blacklist_exceptions} } ''} - ${optionalString (!isNull overrides) '' + ${optionalString (overrides != null) '' overrides { ${indentLines 2 overrides} } diff --git a/nixos/modules/services/networking/peroxide.nix b/nixos/modules/services/networking/peroxide.nix new file mode 100644 index 0000000000000..6cac4bf2f89a1 --- /dev/null +++ b/nixos/modules/services/networking/peroxide.nix @@ -0,0 +1,131 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.peroxide; + settingsFormat = pkgs.formats.yaml { }; + stateDir = "peroxide"; +in +{ + options.services.peroxide = { + enable = mkEnableOption (lib.mdDoc "enable"); + + package = mkPackageOptionMD pkgs "peroxide" { + default = [ "peroxide" ]; + }; + + logLevel = mkOption { + # https://github.com/sirupsen/logrus#level-logging + type = types.enum [ "Panic" "Fatal" "Error" "Warning" "Info" "Debug" "Trace" ]; + default = "Warning"; + example = "Info"; + description = lib.mdDoc "Only log messages of this priority or higher."; + }; + + settings = mkOption { + type = types.submodule { + freeformType = settingsFormat.type; + + options = { + UserPortImap = mkOption { + type = types.port; + default = 1143; + description = lib.mdDoc "The port on which to listen for IMAP connections."; + }; + + UserPortSmtp = mkOption { + type = types.port; + default = 1025; + description = lib.mdDoc "The port on which to listen for SMTP connections."; + }; + + ServerAddress = mkOption { + type = types.str; + default = "[::0]"; + example = "localhost"; + description = lib.mdDoc "The address on which to listen for connections."; + }; + }; + }; + default = { }; + description = lib.mdDoc '' + Configuration for peroxide. See + [config.example.yaml](https://github.com/ljanyst/peroxide/blob/master/config.example.yaml) + for an example configuration. + ''; + }; + }; + + config = mkIf cfg.enable { + services.peroxide.settings = { + # peroxide deletes the cache directory on startup, which requires write + # permission on the parent directory, so we can't use + # /var/cache/peroxide + CacheDir = "/var/cache/peroxide/cache"; + X509Key = mkDefault "/var/lib/${stateDir}/key.pem"; + X509Cert = mkDefault "/var/lib/${stateDir}/cert.pem"; + CookieJar = "/var/lib/${stateDir}/cookies.json"; + CredentialsStore = "/var/lib/${stateDir}/credentials.json"; + }; + + users.users.peroxide = { + isSystemUser = true; + group = "peroxide"; + }; + users.groups.peroxide = { }; + + systemd.services.peroxide = { + description = "Peroxide ProtonMail bridge"; + requires = [ "network.target" ]; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + restartTriggers = [ config.environment.etc."peroxide.conf".source ]; + + serviceConfig = { + Type = "simple"; + User = "peroxide"; + LogsDirectory = "peroxide"; + LogsDirectoryMode = "0750"; + # Specify just "peroxide" so that the user has write permission, because + # peroxide deletes and recreates the cache directory on startup. + CacheDirectory = [ "peroxide" "peroxide/cache" ]; + CacheDirectoryMode = "0700"; + StateDirectory = stateDir; + StateDirectoryMode = "0700"; + ExecStart = "${cfg.package}/bin/peroxide -log-file=/var/log/peroxide/peroxide.log -log-level ${cfg.logLevel}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + + preStart = '' + # Create a self-signed certificate if no certificate exists. + if [[ ! -e "${cfg.settings.X509Key}" && ! -e "${cfg.settings.X509Cert}" ]]; then + ${cfg.package}/bin/peroxide-cfg -action gen-x509 \ + -x509-org 'N/A' \ + -x509-cn 'nixos' \ + -x509-cert "${cfg.settings.X509Cert}" \ + -x509-key "${cfg.settings.X509Key}" + fi + ''; + }; + + # https://github.com/ljanyst/peroxide/blob/master/peroxide.logrotate + services.logrotate.settings.peroxide = { + files = "/var/log/peroxide/peroxide.log"; + rotate = 31; + frequency = "daily"; + compress = true; + delaycompress = true; + missingok = true; + notifempty = true; + su = "peroxide peroxide"; + postrotate = "systemctl reload peroxide"; + }; + + environment.etc."peroxide.conf".source = settingsFormat.generate "peroxide.conf" cfg.settings; + environment.systemPackages = [ cfg.package ]; + }; + + meta.maintainers = with maintainers; [ aanderse aidalgol ]; +} diff --git a/nixos/modules/services/networking/radicale.nix b/nixos/modules/services/networking/radicale.nix index 8e4789c7ca597..00dbd6bbe386d 100644 --- a/nixos/modules/services/networking/radicale.nix +++ b/nixos/modules/services/networking/radicale.nix @@ -9,7 +9,7 @@ let listToValue = concatMapStringsSep ", " (generators.mkValueStringDefault { }); }; - pkg = if isNull cfg.package then + pkg = if cfg.package == null then pkgs.radicale else cfg.package; @@ -117,13 +117,13 @@ in { } ]; - warnings = optional (isNull cfg.package && versionOlder config.system.stateVersion "17.09") '' + warnings = optional (cfg.package == null && versionOlder config.system.stateVersion "17.09") '' The configuration and storage formats of your existing Radicale installation might be incompatible with the newest version. For upgrade instructions see https://radicale.org/2.1.html#documentation/migration-from-1xx-to-2xx. Set services.radicale.package to suppress this warning. - '' ++ optional (isNull cfg.package && versionOlder config.system.stateVersion "20.09") '' + '' ++ optional (cfg.package == null && versionOlder config.system.stateVersion "20.09") '' The configuration format of your existing Radicale installation might be incompatible with the newest version. For upgrade instructions see https://github.com/Kozea/Radicale/blob/3.0.6/NEWS.md#upgrade-checklist. diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index 095c7de0b7aa1..5f225682b7779 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -19,7 +19,7 @@ let else if true == v then "yes" else if false == v then "no" else if isList v then concatStringsSep "," v - else throw "unsupported type ${typeOf v}: ${(lib.generators.toPretty {}) v}"; + else throw "unsupported type ${builtins.typeOf v}: ${(lib.generators.toPretty {}) v}"; # dont use the "=" operator settingsFormat = (pkgs.formats.keyValue { diff --git a/nixos/modules/services/networking/yggdrasil.nix b/nixos/modules/services/networking/yggdrasil.nix index fd7193154c6c7..55a6002d61af1 100644 --- a/nixos/modules/services/networking/yggdrasil.nix +++ b/nixos/modules/services/networking/yggdrasil.nix @@ -8,7 +8,8 @@ let configFileProvided = cfg.configFile != null; format = pkgs.formats.json { }; -in { +in +{ imports = [ (mkRenamedOptionModule [ "services" "yggdrasil" "config" ] @@ -21,7 +22,7 @@ in { settings = mkOption { type = format.type; - default = {}; + default = { }; example = { Peers = [ "tcp://aa.bb.cc.dd:eeeee" @@ -45,7 +46,7 @@ in { If no keys are specified then ephemeral keys are generated and the Yggdrasil interface will have a random IPv6 address - each time the service is started, this is the default. + each time the service is started. This is the default. If both {option}`configFile` and {option}`settings` are supplied, they will be combined, with values from @@ -61,8 +62,13 @@ in { default = null; example = "/run/keys/yggdrasil.conf"; description = lib.mdDoc '' - A file which contains JSON configuration for yggdrasil. - See the {option}`settings` option for more information. + A file which contains JSON or HJSON configuration for yggdrasil. See + the {option}`settings` option for more information. + + Note: This file must not be larger than 1 MB because it is passed to + the yggdrasil process via systemd‘s LoadCredential mechanism. For + details, see <https://systemd.io/CREDENTIALS/> and `man 5 + systemd.exec`. ''; }; @@ -77,20 +83,20 @@ in { type = bool; default = false; description = lib.mdDoc '' - Whether to open the UDP port used for multicast peer - discovery. The NixOS firewall blocks link-local - communication, so in order to make local peering work you - will also need to set `LinkLocalTCPPort` in your - yggdrasil configuration ({option}`settings` or - {option}`configFile`) to a port number other than 0, - and then add that port to - {option}`networking.firewall.allowedTCPPorts`. + Whether to open the UDP port used for multicast peer discovery. The + NixOS firewall blocks link-local communication, so in order to make + incoming local peering work you will also need to configure + `MulticastInterfaces` in your Yggdrasil configuration + ({option}`settings` or {option}`configFile`). You will then have to + add the ports that you configure there to your firewall configuration + ({option}`networking.firewall.allowedTCPPorts` or + {option}`networking.firewall.interfaces.<name>.allowedTCPPorts`). ''; }; denyDhcpcdInterfaces = mkOption { type = listOf str; - default = []; + default = [ ]; example = [ "tap*" ]; description = lib.mdDoc '' Disable the DHCP client for any interface whose name matches @@ -118,80 +124,102 @@ in { }; }; - config = mkIf cfg.enable (let binYggdrasil = cfg.package + "/bin/yggdrasil"; - in { - assertions = [{ - assertion = config.networking.enableIPv6; - message = "networking.enableIPv6 must be true for yggdrasil to work"; - }]; - - system.activationScripts.yggdrasil = mkIf cfg.persistentKeys '' - if [ ! -e ${keysPath} ] - then - mkdir --mode=700 -p ${builtins.dirOf keysPath} - ${binYggdrasil} -genconf -json \ - | ${pkgs.jq}/bin/jq \ - 'to_entries|map(select(.key|endswith("Key")))|from_entries' \ - > ${keysPath} - fi - ''; - - systemd.services.yggdrasil = { - description = "Yggdrasil Network Service"; - after = [ "network-pre.target" ]; - wants = [ "network.target" ]; - before = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - - preStart = - (if settingsProvided || configFileProvided || cfg.persistentKeys then - "echo " - - + (lib.optionalString settingsProvided - "'${builtins.toJSON cfg.settings}'") - + (lib.optionalString configFileProvided "$(cat ${cfg.configFile})") - + (lib.optionalString cfg.persistentKeys "$(cat ${keysPath})") - + " | ${pkgs.jq}/bin/jq -s add | ${binYggdrasil} -normaliseconf -useconf" - else - "${binYggdrasil} -genconf") + " > /run/yggdrasil/yggdrasil.conf"; - - serviceConfig = { - ExecStart = - "${binYggdrasil} -useconffile /run/yggdrasil/yggdrasil.conf"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - Restart = "always"; - - DynamicUser = true; - StateDirectory = "yggdrasil"; - RuntimeDirectory = "yggdrasil"; - RuntimeDirectoryMode = "0750"; - BindReadOnlyPaths = lib.optional configFileProvided cfg.configFile - ++ lib.optional cfg.persistentKeys keysPath; - ReadWritePaths = "/run/yggdrasil"; - - AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE"; - CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE"; - MemoryDenyWriteExecute = true; - ProtectControlGroups = true; - ProtectHome = "tmpfs"; - ProtectKernelModules = true; - ProtectKernelTunables = true; - RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; - RestrictNamespaces = true; - RestrictRealtime = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ "@system-service" "~@privileged @keyring" ]; - } // (if (cfg.group != null) then { - Group = cfg.group; - } else {}); - }; + config = mkIf cfg.enable ( + let + binYggdrasil = "${cfg.package}/bin/yggdrasil"; + binHjson = "${pkgs.hjson-go}/bin/hjson-cli"; + in + { + assertions = [{ + assertion = config.networking.enableIPv6; + message = "networking.enableIPv6 must be true for yggdrasil to work"; + }]; + + system.activationScripts.yggdrasil = mkIf cfg.persistentKeys '' + if [ ! -e ${keysPath} ] + then + mkdir --mode=700 -p ${builtins.dirOf keysPath} + ${binYggdrasil} -genconf -json \ + | ${pkgs.jq}/bin/jq \ + 'to_entries|map(select(.key|endswith("Key")))|from_entries' \ + > ${keysPath} + fi + ''; + + systemd.services.yggdrasil = { + description = "Yggdrasil Network Service"; + after = [ "network-pre.target" ]; + wants = [ "network.target" ]; + before = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + # This script first prepares the config file, then it starts Yggdrasil. + # The preparation could also be done in ExecStartPre/preStart but only + # systemd versions >= v252 support reading credentials in ExecStartPre. As + # of February 2023, systemd v252 is not yet in the stable branch of NixOS. + # + # This could be changed in the future once systemd version v252 has + # reached NixOS but it does not have to be. Config file preparation is + # fast enough, it does not need elevated privileges, and `set -euo + # pipefail` should make sure that the service is not started if the + # preparation fails. Therefore, it is not necessary to move the + # preparation to ExecStartPre. + script = '' + set -euo pipefail + + # prepare config file + ${(if settingsProvided || configFileProvided || cfg.persistentKeys then + "echo " + + + (lib.optionalString settingsProvided + "'${builtins.toJSON cfg.settings}'") + + (lib.optionalString configFileProvided + "$(${binHjson} -c \"$CREDENTIALS_DIRECTORY/yggdrasil.conf\")") + + (lib.optionalString cfg.persistentKeys "$(cat ${keysPath})") + + " | ${pkgs.jq}/bin/jq -s add | ${binYggdrasil} -normaliseconf -useconf" + else + "${binYggdrasil} -genconf") + " > /run/yggdrasil/yggdrasil.conf"} + + # start yggdrasil + ${binYggdrasil} -useconffile /run/yggdrasil/yggdrasil.conf + ''; + + serviceConfig = { + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + Restart = "always"; + + DynamicUser = true; + StateDirectory = "yggdrasil"; + RuntimeDirectory = "yggdrasil"; + RuntimeDirectoryMode = "0750"; + BindReadOnlyPaths = lib.optional cfg.persistentKeys keysPath; + LoadCredential = + mkIf configFileProvided "yggdrasil.conf:${cfg.configFile}"; + + AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE"; + CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE"; + MemoryDenyWriteExecute = true; + ProtectControlGroups = true; + ProtectHome = "tmpfs"; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged @keyring" ]; + } // (if (cfg.group != null) then { + Group = cfg.group; + } else { }); + }; - networking.dhcpcd.denyInterfaces = cfg.denyDhcpcdInterfaces; - networking.firewall.allowedUDPPorts = mkIf cfg.openMulticastPort [ 9001 ]; + networking.dhcpcd.denyInterfaces = cfg.denyDhcpcdInterfaces; + networking.firewall.allowedUDPPorts = mkIf cfg.openMulticastPort [ 9001 ]; - # Make yggdrasilctl available on the command line. - environment.systemPackages = [ cfg.package ]; - }); + # Make yggdrasilctl available on the command line. + environment.systemPackages = [ cfg.package ]; + } + ); meta = { doc = ./yggdrasil.md; maintainers = with lib.maintainers; [ gazally ehmry ]; diff --git a/nixos/modules/services/search/solr.nix b/nixos/modules/services/search/solr.nix deleted file mode 100644 index 05592e9fa247d..0000000000000 --- a/nixos/modules/services/search/solr.nix +++ /dev/null @@ -1,110 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.services.solr; - -in - -{ - options = { - services.solr = { - enable = mkEnableOption (lib.mdDoc "Solr"); - - package = mkOption { - type = types.package; - default = pkgs.solr; - defaultText = literalExpression "pkgs.solr"; - description = lib.mdDoc "Which Solr package to use."; - }; - - port = mkOption { - type = types.port; - default = 8983; - description = lib.mdDoc "Port on which Solr is ran."; - }; - - stateDir = mkOption { - type = types.path; - default = "/var/lib/solr"; - description = lib.mdDoc "The solr home directory containing config, data, and logging files."; - }; - - extraJavaOptions = mkOption { - type = types.listOf types.str; - default = []; - description = lib.mdDoc "Extra command line options given to the java process running Solr."; - }; - - user = mkOption { - type = types.str; - default = "solr"; - description = lib.mdDoc "User under which Solr is ran."; - }; - - group = mkOption { - type = types.str; - default = "solr"; - description = lib.mdDoc "Group under which Solr is ran."; - }; - }; - }; - - config = mkIf cfg.enable { - - environment.systemPackages = [ cfg.package ]; - - systemd.services.solr = { - after = [ "network.target" "remote-fs.target" "nss-lookup.target" "systemd-journald-dev-log.socket" ]; - wantedBy = [ "multi-user.target" ]; - - environment = { - SOLR_HOME = "${cfg.stateDir}/data"; - LOG4J_PROPS = "${cfg.stateDir}/log4j2.xml"; - SOLR_LOGS_DIR = "${cfg.stateDir}/logs"; - SOLR_PORT = "${toString cfg.port}"; - }; - path = with pkgs; [ - gawk - procps - ]; - preStart = '' - mkdir -p "${cfg.stateDir}/data"; - mkdir -p "${cfg.stateDir}/logs"; - - if ! test -e "${cfg.stateDir}/data/solr.xml"; then - install -D -m0640 ${cfg.package}/server/solr/solr.xml "${cfg.stateDir}/data/solr.xml" - install -D -m0640 ${cfg.package}/server/solr/zoo.cfg "${cfg.stateDir}/data/zoo.cfg" - fi - - if ! test -e "${cfg.stateDir}/log4j2.xml"; then - install -D -m0640 ${cfg.package}/server/resources/log4j2.xml "${cfg.stateDir}/log4j2.xml" - fi - ''; - - serviceConfig = { - User = cfg.user; - Group = cfg.group; - ExecStart="${cfg.package}/bin/solr start -f -a \"${concatStringsSep " " cfg.extraJavaOptions}\""; - ExecStop="${cfg.package}/bin/solr stop"; - }; - }; - - users.users = optionalAttrs (cfg.user == "solr") { - solr = { - group = cfg.group; - home = cfg.stateDir; - createHome = true; - uid = config.ids.uids.solr; - }; - }; - - users.groups = optionalAttrs (cfg.group == "solr") { - solr.gid = config.ids.gids.solr; - }; - - }; - -} diff --git a/nixos/modules/services/security/authelia.nix b/nixos/modules/services/security/authelia.nix new file mode 100644 index 0000000000000..143c441c7e153 --- /dev/null +++ b/nixos/modules/services/security/authelia.nix @@ -0,0 +1,401 @@ +{ lib +, pkgs +, config +, ... +}: + +let + cfg = config.services.authelia; + + format = pkgs.formats.yaml { }; + configFile = format.generate "config.yml" cfg.settings; + + autheliaOpts = with lib; { name, ... }: { + options = { + enable = mkEnableOption (mdDoc "Authelia instance"); + + name = mkOption { + type = types.str; + default = name; + description = mdDoc '' + Name is used as a suffix for the service name, user, and group. + By default it takes the value you use for `<instance>` in: + {option}`services.authelia.<instance>` + ''; + }; + + package = mkOption { + default = pkgs.authelia; + type = types.package; + defaultText = literalExpression "pkgs.authelia"; + description = mdDoc "Authelia derivation to use."; + }; + + user = mkOption { + default = "authelia-${name}"; + type = types.str; + description = mdDoc "The name of the user for this authelia instance."; + }; + + group = mkOption { + default = "authelia-${name}"; + type = types.str; + description = mdDoc "The name of the group for this authelia instance."; + }; + + secrets = mkOption { + description = mdDoc '' + It is recommended you keep your secrets separate from the configuration. + It's especially important to keep the raw secrets out of your nix configuration, + as the values will be preserved in your nix store. + This attribute allows you to configure the location of secret files to be loaded at runtime. + + https://www.authelia.com/configuration/methods/secrets/ + ''; + default = { }; + type = types.submodule { + options = { + manual = mkOption { + default = false; + example = true; + description = mdDoc '' + Configuring authelia's secret files via the secrets attribute set + is intended to be convenient and help catch cases where values are required + to run at all. + If a user wants to set these values themselves and bypass the validation they can set this value to true. + ''; + type = types.bool; + }; + + # required + jwtSecretFile = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + Path to your JWT secret used during identity verificaiton. + ''; + }; + + oidcIssuerPrivateKeyFile = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + Path to your private key file used to encrypt OIDC JWTs. + ''; + }; + + oidcHmacSecretFile = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + Path to your HMAC secret used to sign OIDC JWTs. + ''; + }; + + sessionSecretFile = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + Path to your session secret. Only used when redis is used as session storage. + ''; + }; + + # required + storageEncryptionKeyFile = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + Path to your storage encryption key. + ''; + }; + }; + }; + }; + + environmentVariables = mkOption { + type = types.attrsOf types.str; + description = mdDoc '' + Additional environment variables to provide to authelia. + If you are providing secrets please consider the options under {option}`services.authelia.<instance>.secrets` + or make sure you use the `_FILE` suffix. + If you provide the raw secret rather than the location of a secret file that secret will be preserved in the nix store. + For more details: https://www.authelia.com/configuration/methods/secrets/ + ''; + default = { }; + }; + + settings = mkOption { + description = mdDoc '' + Your Authelia config.yml as a Nix attribute set. + There are several values that are defined and documented in nix such as `default_2fa_method`, + but additional items can also be included. + + https://github.com/authelia/authelia/blob/master/config.template.yml + ''; + default = { }; + example = '' + { + theme = "light"; + default_2fa_method = "totp"; + log.level = "debug"; + server.disable_healthcheck = true; + } + ''; + type = types.submodule { + freeformType = format.type; + options = { + theme = mkOption { + type = types.enum [ "light" "dark" "grey" "auto" ]; + default = "light"; + example = "dark"; + description = mdDoc "The theme to display."; + }; + + default_2fa_method = mkOption { + type = types.enum [ "" "totp" "webauthn" "mobile_push" ]; + default = ""; + example = "webauthn"; + description = mdDoc '' + Default 2FA method for new users and fallback for preferred but disabled methods. + ''; + }; + + server = { + host = mkOption { + type = types.str; + default = "localhost"; + example = "0.0.0.0"; + description = mdDoc "The address to listen on."; + }; + + port = mkOption { + type = types.port; + default = 9091; + description = mdDoc "The port to listen on."; + }; + }; + + log = { + level = mkOption { + type = types.enum [ "info" "debug" "trace" ]; + default = "debug"; + example = "info"; + description = mdDoc "Level of verbosity for logs: info, debug, trace."; + }; + + format = mkOption { + type = types.enum [ "json" "text" ]; + default = "json"; + example = "text"; + description = mdDoc "Format the logs are written as."; + }; + + file_path = mkOption { + type = types.nullOr types.path; + default = null; + example = "/var/log/authelia/authelia.log"; + description = mdDoc "File path where the logs will be written. If not set logs are written to stdout."; + }; + + keep_stdout = mkOption { + type = types.bool; + default = false; + example = true; + description = mdDoc "Whether to also log to stdout when a `file_path` is defined."; + }; + }; + + telemetry = { + metrics = { + enabled = mkOption { + type = types.bool; + default = false; + example = true; + description = mdDoc "Enable Metrics."; + }; + + address = mkOption { + type = types.str; + default = "tcp://127.0.0.1:9959"; + example = "tcp://0.0.0.0:8888"; + description = mdDoc "The address to listen on for metrics. This should be on a different port to the main `server.port` value."; + }; + }; + }; + }; + }; + }; + + settingsFiles = mkOption { + type = types.listOf types.path; + default = [ ]; + example = [ "/etc/authelia/config.yml" "/etc/authelia/access-control.yml" "/etc/authelia/config/" ]; + description = mdDoc '' + Here you can provide authelia with configuration files or directories. + It is possible to give authelia multiple files and use the nix generated configuration + file set via {option}`services.authelia.<instance>.settings`. + ''; + }; + }; + }; +in +{ + options.services.authelia.instances = with lib; mkOption { + default = { }; + type = types.attrsOf (types.submodule autheliaOpts); + description = mdDoc '' + Multi-domain protection currently requires multiple instances of Authelia. + If you don't require multiple instances of Authelia you can define just the one. + + https://www.authelia.com/roadmap/active/multi-domain-protection/ + ''; + example = '' + { + main = { + enable = true; + secrets.storageEncryptionKeyFile = "/etc/authelia/storageEncryptionKeyFile"; + secrets.jwtSecretFile = "/etc/authelia/jwtSecretFile"; + settings = { + theme = "light"; + default_2fa_method = "totp"; + log.level = "debug"; + server.disable_healthcheck = true; + }; + }; + preprod = { + enable = false; + secrets.storageEncryptionKeyFile = "/mnt/pre-prod/authelia/storageEncryptionKeyFile"; + secrets.jwtSecretFile = "/mnt/pre-prod/jwtSecretFile"; + settings = { + theme = "dark"; + default_2fa_method = "webauthn"; + server.host = "0.0.0.0"; + }; + }; + test.enable = true; + test.secrets.manual = true; + test.settings.theme = "grey"; + test.settings.server.disable_healthcheck = true; + test.settingsFiles = [ "/mnt/test/authelia" "/mnt/test-authelia.conf" ]; + }; + } + ''; + }; + + config = + let + mkInstanceServiceConfig = instance: + let + execCommand = "${instance.package}/bin/authelia"; + configFile = format.generate "config.yml" instance.settings; + configArg = "--config ${builtins.concatStringsSep "," (lib.concatLists [[configFile] instance.settingsFiles])}"; + in + { + description = "Authelia authentication and authorization server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + environment = + (lib.filterAttrs (_: v: v != null) { + AUTHELIA_JWT_SECRET_FILE = instance.secrets.jwtSecretFile; + AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE = instance.secrets.storageEncryptionKeyFile; + AUTHELIA_SESSION_SECRET_FILE = instance.secrets.sessionSecretFile; + AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY_FILE = instance.secrets.oidcIssuerPrivateKeyFile; + AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE = instance.secrets.oidcHmacSecretFile; + }) + // instance.environmentVariables; + + preStart = "${execCommand} ${configArg} validate-config"; + serviceConfig = { + User = instance.user; + Group = instance.group; + ExecStart = "${execCommand} ${configArg}"; + Restart = "always"; + RestartSec = "5s"; + StateDirectory = "authelia-${instance.name}"; + StateDirectoryMode = "0700"; + + # Security options: + AmbientCapabilities = ""; + CapabilityBoundingSet = ""; + DeviceAllow = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = true; + + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = "read-only"; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "noaccess"; + ProtectSystem = "strict"; + + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + + SystemCallArchitectures = "native"; + SystemCallErrorNumber = "EPERM"; + SystemCallFilter = [ + "@system-service" + "~@cpu-emulation" + "~@debug" + "~@keyring" + "~@memlock" + "~@obsolete" + "~@privileged" + "~@setuid" + ]; + }; + }; + mkInstanceUsersConfig = instance: { + groups."authelia-${instance.name}" = + lib.mkIf (instance.group == "authelia-${instance.name}") { + name = "authelia-${instance.name}"; + }; + users."authelia-${instance.name}" = + lib.mkIf (instance.user == "authelia-${instance.name}") { + name = "authelia-${instance.name}"; + isSystemUser = true; + group = instance.group; + }; + }; + instances = lib.attrValues cfg.instances; + in + { + assertions = lib.flatten (lib.flip lib.mapAttrsToList cfg.instances (name: instance: + [ + { + assertion = instance.secrets.manual || (instance.secrets.jwtSecretFile != null && instance.secrets.storageEncryptionKeyFile != null); + message = '' + Authelia requires a JWT Secret and a Storage Encryption Key to work. + Either set them like so: + services.authelia.${name}.secrets.jwtSecretFile = /my/path/to/jwtsecret; + services.authelia.${name}.secrets.storageEncryptionKeyFile = /my/path/to/encryptionkey; + Or set services.authelia.${name}.secrets.manual = true and provide them yourself via + environmentVariables or settingsFiles. + Do not include raw secrets in nix settings. + ''; + } + ] + )); + + systemd.services = lib.mkMerge + (map + (instance: lib.mkIf instance.enable { + "authelia-${instance.name}" = mkInstanceServiceConfig instance; + }) + instances); + users = lib.mkMerge + (map + (instance: lib.mkIf instance.enable (mkInstanceUsersConfig instance)) + instances); + }; +} diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix index 3c4bcd1ac2659..ead24d1470717 100644 --- a/nixos/modules/services/security/fail2ban.nix +++ b/nixos/modules/services/security/fail2ban.nix @@ -273,26 +273,16 @@ in "fail2ban/filter.d".source = "${cfg.package}/etc/fail2ban/filter.d/*.conf"; }; + systemd.packages = [ cfg.package ]; systemd.services.fail2ban = { - description = "Fail2ban Intrusion Prevention System"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; partOf = optional config.networking.firewall.enable "firewall.service"; restartTriggers = [ fail2banConf jailConf pathsConf ]; path = [ cfg.package cfg.packageFirewall pkgs.iproute2 ] ++ cfg.extraPackages; - unitConfig.Documentation = "man:fail2ban(1)"; - serviceConfig = { - ExecStart = "${cfg.package}/bin/fail2ban-server -xf start"; - ExecStop = "${cfg.package}/bin/fail2ban-server stop"; - ExecReload = "${cfg.package}/bin/fail2ban-server reload"; - Type = "simple"; - Restart = "on-failure"; - PIDFile = "/run/fail2ban/fail2ban.pid"; # Capabilities CapabilityBoundingSet = [ "CAP_AUDIT_READ" "CAP_DAC_READ_SEARCH" "CAP_NET_ADMIN" "CAP_NET_RAW" ]; # Security diff --git a/nixos/modules/services/system/cachix-watch-store.nix b/nixos/modules/services/system/cachix-watch-store.nix index ec73c0bcdcfe5..85e9509bcc82d 100644 --- a/nixos/modules/services/system/cachix-watch-store.nix +++ b/nixos/modules/services/system/cachix-watch-store.nix @@ -25,7 +25,7 @@ in compressionLevel = mkOption { type = types.nullOr types.int; - description = lib.mdDoc "The compression level for XZ compression (between 0 and 9)"; + description = lib.mdDoc "The compression level for ZSTD compression (between 0 and 16)"; default = null; }; diff --git a/nixos/modules/services/system/self-deploy.nix b/nixos/modules/services/system/self-deploy.nix index 16a793a42253c..5f9ee06124cb4 100644 --- a/nixos/modules/services/system/self-deploy.nix +++ b/nixos/modules/services/system/self-deploy.nix @@ -132,7 +132,7 @@ in requires = lib.mkIf (!(isPathType cfg.repository)) [ "network-online.target" ]; - environment.GIT_SSH_COMMAND = lib.mkIf (!(isNull cfg.sshKeyFile)) + environment.GIT_SSH_COMMAND = lib.mkIf (cfg.sshKeyFile != null) "${pkgs.openssh}/bin/ssh -i ${lib.escapeShellArg cfg.sshKeyFile}"; restartIfChanged = false; diff --git a/nixos/modules/services/web-apps/baget.nix b/nixos/modules/services/web-apps/baget.nix deleted file mode 100644 index e4d5a1faddb2e..0000000000000 --- a/nixos/modules/services/web-apps/baget.nix +++ /dev/null @@ -1,170 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.services.baget; - - defaultConfig = { - "PackageDeletionBehavior" = "Unlist"; - "AllowPackageOverwrites" = false; - - "Database" = { - "Type" = "Sqlite"; - "ConnectionString" = "Data Source=baget.db"; - }; - - "Storage" = { - "Type" = "FileSystem"; - "Path" = ""; - }; - - "Search" = { - "Type" = "Database"; - }; - - "Mirror" = { - "Enabled" = false; - "PackageSource" = "https://api.nuget.org/v3/index.json"; - }; - - "Logging" = { - "IncludeScopes" = false; - "Debug" = { - "LogLevel" = { - "Default" = "Warning"; - }; - }; - "Console" = { - "LogLevel" = { - "Microsoft.Hosting.Lifetime" = "Information"; - "Default" = "Warning"; - }; - }; - }; - }; - - configAttrs = recursiveUpdate defaultConfig cfg.extraConfig; - - configFormat = pkgs.formats.json {}; - configFile = configFormat.generate "appsettings.json" configAttrs; - -in -{ - options.services.baget = { - enable = mkEnableOption (lib.mdDoc "BaGet NuGet-compatible server"); - - apiKeyFile = mkOption { - type = types.path; - example = "/root/baget.key"; - description = lib.mdDoc '' - Private API key for BaGet. - ''; - }; - - extraConfig = mkOption { - type = configFormat.type; - default = {}; - example = { - "Database" = { - "Type" = "PostgreSql"; - "ConnectionString" = "Server=/run/postgresql;Port=5432;"; - }; - }; - defaultText = literalExpression '' - { - "PackageDeletionBehavior" = "Unlist"; - "AllowPackageOverwrites" = false; - - "Database" = { - "Type" = "Sqlite"; - "ConnectionString" = "Data Source=baget.db"; - }; - - "Storage" = { - "Type" = "FileSystem"; - "Path" = ""; - }; - - "Search" = { - "Type" = "Database"; - }; - - "Mirror" = { - "Enabled" = false; - "PackageSource" = "https://api.nuget.org/v3/index.json"; - }; - - "Logging" = { - "IncludeScopes" = false; - "Debug" = { - "LogLevel" = { - "Default" = "Warning"; - }; - }; - "Console" = { - "LogLevel" = { - "Microsoft.Hosting.Lifetime" = "Information"; - "Default" = "Warning"; - }; - }; - }; - } - ''; - description = lib.mdDoc '' - Extra configuration options for BaGet. Refer to <https://loic-sharma.github.io/BaGet/configuration/> for details. - Default value is merged with values from here. - ''; - }; - }; - - # implementation - - config = mkIf cfg.enable { - - systemd.services.baget = { - description = "BaGet server"; - wantedBy = [ "multi-user.target" ]; - wants = [ "network-online.target" ]; - after = [ "network.target" "network-online.target" ]; - path = [ pkgs.jq ]; - serviceConfig = { - WorkingDirectory = "/var/lib/baget"; - DynamicUser = true; - StateDirectory = "baget"; - StateDirectoryMode = "0700"; - LoadCredential = "api_key:${cfg.apiKeyFile}"; - - CapabilityBoundingSet = ""; - NoNewPrivileges = true; - PrivateDevices = true; - PrivateTmp = true; - PrivateUsers = true; - PrivateMounts = true; - ProtectHome = true; - ProtectClock = true; - ProtectProc = "noaccess"; - ProcSubset = "pid"; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectControlGroups = true; - ProtectHostname = true; - RestrictSUIDSGID = true; - RestrictRealtime = true; - RestrictNamespaces = true; - LockPersonality = true; - RemoveIPC = true; - RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; - SystemCallFilter = [ "@system-service" "~@privileged" ]; - }; - script = '' - jq --slurpfile apiKeys <(jq -R . "$CREDENTIALS_DIRECTORY/api_key") '.ApiKey = $apiKeys[0]' ${configFile} > appsettings.json - ln -snf ${pkgs.baget}/lib/BaGet/wwwroot wwwroot - exec ${pkgs.baget}/bin/BaGet - ''; - }; - - }; -} diff --git a/nixos/modules/services/web-apps/dolibarr.nix b/nixos/modules/services/web-apps/dolibarr.nix index a9df391128ee5..453229c130c22 100644 --- a/nixos/modules/services/web-apps/dolibarr.nix +++ b/nixos/modules/services/web-apps/dolibarr.nix @@ -16,7 +16,7 @@ let if (any (str: k == str) secretKeys) then v else if isString v then "'${v}'" else if isBool v then boolToString v - else if isNull v then "null" + else if v == null then "null" else toString v ; in diff --git a/nixos/modules/services/web-apps/jitsi-meet.nix b/nixos/modules/services/web-apps/jitsi-meet.nix index 28be3a3702eb6..3825b03c24496 100644 --- a/nixos/modules/services/web-apps/jitsi-meet.nix +++ b/nixos/modules/services/web-apps/jitsi-meet.nix @@ -411,11 +411,14 @@ in componentPasswordFile = "/var/lib/jitsi-meet/jicofo-component-secret"; bridgeMuc = "jvbbrewery@internal.${cfg.hostName}"; config = mkMerge [{ - "org.jitsi.jicofo.ALWAYS_TRUST_MODE_ENABLED" = "true"; + jicofo.xmpp.service.disable-certificate-verification = true; + jicofo.xmpp.client.disable-certificate-verification = true; #} (lib.mkIf cfg.jibri.enable { } (lib.mkIf (config.services.jibri.enable || cfg.jibri.enable) { - "org.jitsi.jicofo.jibri.BREWERY" = "JibriBrewery@internal.${cfg.hostName}"; - "org.jitsi.jicofo.jibri.PENDING_TIMEOUT" = "90"; + jicofo.jibri = { + brewery-jid = "JibriBrewery@internal.${cfg.hostName}"; + pending-timeout = "90"; + }; })]; }; diff --git a/nixos/modules/services/web-apps/limesurvey.nix b/nixos/modules/services/web-apps/limesurvey.nix index dd51174c8b8e0..8e6b39cbdebcb 100644 --- a/nixos/modules/services/web-apps/limesurvey.nix +++ b/nixos/modules/services/web-apps/limesurvey.nix @@ -34,6 +34,24 @@ in options.services.limesurvey = { enable = mkEnableOption (lib.mdDoc "Limesurvey web application"); + encryptionKey = mkOption { + type = types.str; + default = "E17687FC77CEE247F0E22BB3ECF27FDE8BEC310A892347EC13013ABA11AA7EB5"; + description = lib.mdDoc '' + This is a 32-byte key used to encrypt variables in the database. + You _must_ change this from the default value. + ''; + }; + + encryptionNonce = mkOption { + type = types.str; + default = "1ACC8555619929DB91310BE848025A427B0F364A884FFA77"; + description = lib.mdDoc '' + This is a 24-byte nonce used to encrypt variables in the database. + You _must_ change this from the default value. + ''; + }; + database = { type = mkOption { type = types.enum [ "mysql" "pgsql" "odbc" "mssql" ]; @@ -42,6 +60,12 @@ in description = lib.mdDoc "Database engine to use."; }; + dbEngine = mkOption { + type = types.enum [ "MyISAM" "InnoDB" ]; + default = "InnoDB"; + description = lib.mdDoc "Database storage engine to use."; + }; + host = mkOption { type = types.str; default = "localhost"; @@ -180,6 +204,8 @@ in config = { tempdir = "${stateDir}/tmp"; uploaddir = "${stateDir}/upload"; + encryptionnonce = cfg.encryptionNonce; + encryptionsecretboxkey = cfg.encryptionKey; force_ssl = mkIf (cfg.virtualHost.addSSL || cfg.virtualHost.forceSSL || cfg.virtualHost.onlySSL) "on"; config.defaultlang = "en"; }; @@ -200,6 +226,8 @@ in services.phpfpm.pools.limesurvey = { inherit user group; + phpPackage = pkgs.php80; + phpEnv.DBENGINE = "${cfg.database.dbEngine}"; phpEnv.LIMESURVEY_CONFIG = "${limesurveyConfig}"; settings = { "listen.owner" = config.services.httpd.user; @@ -256,11 +284,12 @@ in wantedBy = [ "multi-user.target" ]; before = [ "phpfpm-limesurvey.service" ]; after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service"; + environment.DBENGINE = "${cfg.database.dbEngine}"; environment.LIMESURVEY_CONFIG = limesurveyConfig; script = '' # update or install the database as required - ${pkgs.php}/bin/php ${pkg}/share/limesurvey/application/commands/console.php updatedb || \ - ${pkgs.php}/bin/php ${pkg}/share/limesurvey/application/commands/console.php install admin password admin admin@example.com verbose + ${pkgs.php80}/bin/php ${pkg}/share/limesurvey/application/commands/console.php updatedb || \ + ${pkgs.php80}/bin/php ${pkg}/share/limesurvey/application/commands/console.php install admin password admin admin@example.com verbose ''; serviceConfig = { User = user; diff --git a/nixos/modules/services/web-apps/mattermost.nix b/nixos/modules/services/web-apps/mattermost.nix index 56a53198b3fbf..db5122e79f006 100644 --- a/nixos/modules/services/web-apps/mattermost.nix +++ b/nixos/modules/services/web-apps/mattermost.nix @@ -184,6 +184,22 @@ in .tar.gz files. ''; }; + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Environment file (see {manpage}`systemd.exec(5)` + "EnvironmentFile=" section for the syntax) which sets config options + for mattermost (see [the mattermost documentation](https://docs.mattermost.com/configure/configuration-settings.html#environment-variables)). + + Settings defined in the environment file will overwrite settings + set via nix or via the {option}`services.mattermost.extraConfig` + option. + + Useful for setting config options without their value ending up in the + (world-readable) nix store, e.g. for a database password. + ''; + }; localDatabaseCreate = mkOption { type = types.bool; @@ -321,6 +337,7 @@ in Restart = "always"; RestartSec = "10"; LimitNOFILE = "49152"; + EnvironmentFile = cfg.environmentFile; }; unitConfig.JoinsNamespaceOf = mkIf cfg.localDatabaseCreate "postgresql.service"; }; diff --git a/nixos/modules/services/web-apps/nextcloud.md b/nixos/modules/services/web-apps/nextcloud.md index 014807f3da23c..7ef3cca281f9e 100644 --- a/nixos/modules/services/web-apps/nextcloud.md +++ b/nixos/modules/services/web-apps/nextcloud.md @@ -5,7 +5,7 @@ self-hostable cloud platform. The server setup can be automated using [services.nextcloud](#opt-services.nextcloud.enable). A desktop client is packaged at `pkgs.nextcloud-client`. -The current default by NixOS is `nextcloud25` which is also the latest +The current default by NixOS is `nextcloud26` which is also the latest major version available. ## Basic usage {#module-services-nextcloud-basic-usage} diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index c5e161c2516ad..76a0172747ffd 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -204,7 +204,7 @@ in { package = mkOption { type = types.package; description = lib.mdDoc "Which package to use for the Nextcloud instance."; - relatedPackages = [ "nextcloud24" "nextcloud25" ]; + relatedPackages = [ "nextcloud24" "nextcloud25" "nextcloud26" ]; }; phpPackage = mkOption { type = types.package; @@ -514,6 +514,27 @@ in { `http://hostname.domain/bucket` instead. ''; }; + sseCKeyFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/var/nextcloud-objectstore-s3-sse-c-key"; + description = lib.mdDoc '' + If provided this is the full path to a file that contains the key + to enable [server-side encryption with customer-provided keys][1] + (SSE-C). + + The file must contain a random 32-byte key encoded as a base64 + string, e.g. generated with the command + + ``` + openssl rand 32 | base64 + ``` + + Must be readable by user `nextcloud`. + + [1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html + ''; + }; }; }; }; @@ -652,7 +673,7 @@ in { config = mkIf cfg.enable (mkMerge [ { warnings = let - latest = 25; + latest = 26; upgradeWarning = major: nixos: '' A legacy Nextcloud install (from before NixOS ${nixos}) may be installed. @@ -667,20 +688,6 @@ in { `services.nextcloud.package`. ''; - # FIXME(@Ma27) remove as soon as nextcloud properly supports - # mariadb >=10.6. - isUnsupportedMariadb = - # All currently supported Nextcloud versions are affected (https://github.com/nextcloud/server/issues/25436). - (versionOlder cfg.package.version "24") - # This module uses mysql - && (cfg.config.dbtype == "mysql") - # MySQL is managed via NixOS - && config.services.mysql.enable - # We're using MariaDB - && (getName config.services.mysql.package) == "mariadb-server" - # MariaDB is at least 10.6 and thus not supported - && (versionAtLeast (getVersion config.services.mysql.package) "10.6"); - in (optional (cfg.poolConfig != null) '' Using config.services.nextcloud.poolConfig is deprecated and will become unsupported in a future release. Please migrate your configuration to config.services.nextcloud.poolSettings. @@ -688,6 +695,7 @@ in { ++ (optional (versionOlder cfg.package.version "23") (upgradeWarning 22 "22.05")) ++ (optional (versionOlder cfg.package.version "24") (upgradeWarning 23 "22.05")) ++ (optional (versionOlder cfg.package.version "25") (upgradeWarning 24 "22.11")) + ++ (optional (versionOlder cfg.package.version "26") (upgradeWarning 25 "23.05")) ++ (optional cfg.enableBrokenCiphersForSSE '' You're using PHP's openssl extension built against OpenSSL 1.1 for Nextcloud. This is only necessary if you're using Nextcloud's server-side encryption. @@ -704,18 +712,7 @@ in { See <https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/encryption_configuration.html#disabling-encryption> on how to achieve this. For more context, here is the implementing pull request: https://github.com/NixOS/nixpkgs/pull/198470 - '') - ++ (optional isUnsupportedMariadb '' - You seem to be using MariaDB at an unsupported version (i.e. at least 10.6)! - Please note that this isn't supported officially by Nextcloud. You can either - - * Switch to `pkgs.mysql` - * Downgrade MariaDB to at least 10.5 - * Work around Nextcloud's problems by specifying `innodb_read_only_compressed=0` - - For further context, please read - https://help.nextcloud.com/t/update-to-next-cloud-21-0-2-has-get-an-error/117028/15 - ''); + ''); services.nextcloud.package = with pkgs; mkDefault ( @@ -726,12 +723,13 @@ in { `pkgs.nextcloud`. '' else if versionOlder stateVersion "22.11" then nextcloud24 - else nextcloud25 + else if versionOlder stateVersion "23.05" then nextcloud25 + else nextcloud26 ); services.nextcloud.phpPackage = - if versionOlder cfg.package.version "24" then pkgs.php80 - else pkgs.php81; + if versionOlder cfg.package.version "26" then pkgs.php81 + else pkgs.php82; } { assertions = [ @@ -773,6 +771,7 @@ in { 'use_ssl' => ${boolToString s3.useSsl}, ${optionalString (s3.region != null) "'region' => '${s3.region}',"} 'use_path_style' => ${boolToString s3.usePathStyle}, + ${optionalString (s3.sseCKeyFile != null) "'sse_c_key' => nix_read_secret('${s3.sseCKeyFile}'),"} ], ] ''; @@ -958,6 +957,9 @@ in { ''; serviceConfig.Type = "oneshot"; serviceConfig.User = "nextcloud"; + # On Nextcloud ≥ 26, it is not necessary to patch the database files to prevent + # an automatic creation of the database user. + environment.NC_setup_create_db_user = lib.mkIf (nextcloudGreaterOrEqualThan "26") "false"; }; nextcloud-cron = { after = [ "nextcloud-setup.service" ]; @@ -1009,14 +1011,6 @@ in { name = cfg.config.dbuser; ensurePermissions = { "${cfg.config.dbname}.*" = "ALL PRIVILEGES"; }; }]; - # FIXME(@Ma27) Nextcloud isn't compatible with mariadb 10.6, - # this is a workaround. - # See https://help.nextcloud.com/t/update-to-next-cloud-21-0-2-has-get-an-error/117028/22 - settings = mkIf (versionOlder cfg.package.version "24") { - mysqld = { - innodb_read_only_compressed = 0; - }; - }; initialScript = pkgs.writeText "mysql-init" '' CREATE USER '${cfg.config.dbname}'@'localhost' IDENTIFIED BY '${builtins.readFile( cfg.config.dbpassFile )}'; CREATE DATABASE IF NOT EXISTS ${cfg.config.dbname}; @@ -1118,7 +1112,7 @@ in { ${optionalString (cfg.nginx.recommendedHttpHeaders) '' add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; + add_header X-Robots-Tag "noindex, nofollow"; add_header X-Download-Options noopen; add_header X-Permitted-Cross-Domain-Policies none; add_header X-Frame-Options sameorigin; diff --git a/nixos/modules/services/web-apps/writefreely.nix b/nixos/modules/services/web-apps/writefreely.nix index dec00b46f335e..a7671aa717f43 100644 --- a/nixos/modules/services/web-apps/writefreely.nix +++ b/nixos/modules/services/web-apps/writefreely.nix @@ -10,12 +10,11 @@ let format = pkgs.formats.ini { mkKeyValue = key: value: let - value' = if builtins.isNull value then - "" - else if builtins.isBool value then - if value == true then "true" else "false" - else - toString value; + value' = lib.optionalString (value != null) + (if builtins.isBool value then + if value == true then "true" else "false" + else + toString value); in "${key} = ${value'}"; }; diff --git a/nixos/modules/services/web-servers/garage.nix b/nixos/modules/services/web-servers/garage.nix index 2491c788d6c51..df8ed96f8d908 100644 --- a/nixos/modules/services/web-servers/garage.nix +++ b/nixos/modules/services/web-servers/garage.nix @@ -60,7 +60,7 @@ in package = mkOption { # TODO: when 23.05 is released and if Garage 0.9 is the default, put a stateVersion check. - default = if versionAtLeast stateVersion "23.05" then pkgs.garage_0_8_0 + default = if versionAtLeast config.system.stateVersion "23.05" then pkgs.garage_0_8 else pkgs.garage_0_7; defaultText = literalExpression "pkgs.garage_0_7"; type = types.package; diff --git a/nixos/modules/services/web-servers/minio.nix b/nixos/modules/services/web-servers/minio.nix index 1a9eacb431b3c..21bec4f63a879 100644 --- a/nixos/modules/services/web-servers/minio.nix +++ b/nixos/modules/services/web-servers/minio.nix @@ -60,7 +60,7 @@ in ''; }; - rootCredentialsFile = mkOption { + rootCredentialsFile = mkOption { type = types.nullOr types.path; default = null; description = lib.mdDoc '' @@ -96,29 +96,62 @@ in config = mkIf cfg.enable { warnings = optional ((cfg.accessKey != "") || (cfg.secretKey != "")) "services.minio.`accessKey` and services.minio.`secretKey` are deprecated, please use services.minio.`rootCredentialsFile` instead."; - systemd.tmpfiles.rules = [ - "d '${cfg.configDir}' - minio minio - -" - ] ++ (map (x: "d '" + x + "' - minio minio - - ") cfg.dataDir); - - systemd.services.minio = { - description = "Minio Object Storage"; - after = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${cfg.package}/bin/minio server --json --address ${cfg.listenAddress} --console-address ${cfg.consoleAddress} --config-dir=${cfg.configDir} ${toString cfg.dataDir}"; - Type = "simple"; - User = "minio"; - Group = "minio"; - LimitNOFILE = 65536; - EnvironmentFile = if (cfg.rootCredentialsFile != null) then cfg.rootCredentialsFile - else if ((cfg.accessKey != "") || (cfg.secretKey != "")) then (legacyCredentials cfg) - else null; + systemd = lib.mkMerge [{ + tmpfiles.rules = [ + "d '${cfg.configDir}' - minio minio - -" + ] ++ (map (x: "d '" + x + "' - minio minio - - ") cfg.dataDir); + + services.minio = { + description = "Minio Object Storage"; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${cfg.package}/bin/minio server --json --address ${cfg.listenAddress} --console-address ${cfg.consoleAddress} --config-dir=${cfg.configDir} ${toString cfg.dataDir}"; + Type = "simple"; + User = "minio"; + Group = "minio"; + LimitNOFILE = 65536; + EnvironmentFile = + if (cfg.rootCredentialsFile != null) then cfg.rootCredentialsFile + else if ((cfg.accessKey != "") || (cfg.secretKey != "")) then (legacyCredentials cfg) + else null; + }; + environment = { + MINIO_REGION = "${cfg.region}"; + MINIO_BROWSER = "${if cfg.browser then "on" else "off"}"; + }; }; - environment = { - MINIO_REGION = "${cfg.region}"; - MINIO_BROWSER = "${if cfg.browser then "on" else "off"}"; - }; - }; + } + + (lib.mkIf (cfg.rootCredentialsFile != null) { + # The service will fail if the credentials file is missing + services.minio.unitConfig.ConditionPathExists = cfg.rootCredentialsFile; + + # The service will not restart if the credentials file has + # been changed. This can cause stale root credentials. + paths.minio-root-credentials = { + wantedBy = [ "multi-user.target" ]; + + pathConfig = { + PathChanged = [ cfg.rootCredentialsFile ]; + Unit = "minio-restart.service"; + }; + }; + + services.minio-restart = { + description = "Restart MinIO"; + + script = '' + systemctl restart minio.service + ''; + + serviceConfig = { + Type = "oneshot"; + Restart = "on-failure"; + RestartSec = 5; + }; + }; + })]; users.users.minio = { group = "minio"; diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 905dd5bef1f71..064c86a9a7e29 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -184,8 +184,8 @@ let brotli_types ${lib.concatStringsSep " " compressMimeTypes}; ''} - # https://docs.nginx.com/nginx/admin-guide/web-server/compression/ ${optionalString cfg.recommendedGzipSettings '' + # https://docs.nginx.com/nginx/admin-guide/web-server/compression/ gzip on; gzip_static on; gzip_vary on; @@ -195,6 +195,14 @@ let gzip_types ${lib.concatStringsSep " " compressMimeTypes}; ''} + ${optionalString cfg.recommendedZstdSettings '' + zstd on; + zstd_comp_level 9; + zstd_min_length 256; + zstd_static on; + zstd_types ${lib.concatStringsSep " " compressMimeTypes}; + ''} + ${optionalString cfg.recommendedProxySettings '' proxy_redirect off; proxy_connect_timeout ${cfg.proxyTimeout}; @@ -490,6 +498,16 @@ in ''; }; + recommendedZstdSettings = mkOption { + default = false; + type = types.bool; + description = lib.mdDoc '' + Enable recommended zstd settings. Learn more about compression in Zstd format [here](https://github.com/tokers/zstd-nginx-module). + + This adds `pkgs.nginxModules.zstd` to `services.nginx.additionalModules`. + ''; + }; + proxyTimeout = mkOption { type = types.str; default = "60s"; @@ -1015,7 +1033,8 @@ in groups = config.users.groups; }) dependentCertNames; - services.nginx.additionalModules = optional cfg.recommendedBrotliSettings pkgs.nginxModules.brotli; + services.nginx.additionalModules = optional cfg.recommendedBrotliSettings pkgs.nginxModules.brotli + ++ lib.optional cfg.recommendedZstdSettings pkgs.nginxModules.zstd; systemd.services.nginx = { description = "Nginx Web Server"; diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index f0c4b2172f9d2..73a864bb95fe8 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -81,99 +81,90 @@ let in { - options.services.xserver.desktopManager.plasma5 = { - enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Enable the Plasma 5 (KDE 5) desktop environment."; - }; - - phononBackend = mkOption { - type = types.enum [ "gstreamer" "vlc" ]; - default = "vlc"; - example = "gstreamer"; - description = lib.mdDoc "Phonon audio backend to install."; - }; - - supportDDC = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Support setting monitor brightness via DDC. - - This is not needed for controlling brightness of the internal monitor - of a laptop and as it is considered experimental by upstream, it is - disabled by default. - ''; - }; + options = { + services.xserver.desktopManager.plasma5 = { + enable = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc "Enable the Plasma 5 (KDE 5) desktop environment."; + }; - useQtScaling = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Enable HiDPI scaling in Qt."; - }; + phononBackend = mkOption { + type = types.enum [ "gstreamer" "vlc" ]; + default = "vlc"; + example = "gstreamer"; + description = lib.mdDoc "Phonon audio backend to install."; + }; - runUsingSystemd = mkOption { - description = lib.mdDoc "Use systemd to manage the Plasma session"; - type = types.bool; - default = true; - }; + useQtScaling = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc "Enable HiDPI scaling in Qt."; + }; - excludePackages = mkOption { - description = lib.mdDoc "List of default packages to exclude from the configuration"; - type = types.listOf types.package; - default = []; - example = literalExpression "[ pkgs.plasma5Packages.oxygen ]"; - }; + runUsingSystemd = mkOption { + description = lib.mdDoc "Use systemd to manage the Plasma session"; + type = types.bool; + default = true; + }; - notoPackage = mkPackageOptionMD pkgs "Noto fonts" { - default = [ "noto-fonts" ]; - example = "noto-fonts-lgc-plus"; - }; + notoPackage = mkPackageOptionMD pkgs "Noto fonts" { + default = [ "noto-fonts" ]; + example = "noto-fonts-lgc-plus"; + }; - # Internally allows configuring kdeglobals globally - kdeglobals = mkOption { - internal = true; - default = {}; - type = kdeConfigurationType; - }; + # Internally allows configuring kdeglobals globally + kdeglobals = mkOption { + internal = true; + default = {}; + type = kdeConfigurationType; + }; - # Internally allows configuring kwin globally - kwinrc = mkOption { - internal = true; - default = {}; - type = kdeConfigurationType; - }; + # Internally allows configuring kwin globally + kwinrc = mkOption { + internal = true; + default = {}; + type = kdeConfigurationType; + }; - mobile.enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Enable support for running the Plasma Mobile shell. - ''; - }; + mobile.enable = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Enable support for running the Plasma Mobile shell. + ''; + }; - mobile.installRecommendedSoftware = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Installs software recommended for use with Plasma Mobile, but which - is not strictly required for Plasma Mobile to run. - ''; - }; + mobile.installRecommendedSoftware = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Installs software recommended for use with Plasma Mobile, but which + is not strictly required for Plasma Mobile to run. + ''; + }; - bigscreen.enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Enable support for running the Plasma Bigscreen session. - ''; + bigscreen.enable = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Enable support for running the Plasma Bigscreen session. + ''; + }; }; + environment.plasma5.excludePackages = mkOption { + description = lib.mdDoc "List of default packages to exclude from the configuration"; + type = types.listOf types.package; + default = []; + example = literalExpression "[ pkgs.plasma5Packages.oxygen ]"; + }; }; imports = [ (mkRemovedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "enableQt4Support" ] "Phonon no longer supports Qt 4.") + (mkRemovedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "supportDDC" ] "DDC/CI is no longer supported upstream.") (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "kde5" ] [ "services" "xserver" "desktopManager" "plasma5" ]) + (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "excludePackages" ] [ "environment" "plasma5" "excludePackages" ]) ]; config = mkMerge [ @@ -201,12 +192,6 @@ in }; }; - # DDC support - boot.kernelModules = lib.optional cfg.supportDDC "i2c_dev"; - services.udev.extraRules = lib.optionalString cfg.supportDDC '' - KERNEL=="i2c-[0-9]*", TAG+="uaccess" - ''; - environment.systemPackages = with libsForQt5; with plasma5; with kdeGear; with kdeFrameworks; @@ -301,7 +286,7 @@ in ]; in requiredPackages - ++ utils.removePackagesByName optionalPackages cfg.excludePackages + ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages # Phonon audio backend ++ lib.optional (cfg.phononBackend == "gstreamer") libsForQt5.phonon-backend-gstreamer @@ -455,7 +440,7 @@ in khelpcenter print-manager ]; - in requiredPackages ++ utils.removePackagesByName optionalPackages cfg.excludePackages; + in requiredPackages ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages; systemd.user.services = { plasma-run-with-systemd = { diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index 1c3881bef2de2..f8f82bda3fa43 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -323,7 +323,7 @@ in account sufficient pam_unix.so - password requisite pam_unix.so nullok sha512 + password requisite pam_unix.so nullok yescrypt session optional pam_keyinit.so revoke session include login diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 65f414705fc51..548d3c5bc46a5 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -302,7 +302,7 @@ in account sufficient pam_unix.so - password requisite pam_unix.so nullok sha512 + password requisite pam_unix.so nullok yescrypt session optional pam_keyinit.so revoke session include login diff --git a/nixos/modules/services/x11/gdk-pixbuf.nix b/nixos/modules/services/x11/gdk-pixbuf.nix index 2105224f92ff3..9c088e4cc4237 100644 --- a/nixos/modules/services/x11/gdk-pixbuf.nix +++ b/nixos/modules/services/x11/gdk-pixbuf.nix @@ -21,7 +21,7 @@ in # loaders.cache based on that and set the environment variable # GDK_PIXBUF_MODULE_FILE to point to it. config = lib.mkIf (cfg.modulePackages != []) { - environment.variables = { + environment.sessionVariables = { GDK_PIXBUF_MODULE_FILE = "${loadersCache}"; }; }; diff --git a/nixos/modules/services/x11/window-managers/qtile.nix b/nixos/modules/services/x11/window-managers/qtile.nix index fc27566d49ee6..cc24522970f3a 100644 --- a/nixos/modules/services/x11/window-managers/qtile.nix +++ b/nixos/modules/services/x11/window-managers/qtile.nix @@ -1,23 +1,63 @@ -{ config, lib, pkgs, ... }: +{ config, pkgs, lib, ... }: with lib; let cfg = config.services.xserver.windowManager.qtile; + pyEnv = pkgs.python3.withPackages (p: [ (cfg.package.unwrapped or cfg.package) ] ++ (cfg.extraPackages p)); in { options.services.xserver.windowManager.qtile = { enable = mkEnableOption (lib.mdDoc "qtile"); - package = mkPackageOptionMD pkgs "qtile" { }; + package = mkPackageOptionMD pkgs "qtile-unwrapped" { }; + + configFile = mkOption { + type = with types; nullOr path; + default = null; + example = literalExpression "./your_config.py"; + description = lib.mdDoc '' + Path to the qtile configuration file. + If null, $XDG_CONFIG_HOME/qtile/config.py will be used. + ''; + }; + + backend = mkOption { + type = types.enum [ "x11" "wayland" ]; + default = "x11"; + description = lib.mdDoc '' + Backend to use in qtile: + <option>x11</option> or <option>wayland</option>. + ''; + }; + + extraPackages = mkOption { + type = types.functionTo (types.listOf types.package); + default = _: []; + defaultText = literalExpression '' + python3Packages: with python3Packages; []; + ''; + description = lib.mdDoc '' + Extra Python packages available to Qtile. + An example would be to include `python3Packages.qtile-extras` + for additional unoffical widgets. + ''; + example = literalExpression '' + python3Packages: with python3Packages; [ + qtile-extras + ]; + ''; + }; }; config = mkIf cfg.enable { services.xserver.windowManager.session = [{ name = "qtile"; start = '' - ${cfg.package}/bin/qtile start & + ${pyEnv}/bin/qtile start -b ${cfg.backend} \ + ${optionalString (cfg.configFile != null) + "--config \"${cfg.configFile}\""} & waitPID=$! ''; }]; diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index adb079c87a8b8..fcc18c9a26fd0 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -138,6 +138,26 @@ let concatMapStringsSep "\n" (line: prefix + line) (splitString "\n" str); indent = prefixStringLines " "; + + # A scalable variant of the X11 "core" cursor + # + # If not running a fancy desktop environment, the cursor is likely set to + # the default `cursor.pcf` bitmap font. This is 17px wide, so it's very + # small and almost invisible on 4K displays. + fontcursormisc_hidpi = pkgs.xorg.fontxfree86type1.overrideAttrs (old: + let + # The scaling constant is 230/96: the scalable `left_ptr` glyph at + # about 23 points is rendered as 17px, on a 96dpi display. + # Note: the XLFD font size is in decipoints. + size = 2.39583 * cfg.dpi; + sizeString = builtins.head (builtins.split "\\." (toString size)); + in + { + postInstall = '' + alias='cursor -xfree86-cursor-medium-r-normal--0-${sizeString}-0-0-p-0-adobe-fontspecific' + echo "$alias" > $out/lib/X11/fonts/Type1/fonts.alias + ''; + }); in { @@ -576,6 +596,15 @@ in Whether to terminate X upon server reset. ''; }; + + upscaleDefaultCursor = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Upscale the default X cursor to be more visible on high-density displays. + Requires `config.services.xserver.dpi` to be set. + ''; + }; }; }; @@ -592,7 +621,8 @@ in || dmConf.sddm.enable || dmConf.xpra.enable || dmConf.sx.enable - || dmConf.startx.enable); + || dmConf.startx.enable + || config.services.greetd.enable); in mkIf (default) (mkDefault true); # so that the service won't be enabled when only startx is used @@ -626,6 +656,10 @@ in + "${toString (length primaryHeads)} heads set to primary: " + concatMapStringsSep ", " (x: x.output) primaryHeads; }) + { + assertion = cfg.upscaleDefaultCursor -> cfg.dpi != null; + message = "Specify `config.services.xserver.dpi` to upscale the default cursor."; + } ]; environment.etc = @@ -850,6 +884,10 @@ in ''; fonts.enableDefaultFonts = mkDefault true; + fonts.fonts = [ + (if cfg.upscaleDefaultCursor then fontcursormisc_hidpi else pkgs.xorg.fontcursormisc) + pkgs.xorg.fontmiscmisc + ]; }; diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 240e209591752..896f8c0a69355 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -130,6 +130,13 @@ let pkgs.replaceDependency { inherit oldDependency newDependency drv; } ) baseSystemAssertWarn config.system.replaceRuntimeDependencies; + systemWithBuildDeps = system.overrideAttrs (o: { + systemBuildClosure = pkgs.closureInfo { rootPaths = [ system.drvPath ]; }; + buildCommand = o.buildCommand + '' + ln -sn $systemBuildClosure $out/build-closure + ''; + }); + in { @@ -306,6 +313,27 @@ in ''; }; + system.includeBuildDependencies = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Whether to include the build closure of the whole system in + its runtime closure. This can be useful for making changes + fully offline, as it includes all sources, patches, and + intermediate outputs required to build all the derivations + that the system depends on. + + Note that this includes _all_ the derivations, down from the + included applications to their sources, the compilers used to + build them, and even the bootstrap compiler used to compile + the compilers. This increases the size of the system and the + time needed to download its dependencies drastically: a + minimal configuration with no extra services enabled grows + from ~670MiB in size to 13.5GiB, and takes proportionally + longer to download. + ''; + }; + }; @@ -336,7 +364,7 @@ in ]; }; }; - system.build.toplevel = system; + system.build.toplevel = if config.system.includeBuildDependencies then systemWithBuildDeps else system; }; diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix index 98db67e7c00e0..cceb02c1a73b3 100644 --- a/nixos/modules/system/boot/binfmt.nix +++ b/nixos/modules/system/boot/binfmt.nix @@ -134,11 +134,11 @@ let mask = ''\xff\xff\xff\xff''; }; x86_64-windows = { - magicOrExtension = ".exe"; + magicOrExtension = "exe"; recognitionType = "extension"; }; i686-windows = { - magicOrExtension = ".exe"; + magicOrExtension = "exe"; recognitionType = "extension"; }; }; diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index cdb5d8bf3c26f..8954c90812f92 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -158,6 +158,20 @@ let wait_target "header" ${dev.header} || die "${dev.header} is unavailable" ''} + try_empty_passphrase() { + ${if dev.tryEmptyPassphrase then '' + echo "Trying empty passphrase!" + echo "" | ${csopen} + cs_status=$? + if [ $cs_status -eq 0 ]; then + return 0 + else + return 1 + fi + '' else "return 1"} + } + + do_open_passphrase() { local passphrase @@ -212,13 +226,27 @@ let ${csopen} --key-file=${dev.keyFile} \ ${optionalString (dev.keyFileSize != null) "--keyfile-size=${toString dev.keyFileSize}"} \ ${optionalString (dev.keyFileOffset != null) "--keyfile-offset=${toString dev.keyFileOffset}"} + cs_status=$? + if [ $cs_status -ne 0 ]; then + echo "Key File ${dev.keyFile} failed!" + if ! try_empty_passphrase; then + ${if dev.fallbackToPassword then "echo" else "die"} "${dev.keyFile} is unavailable" + echo " - failing back to interactive password prompt" + do_open_passphrase + fi + fi else - ${if dev.fallbackToPassword then "echo" else "die"} "${dev.keyFile} is unavailable" - echo " - failing back to interactive password prompt" - do_open_passphrase + # If the key file never shows up we should also try the empty passphrase + if ! try_empty_passphrase; then + ${if dev.fallbackToPassword then "echo" else "die"} "${dev.keyFile} is unavailable" + echo " - failing back to interactive password prompt" + do_open_passphrase + fi fi '' else '' - do_open_passphrase + if ! try_empty_passphrase; then + do_open_passphrase + fi ''} } @@ -476,6 +504,7 @@ let preLVM = filterAttrs (n: v: v.preLVM) luks.devices; postLVM = filterAttrs (n: v: !v.preLVM) luks.devices; + stage1Crypttab = pkgs.writeText "initrd-crypttab" (lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: let opts = v.crypttabExtraOpts ++ optional v.allowDiscards "discard" @@ -483,6 +512,8 @@ let ++ optional (v.header != null) "header=${v.header}" ++ optional (v.keyFileOffset != null) "keyfile-offset=${toString v.keyFileOffset}" ++ optional (v.keyFileSize != null) "keyfile-size=${toString v.keyFileSize}" + ++ optional (v.keyFileTimeout != null) "keyfile-timeout=${builtins.toString v.keyFileTimeout}s" + ++ optional (v.tryEmptyPassphrase) "try-empty-password=true" ; in "${n} ${v.device} ${if v.keyFile == null then "-" else v.keyFile} ${lib.concatStringsSep "," opts}") luks.devices)); @@ -594,6 +625,25 @@ in ''; }; + tryEmptyPassphrase = mkOption { + default = false; + type = types.bool; + description = lib.mdDoc '' + If keyFile fails then try an empty passphrase first before + prompting for password. + ''; + }; + + keyFileTimeout = mkOption { + default = null; + example = 5; + type = types.nullOr types.int; + description = lib.mdDoc '' + The amount of time in seconds for a keyFile to appear before + timing out and trying passwords. + ''; + }; + keyFileSize = mkOption { default = null; example = 4096; @@ -889,6 +939,10 @@ in message = "boot.initrd.luks.devices.<name>.bypassWorkqueues is not supported for kernels older than 5.9"; } + { assertion = !config.boot.initrd.systemd.enable -> all (x: x.keyFileTimeout == null) (attrValues luks.devices); + message = "boot.initrd.luks.devices.<name>.keyFileTimeout is only supported for systemd initrd"; + } + { assertion = config.boot.initrd.systemd.enable -> all (dev: !dev.fallbackToPassword) (attrValues luks.devices); message = "boot.initrd.luks.devices.<name>.fallbackToPassword is implied by systemd stage 1."; } diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index d1ce3d13ee855..05a667a09efc1 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -303,6 +303,48 @@ let sectionTap = checkUnitConfig "Tap" tunChecks; + sectionL2TP = checkUnitConfig "L2TP" [ + (assertOnlyFields [ + "TunnelId" + "PeerTunnelId" + "Remote" + "Local" + "EncapsulationType" + "UDPSourcePort" + "UDPDestinationPort" + "UDPChecksum" + "UDP6ZeroChecksumTx" + "UDP6ZeroChecksumRx" + ]) + (assertInt "TunnelId") + (assertRange "TunnelId" 1 4294967295) + (assertInt "PeerTunnelId") + (assertRange "PeerTunnelId" 1 4294967295) + (assertValueOneOf "EncapsulationType" [ "ip" "udp" ]) + (assertPort "UDPSourcePort") + (assertPort "UDPDestinationPort") + (assertValueOneOf "UDPChecksum" boolValues) + (assertValueOneOf "UDP6ZeroChecksumTx" boolValues) + (assertValueOneOf "UDP6ZeroChecksumRx" boolValues) + ]; + + sectionL2TPSession = checkUnitConfig "L2TPSession" [ + (assertOnlyFields [ + "Name" + "SessionId" + "PeerSessionId" + "Layer2SpecificHeader" + ]) + (assertHasField "Name") + (assertHasField "SessionId") + (assertInt "SessionId") + (assertRange "SessionId" 1 4294967295) + (assertHasField "PeerSessionId") + (assertInt "PeerSessionId") + (assertRange "PeerSessionId" 1 4294967295) + (assertValueOneOf "Layer2SpecificHeader" [ "none" "default" ]) + ]; + # NOTE The PrivateKey directive is missing on purpose here, please # do not add it to this list. The nix store is world-readable let's # refrain ourselves from providing a footgun. @@ -918,6 +960,470 @@ let (assertMacAddress "MACAddress") ]; + sectionBridge = checkUnitConfig "Bridge" [ + (assertOnlyFields [ + "UnicastFlood" + "MulticastFlood" + "MulticastToUnicast" + "NeighborSuppression" + "Learning" + "Hairpin" + "Isolated" + "UseBPDU" + "FastLeave" + "AllowPortToBeRoot" + "ProxyARP" + "ProxyARPWiFi" + "MulticastRouter" + "Cost" + "Priority" + ]) + (assertValueOneOf "UnicastFlood" boolValues) + (assertValueOneOf "MulticastFlood" boolValues) + (assertValueOneOf "MulticastToUnicast" boolValues) + (assertValueOneOf "NeighborSuppression" boolValues) + (assertValueOneOf "Learning" boolValues) + (assertValueOneOf "Hairpin" boolValues) + (assertValueOneOf "Isolated" boolValues) + (assertValueOneOf "UseBPDU" boolValues) + (assertValueOneOf "FastLeave" boolValues) + (assertValueOneOf "AllowPortToBeRoot" boolValues) + (assertValueOneOf "ProxyARP" boolValues) + (assertValueOneOf "ProxyARPWiFi" boolValues) + (assertValueOneOf "MulticastRouter" [ "no" "query" "permanent" "temporary" ]) + (assertInt "Cost") + (assertRange "Cost" 1 65535) + (assertInt "Priority") + (assertRange "Priority" 0 63) + ]; + + sectionBridgeFDB = checkUnitConfig "BridgeFDB" [ + (assertOnlyFields [ + "MACAddress" + "Destination" + "VLANId" + "VNI" + "AssociatedWith" + "OutgoingInterface" + ]) + (assertHasField "MACAddress") + (assertInt "VLANId") + (assertRange "VLANId" 0 4094) + (assertInt "VNI") + (assertRange "VNI" 1 16777215) + (assertValueOneOf "AssociatedWith" [ "use" "self" "master" "router" ]) + ]; + + sectionBridgeMDB = checkUnitConfig "BridgeMDB" [ + (assertOnlyFields [ + "MulticastGroupAddress" + "VLANId" + ]) + (assertHasField "MulticastGroupAddress") + (assertInt "VLANId") + (assertRange "VLANId" 0 4094) + ]; + + sectionLLDP = checkUnitConfig "LLDP" [ + (assertOnlyFields [ + "MUDURL" + ]) + ]; + + sectionCAN = checkUnitConfig "CAN" [ + (assertOnlyFields [ + "BitRate" + "SamplePoint" + "TimeQuantaNSec" + "PropagationSegment" + "PhaseBufferSegment1" + "PhaseBufferSegment2" + "SyncJumpWidth" + "DataBitRate" + "DataSamplePoint" + "DataTimeQuantaNSec" + "DataPropagationSegment" + "DataPhaseBufferSegment1" + "DataPhaseBufferSegment2" + "DataSyncJumpWidth" + "FDMode" + "FDNonISO" + "RestartSec" + "Termination" + "TripleSampling" + "BusErrorReporting" + "ListenOnly" + "Loopback" + "OneShot" + "PresumeAck" + "ClassicDataLengthCode" + ]) + (assertInt "TimeQuantaNSec" ) + (assertRange "TimeQuantaNSec" 0 4294967295 ) + (assertInt "PropagationSegment" ) + (assertRange "PropagationSegment" 0 4294967295 ) + (assertInt "PhaseBufferSegment1" ) + (assertRange "PhaseBufferSegment1" 0 4294967295 ) + (assertInt "PhaseBufferSegment2" ) + (assertRange "PhaseBufferSegment2" 0 4294967295 ) + (assertInt "SyncJumpWidth" ) + (assertRange "SyncJumpWidth" 0 4294967295 ) + (assertInt "DataTimeQuantaNSec" ) + (assertRange "DataTimeQuantaNSec" 0 4294967295 ) + (assertInt "DataPropagationSegment" ) + (assertRange "DataPropagationSegment" 0 4294967295 ) + (assertInt "DataPhaseBufferSegment1" ) + (assertRange "DataPhaseBufferSegment1" 0 4294967295 ) + (assertInt "DataPhaseBufferSegment2" ) + (assertRange "DataPhaseBufferSegment2" 0 4294967295 ) + (assertInt "DataSyncJumpWidth" ) + (assertRange "DataSyncJumpWidth" 0 4294967295 ) + (assertValueOneOf "FDMode" boolValues) + (assertValueOneOf "FDNonISO" boolValues) + (assertValueOneOf "TripleSampling" boolValues) + (assertValueOneOf "BusErrorReporting" boolValues) + (assertValueOneOf "ListenOnly" boolValues) + (assertValueOneOf "Loopback" boolValues) + (assertValueOneOf "OneShot" boolValues) + (assertValueOneOf "PresumeAck" boolValues) + (assertValueOneOf "ClassicDataLengthCode" boolValues) + ]; + + sectionIPoIB = checkUnitConfig "IPoIB" [ + (assertOnlyFields [ + "Mode" + "IgnoreUserspaceMulticastGroup" + ]) + (assertValueOneOf "Mode" [ "datagram" "connected" ]) + (assertValueOneOf "IgnoreUserspaceMulticastGroup" boolValues) + ]; + + sectionQDisc = checkUnitConfig "QDisc" [ + (assertOnlyFields [ + "Parent" + "Handle" + ]) + (assertValueOneOf "Parent" [ "clsact" "ingress" ]) + ]; + + sectionNetworkEmulator = checkUnitConfig "NetworkEmulator" [ + (assertOnlyFields [ + "Parent" + "Handle" + "DelaySec" + "DelayJitterSec" + "PacketLimit" + "LossRate" + "DuplicateRate" + ]) + (assertInt "PacketLimit") + (assertRange "PacketLimit" 0 4294967294) + ]; + + sectionTokenBucketFilter = checkUnitConfig "TokenBucketFilter" [ + (assertOnlyFields [ + "Parent" + "Handle" + "LatencySec" + "LimitBytes" + "BurstBytes" + "Rate" + "MPUBytes" + "PeakRate" + "MTUBytes" + ]) + ]; + + sectionPIE = checkUnitConfig "PIE" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + ]) + (assertInt "PacketLimit") + (assertRange "PacketLimit" 1 4294967294) + ]; + + sectionFlowQueuePIE = checkUnitConfig "FlowQueuePIE" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + ]) + (assertInt "PacketLimit") + (assertRange "PacketLimit" 1 4294967294) + ]; + + sectionStochasticFairBlue = checkUnitConfig "StochasticFairBlue" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + ]) + (assertInt "PacketLimit") + (assertRange "PacketLimit" 1 4294967294) + ]; + + sectionStochasticFairnessQueueing = checkUnitConfig "StochasticFairnessQueueing" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PerturbPeriodSec" + ]) + (assertInt "PerturbPeriodSec") + ]; + + sectionBFIFO = checkUnitConfig "BFIFO" [ + (assertOnlyFields [ + "Parent" + "Handle" + "LimitBytes" + ]) + ]; + + sectionPFIFO = checkUnitConfig "PFIFO" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + ]) + (assertInt "PacketLimit") + (assertRange "PacketLimit" 0 4294967294) + ]; + + sectionPFIFOHeadDrop = checkUnitConfig "PFIFOHeadDrop" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + ]) + (assertInt "PacketLimit") + (assertRange "PacketLimit" 0 4294967294) + ]; + + sectionPFIFOFast = checkUnitConfig "PFIFOFast" [ + (assertOnlyFields [ + "Parent" + "Handle" + ]) + ]; + + sectionCAKE = checkUnitConfig "CAKE" [ + (assertOnlyFields [ + "Parent" + "Handle" + "Bandwidth" + "AutoRateIngress" + "OverheadBytes" + "MPUBytes" + "CompensationMode" + "UseRawPacketSize" + "FlowIsolationMode" + "NAT" + "PriorityQueueingPreset" + "FirewallMark" + "Wash" + "SplitGSO" + ]) + (assertValueOneOf "AutoRateIngress" boolValues) + (assertInt "OverheadBytes") + (assertRange "OverheadBytes" (-64) 256) + (assertInt "MPUBytes") + (assertRange "MPUBytes" 1 256) + (assertValueOneOf "CompensationMode" [ "none" "atm" "ptm" ]) + (assertValueOneOf "UseRawPacketSize" boolValues) + (assertValueOneOf "FlowIsolationMode" + [ + "none" + "src-host" + "dst-host" + "hosts" + "flows" + "dual-src-host" + "dual-dst-host" + "triple" + ]) + (assertValueOneOf "NAT" boolValues) + (assertValueOneOf "PriorityQueueingPreset" + [ + "besteffort" + "precedence" + "diffserv8" + "diffserv4" + "diffserv3" + ]) + (assertInt "FirewallMark") + (assertRange "FirewallMark" 1 4294967295) + (assertValueOneOf "Wash" boolValues) + (assertValueOneOf "SplitGSO" boolValues) + ]; + + sectionControlledDelay = checkUnitConfig "ControlledDelay" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + "TargetSec" + "IntervalSec" + "ECN" + "CEThresholdSec" + ]) + (assertValueOneOf "ECN" boolValues) + ]; + + sectionDeficitRoundRobinScheduler = checkUnitConfig "DeficitRoundRobinScheduler" [ + (assertOnlyFields [ + "Parent" + "Handle" + ]) + ]; + + sectionDeficitRoundRobinSchedulerClass = checkUnitConfig "DeficitRoundRobinSchedulerClass" [ + (assertOnlyFields [ + "Parent" + "Handle" + "QuantumBytes" + ]) + ]; + + sectionEnhancedTransmissionSelection = checkUnitConfig "EnhancedTransmissionSelection" [ + (assertOnlyFields [ + "Parent" + "Handle" + "Bands" + "StrictBands" + "QuantumBytes" + "PriorityMap" + ]) + (assertInt "Bands") + (assertRange "Bands" 1 16) + (assertInt "StrictBands") + (assertRange "StrictBands" 1 16) + ]; + + sectionGenericRandomEarlyDetection = checkUnitConfig "GenericRandomEarlyDetection" [ + (assertOnlyFields [ + "Parent" + "Handle" + "VirtualQueues" + "DefaultVirtualQueue" + "GenericRIO" + ]) + (assertInt "VirtualQueues") + (assertRange "VirtualQueues" 1 16) + (assertInt "DefaultVirtualQueue") + (assertRange "DefaultVirtualQueue" 1 16) + (assertValueOneOf "GenericRIO" boolValues) + ]; + + sectionFairQueueingControlledDelay = checkUnitConfig "FairQueueingControlledDelay" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + "MemoryLimitBytes" + "Flows" + "TargetSec" + "IntervalSec" + "QuantumBytes" + "ECN" + "CEThresholdSec" + ]) + (assertInt "PacketLimit") + (assertInt "Flows") + (assertValueOneOf "ECN" boolValues) + ]; + + sectionFairQueueing = checkUnitConfig "FairQueueing" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + "FlowLimit" + "QuantumBytes" + "InitualQuantumBytes" + "MaximumRate" + "Buckets" + "OrphanMask" + "Pacing" + "CEThresholdSec" + ]) + (assertInt "PacketLimit") + (assertInt "FlowLimit") + (assertInt "OrphanMask") + (assertValueOneOf "Pacing" boolValues) + ]; + + sectionTrivialLinkEqualizer = checkUnitConfig "TrivialLinkEqualizer" [ + (assertOnlyFields [ + "Parent" + "Handle" + "Id" + ]) + ]; + + sectionHierarchyTokenBucket = checkUnitConfig "HierarchyTokenBucket" [ + (assertOnlyFields [ + "Parent" + "Handle" + "DefaultClass" + "RateToQuantum" + ]) + (assertInt "RateToQuantum") + ]; + + sectionHierarchyTokenBucketClass = checkUnitConfig "HierarchyTokenBucketClass" [ + (assertOnlyFields [ + "Parent" + "ClassId" + "Priority" + "QuantumBytes" + "MTUBytes" + "OverheadBytes" + "Rate" + "CeilRate" + "BufferBytes" + "CeilBufferBytes" + ]) + ]; + + sectionHeavyHitterFilter = checkUnitConfig "HeavyHitterFilter" [ + (assertOnlyFields [ + "Parent" + "Handle" + "PacketLimit" + ]) + (assertInt "PacketLimit") + (assertRange "PacketLimit" 0 4294967294) + ]; + + sectionQuickFairQueueing = checkUnitConfig "QuickFairQueueing" [ + (assertOnlyFields [ + "Parent" + "Handle" + ]) + ]; + + sectionQuickFairQueueingClass = checkUnitConfig "QuickFairQueueingClass" [ + (assertOnlyFields [ + "Parent" + "ClassId" + "Weight" + "MaxPacketBytes" + ]) + (assertInt "Weight") + (assertRange "Weight" 1 1023) + ]; + + sectionBridgeVLAN = checkUnitConfig "BridgeVLAN" [ + (assertOnlyFields [ + "VLAN" + "EgressUntagged" + "PVID" + ]) + (assertInt "PVID") + (assertRange "PVID" 0 4094) + ]; }; }; @@ -1012,6 +1518,21 @@ let }; + + l2tpSessionOptions = { + options = { + l2tpSessionConfig = mkOption { + default = {}; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionL2TPSession; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[L2TPSession]` section of the unit. See + {manpage}`systemd.netdev(5)` for details. + ''; + }; + }; + }; + wireguardPeerOptions = { options = { wireguardPeerConfig = mkOption { @@ -1125,6 +1646,38 @@ let ''; }; + l2tpConfig = mkOption { + default = {}; + example = { + TunnelId = 10; + PeerTunnelId = 12; + Local = "static"; + Remote = "192.168.30.101"; + EncapsulationType = "ip"; + }; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionL2TP; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[L2TP]` section of the unit. See + {manpage}`systemd.netdev(5)` for details. + ''; + }; + + l2tpSessions = mkOption { + default = []; + example = [ { l2tpSessionConfig={ + SessionId = 25; + PeerSessionId = 26; + Name = "l2tp-sess"; + };}]; + type = with types; listOf (submodule l2tpSessionOptions); + description = lib.mdDoc '' + Each item in this array specifies an option in the + `[L2TPSession]` section of the unit. See + {manpage}`systemd.netdev(5)` for details. + ''; + }; + wireguardConfig = mkOption { default = {}; example = { @@ -1306,6 +1859,51 @@ let }; }; + bridgeFDBOptions = { + options = { + bridgeFDBConfig = mkOption { + default = {}; + example = { MACAddress = "65:43:4a:5b:d8:5f"; Destination = "192.168.1.42"; VNI = 20; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeFDB; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[BridgeFDB]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + }; + }; + + bridgeMDBOptions = { + options = { + bridgeMDBConfig = mkOption { + default = {}; + example = { MulticastGroupAddress = "ff02::1:2:3:4"; VLANId = 10; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeMDB; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[BridgeMDB]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + }; + }; + + bridgeVLANOptions = { + options = { + bridgeMDBConfig = mkOption { + default = {}; + example = { VLAN = 20; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeVLAN; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[BridgeVLAN]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + }; + }; + networkOptions = commonNetworkOptions // { linkConfig = mkOption { @@ -1445,6 +2043,366 @@ let ''; }; + bridgeConfig = mkOption { + default = {}; + example = { MulticastFlood = false; Cost = 20; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridge; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[Bridge]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + bridgeFDBs = mkOption { + default = []; + example = [ { bridgeFDBConfig = { MACAddress = "90:e2:ba:43:fc:71"; Destination = "192.168.100.4"; VNI = 3600; }; } ]; + type = with types; listOf (submodule bridgeFDBOptions); + description = lib.mdDoc '' + A list of BridgeFDB sections to be added to the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + bridgeMDBs = mkOption { + default = []; + example = [ { bridgeMDBConfig = { MulticastGroupAddress = "ff02::1:2:3:4"; VLANId = 10; } ; } ]; + type = with types; listOf (submodule bridgeMDBOptions); + description = lib.mdDoc '' + A list of BridgeMDB sections to be added to the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + lldpConfig = mkOption { + default = {}; + example = { MUDURL = "https://things.example.org/product_abc123/v5"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionLLDP; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[LLDP]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + canConfig = mkOption { + default = {}; + example = { }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionCAN; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[CAN]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + ipoIBConfig = mkOption { + default = {}; + example = { }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPoIB; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[IPoIB]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + qdiscConfig = mkOption { + default = {}; + example = { Parent = "ingress"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionQDisc; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[QDisc]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + networkEmulatorConfig = mkOption { + default = {}; + example = { Parent = "ingress"; DelaySec = "20msec"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionNetworkEmulator; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[NetworkEmulator]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + tokenBucketFilterConfig = mkOption { + default = {}; + example = { Parent = "ingress"; Rate = "100k"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionTokenBucketFilter; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[TokenBucketFilter]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + pieConfig = mkOption { + default = {}; + example = { Parent = "ingress"; PacketLimit = "3847"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionPIE; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[PIE]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + flowQueuePIEConfig = mkOption { + default = {}; + example = { Parent = "ingress"; PacketLimit = "3847"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionFlowQueuePIE; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[FlowQueuePIE]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + stochasticFairBlueConfig = mkOption { + default = {}; + example = { Parent = "ingress"; PacketLimit = "3847"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionStochasticFairBlue; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[StochasticFairBlue]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + stochasticFairnessQueueingConfig = mkOption { + default = {}; + example = { Parent = "ingress"; PerturbPeriodSec = "30"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionStochasticFairnessQueueing; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[StochasticFairnessQueueing]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + bfifoConfig = mkOption { + default = {}; + example = { Parent = "ingress"; LimitBytes = "20K"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionBFIFO; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[BFIFO]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + pfifoConfig = mkOption { + default = {}; + example = { Parent = "ingress"; PacketLimit = "300"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionPFIFO; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[PFIFO]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + pfifoHeadDropConfig = mkOption { + default = {}; + example = { Parent = "ingress"; PacketLimit = "300"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionPFIFOHeadDrop; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[PFIFOHeadDrop]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + pfifoFastConfig = mkOption { + default = {}; + example = { Parent = "ingress"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionPFIFOFast; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[PFIFOFast]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + cakeConfig = mkOption { + default = {}; + example = { Bandwidth = "40M"; OverheadBytes = 8; CompensationMode = "ptm"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionCAKE; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[CAKE]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + controlledDelayConfig = mkOption { + default = {}; + example = { Parent = "ingress"; TargetSec = "20msec"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionControlledDelay; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[ControlledDelay]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + deficitRoundRobinSchedulerConfig = mkOption { + default = {}; + example = { Parent = "root"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionDeficitRoundRobinScheduler; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[DeficitRoundRobinScheduler]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + deficitRoundRobinSchedulerClassConfig = mkOption { + default = {}; + example = { Parent = "root"; QuantumBytes = "300k"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionDeficitRoundRobinSchedulerClass; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[DeficitRoundRobinSchedulerClass]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + enhancedTransmissionSelectionConfig = mkOption { + default = {}; + example = { Parent = "root"; QuantumBytes = "300k"; Bands = 3; PriorityMap = "100 200 300"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionEnhancedTransmissionSelection; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[EnhancedTransmissionSelection]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + genericRandomEarlyDetectionConfig = mkOption { + default = {}; + example = { Parent = "root"; VirtualQueues = 5; DefaultVirtualQueue = 3; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionGenericRandomEarlyDetection; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[GenericRandomEarlyDetection]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + fairQueueingControlledDelayConfig = mkOption { + default = {}; + example = { Parent = "root"; Flows = 5; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionFairQueueingControlledDelay; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[FairQueueingControlledDelay]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + fairQueueingConfig = mkOption { + default = {}; + example = { Parent = "root"; FlowLimit = 5; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionFairQueueing; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[FairQueueing]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + trivialLinkEqualizerConfig = mkOption { + default = {}; + example = { Parent = "root"; Id = 0; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionTrivialLinkEqualizer; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[TrivialLinkEqualizer]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + hierarchyTokenBucketConfig = mkOption { + default = {}; + example = { Parent = "root"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionHierarchyTokenBucket; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[HierarchyTokenBucket]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + hierarchyTokenBucketClassConfig = mkOption { + default = {}; + example = { Parent = "root"; Rate = "10M"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionHierarchyTokenBucketClass; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[HierarchyTokenBucketClass]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + heavyHitterFilterConfig = mkOption { + default = {}; + example = { Parent = "root"; PacketLimit = 10000; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionHeavyHitterFilter; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[HeavyHitterFilter]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + quickFairQueueingConfig = mkOption { + default = {}; + example = { Parent = "root"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionQuickFairQueueing; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[QuickFairQueueing]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + quickFairQueueingConfigClass = mkOption { + default = {}; + example = { Parent = "root"; Weight = 133; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionQuickFairQueueingClass; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[QuickFairQueueingClass]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + bridgeVLANConfig = mkOption { + default = {}; + example = { VLAN = "10-20"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionbridgeVLAN; + description = lib.mdDoc '' + Each attribute in this set specifies an option in the + `[BridgeVLAN]` section of the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + + bridgeVLANs = mkOption { + default = []; + example = [ { bridgeVLANConfig = { VLAN = "10-20"; }; } ]; + type = with types; listOf (submodule bridgeVLANOptions); + description = lib.mdDoc '' + A list of BridgeVLAN sections to be added to the unit. See + {manpage}`systemd.network(5)` for details. + ''; + }; + name = mkOption { type = types.nullOr types.str; default = null; @@ -1705,6 +2663,14 @@ let [Tap] ${attrsToSection def.tapConfig} '' + + optionalString (def.l2tpConfig != { }) '' + [L2TP] + ${attrsToSection def.l2tpConfig} + '' + + flip concatMapStrings def.l2tpSessions (x: '' + [L2TPSession] + ${attrsToSection x.l2tpSessionConfig} + '') + optionalString (def.wireguardConfig != { }) '' [WireGuard] ${attrsToSection def.wireguardConfig} @@ -1844,6 +2810,134 @@ let [DHCPServerStaticLease] ${attrsToSection x.dhcpServerStaticLeaseConfig} '') + + optionalString (def.bridgeConfig != { }) '' + [Bridge] + ${attrsToSection def.bridgeConfig} + '' + + flip concatMapStrings def.bridgeFDBs (x: '' + [BridgeFDB] + ${attrsToSection x.bridgeFDBConfig} + '') + + flip concatMapStrings def.bridgeMDBs (x: '' + [BridgeMDB] + ${attrsToSection x.bridgeMDBConfig} + '') + + optionalString (def.lldpConfig != { }) '' + [LLDP] + ${attrsToSection def.lldpConfig} + '' + + optionalString (def.canConfig != { }) '' + [CAN] + ${attrsToSection def.canConfig} + '' + + optionalString (def.ipoIBConfig != { }) '' + [IPoIB] + ${attrsToSection def.ipoIBConfig} + '' + + optionalString (def.qdiscConfig != { }) '' + [QDisc] + ${attrsToSection def.qdiscConfig} + '' + + optionalString (def.networkEmulatorConfig != { }) '' + [NetworkEmulator] + ${attrsToSection def.networkEmulatorConfig} + '' + + optionalString (def.tokenBucketFilterConfig != { }) '' + [TokenBucketFilter] + ${attrsToSection def.tockenBucketFilterConfig} + '' + + optionalString (def.pieConfig != { }) '' + [PIE] + ${attrsToSection def.pieConfig} + '' + + optionalString (def.flowQueuePIEConfig != { }) '' + [FlowQueuePIE] + ${attrsToSection def.flowQueuePIEConfig} + '' + + optionalString (def.stochasticFairBlueConfig != { }) '' + [StochasticFairBlue] + ${attrsToSection def.stochasticFairBlueConfig} + '' + + optionalString (def.stochasticFairnessQueueingConfig != { }) '' + [StochasticFairnessQueueing] + ${attrsToSection def.stochasticFairnessQueueingConfig} + '' + + optionalString (def.bfifoConfig != { }) '' + [BFIFO] + ${attrsToSection def.bfifoConfig} + '' + + optionalString (def.pfifoConfig != { }) '' + [PFIFO] + ${attrsToSection def.pfifoConfig} + '' + + optionalString (def.pfifoHeadDropConfig != { }) '' + [PFIFOHeadDrop] + ${attrsToSection def.pfifoHeadDropConfig} + '' + + optionalString (def.pfifoFastConfig != { }) '' + [PFIFOFast] + ${attrsToSection def.pfifoFastConfig} + '' + + optionalString (def.cakeConfig != { }) '' + [CAKE] + ${attrsToSection def.cakeConfig} + '' + + optionalString (def.controlledDelayConfig != { }) '' + [ControlledDelay] + ${attrsToSection def.controlledDelayConfig} + '' + + optionalString (def.deficitRoundRobinSchedulerConfig != { }) '' + [DeficitRoundRobinScheduler] + ${attrsToSection def.deficitRoundRobinSchedulerConfig} + '' + + optionalString (def.deficitRoundRobinSchedulerClassConfig != { }) '' + [DeficitRoundRobinSchedulerClass] + ${attrsToSection def.deficitRoundRobinSchedulerClassConfig} + '' + + optionalString (def.enhancedTransmissionSelectionConfig != { }) '' + [EnhancedTransmissionSelection] + ${attrsToSection def.enhancedTransmissionSelectionConfig} + '' + + optionalString (def.genericRandomEarlyDetectionConfig != { }) '' + [GenericRandomEarlyDetection] + ${attrsToSection def.genericRandomEarlyDetectionConfig} + '' + + optionalString (def.fairQueueingControlledDelayConfig != { }) '' + [FairQueueingControlledDelay] + ${attrsToSection def.fairQueueingControlledDelayConfig} + '' + + optionalString (def.fairQueueingConfig != { }) '' + [FairQueueing] + ${attrsToSection def.fairQueueingConfig} + '' + + optionalString (def.trivialLinkEqualizerConfig != { }) '' + [TrivialLinkEqualizer] + ${attrsToSection def.trivialLinkEqualizerConfig} + '' + + optionalString (def.hierarchyTokenBucketConfig != { }) '' + [HierarchyTokenBucket] + ${attrsToSection def.hierarchyTokenBucketConfig} + '' + + optionalString (def.hierarchyTokenBucketClassConfig != { }) '' + [HierarchyTokenBucketClass] + ${attrsToSection def.hierarchyTokenBucketClassConfig} + '' + + optionalString (def.heavyHitterFilterConfig != { }) '' + [HeavyHitterFilter] + ${attrsToSection def.heavyHitterFilterConfig} + '' + + optionalString (def.quickFairQueueingConfig != { }) '' + [QuickFairQueueing] + ${attrsToSection def.quickFairQueueingConfig} + '' + + optionalString (def.quickFairQueueingConfigClass != { }) '' + [QuickFairQueueingClass] + ${attrsToSection def.quickFairQueueingConfigClass} + '' + + flip concatMapStrings def.bridgeVLANs (x: '' + [BridgeVLAN] + ${attrsToSection x.bridgeVLANConfig} + '') + def.extraConfig; }; diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 8b20f9a7e87f9..5ff99b14dee67 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -79,6 +79,8 @@ let # Filesystems. "systemd-fsck@.service" "systemd-fsck-root.service" + "systemd-growfs@.service" + "systemd-growfs-root.service" "systemd-remount-fs.service" "systemd-pstore.service" "local-fs.target" diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix index cf76704577fd0..ffe96f3ad9c30 100644 --- a/nixos/modules/system/boot/systemd/initrd.nix +++ b/nixos/modules/system/boot/systemd/initrd.nix @@ -56,6 +56,7 @@ let "systemd-ask-password-console.path" "systemd-ask-password-console.service" "systemd-fsck@.service" + "systemd-growfs@.service" "systemd-halt.service" "systemd-hibernate-resume@.service" "systemd-journald-audit.socket" @@ -158,6 +159,16 @@ in { ''; }; + managerEnvironment = mkOption { + type = with types; attrsOf (nullOr (oneOf [ str path package ])); + default = {}; + example = { SYSTEMD_LOG_LEVEL = "debug"; }; + description = lib.mdDoc '' + Environment variables of PID 1. These variables are + *not* passed to started units. + ''; + }; + contents = mkOption { description = lib.mdDoc "Set of files that have to be linked into the initrd"; example = literalExpression '' @@ -355,9 +366,13 @@ in { less = "${pkgs.less}/bin/less"; mount = "${cfg.package.util-linux}/bin/mount"; umount = "${cfg.package.util-linux}/bin/umount"; + fsck = "${cfg.package.util-linux}/bin/fsck"; }; + managerEnvironment.PATH = "/bin:/sbin"; + contents = { + "/tmp/.keep".text = "systemd requires the /tmp mount point in the initrd cpio archive"; "/init".source = "${cfg.package}/lib/systemd/systemd"; "/etc/systemd/system".source = stage1Units; @@ -365,6 +380,7 @@ in { [Manager] DefaultEnvironment=PATH=/bin:/sbin ${optionalString (isBool cfg.emergencyAccess && cfg.emergencyAccess) "SYSTEMD_SULOGIN_FORCE=1"} ${cfg.extraConfig} + ManagerEnvironment=${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${lib.escapeShellArg v}") cfg.managerEnvironment)} ''; "/lib/modules".source = "${modulesClosure}/lib/modules"; @@ -444,21 +460,6 @@ in { (v: let n = escapeSystemdPath v.where; in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); - # The unit in /run/systemd/generator shadows the unit in - # /etc/systemd/system, but will still apply drop-ins from - # /etc/systemd/system/foo.service.d/ - # - # We need IgnoreOnIsolate, otherwise the Requires dependency of - # a mount unit on its makefs unit causes it to be unmounted when - # we isolate for switch-root. Use a dummy package so that - # generateUnits will generate drop-ins instead of unit files. - packages = [(pkgs.runCommand "dummy" {} '' - mkdir -p $out/etc/systemd/system - touch $out/etc/systemd/system/systemd-{makefs,growfs}@.service - '')]; - services."systemd-makefs@" = lib.mkIf needMakefs { unitConfig.IgnoreOnIsolate = true; }; - services."systemd-growfs@" = lib.mkIf needGrowfs { unitConfig.IgnoreOnIsolate = true; }; - # make sure all the /dev nodes are set up services.systemd-tmpfiles-setup-dev.wantedBy = ["sysinit.target"]; diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index 7f2c8a41b20a1..822f1593474eb 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -140,7 +140,10 @@ let else if config.fsType == "reiserfs" then "-q" else null; in { - options = mkIf config.autoResize [ "x-nixos.autoresize" ]; + options = mkMerge [ + (mkIf config.autoResize [ "x-nixos.autoresize" ]) + (mkIf (utils.fsNeededForBoot config) [ "x-initrd.mount" ]) + ]; formatOptions = mkIf (defaultFormatOptions != null) (mkDefault defaultFormatOptions); }; @@ -155,27 +158,54 @@ let makeFstabEntries = let - fsToSkipCheck = [ "none" "bindfs" "btrfs" "zfs" "tmpfs" "nfs" "nfs4" "vboxsf" "glusterfs" "apfs" "9p" "cifs" "prl_fs" "vmhgfs" ]; + fsToSkipCheck = [ + "none" + "auto" + "overlay" + "iso9660" + "bindfs" + "udf" + "btrfs" + "zfs" + "tmpfs" + "bcachefs" + "nfs" + "nfs4" + "nilfs2" + "vboxsf" + "squashfs" + "glusterfs" + "apfs" + "9p" + "cifs" + "prl_fs" + "vmhgfs" + ] ++ lib.optionals (!config.boot.initrd.checkJournalingFS) [ + "ext3" + "ext4" + "reiserfs" + "xfs" + "jfs" + "f2fs" + ]; isBindMount = fs: builtins.elem "bind" fs.options; skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck || isBindMount fs; # https://wiki.archlinux.org/index.php/fstab#Filepath_spaces escape = string: builtins.replaceStrings [ " " "\t" ] [ "\\040" "\\011" ] string; - in fstabFileSystems: { rootPrefix ? "", excludeChecks ? false, extraOpts ? (fs: []) }: concatMapStrings (fs: + in fstabFileSystems: { rootPrefix ? "", extraOpts ? (fs: []) }: concatMapStrings (fs: (optionalString (isBindMount fs) (escape rootPrefix)) + (if fs.device != null then escape fs.device else if fs.label != null then "/dev/disk/by-label/${escape fs.label}" else throw "No device specified for mount point ‘${fs.mountPoint}’.") - + " " + escape (rootPrefix + fs.mountPoint) + + " " + escape fs.mountPoint + " " + fs.fsType + " " + escape (builtins.concatStringsSep "," (fs.options ++ (extraOpts fs))) - + " " + (optionalString (!excludeChecks) - ("0 " + (if skipCheck fs then "0" else if fs.mountPoint == "/" then "1" else "2"))) + + " 0 " + (if skipCheck fs then "0" else if fs.mountPoint == "/" then "1" else "2") + "\n" ) fstabFileSystems; initrdFstab = pkgs.writeText "initrd-fstab" (makeFstabEntries (filter utils.fsNeededForBoot fileSystems) { rootPrefix = "/sysroot"; - excludeChecks = true; extraOpts = fs: (optional fs.autoResize "x-systemd.growfs") ++ (optional fs.autoFormat "x-systemd.makefs"); @@ -328,7 +358,9 @@ in )} ''; - boot.initrd.systemd.contents."/etc/fstab".source = initrdFstab; + boot.initrd.systemd.storePaths = [initrdFstab]; + boot.initrd.systemd.managerEnvironment.SYSTEMD_SYSROOT_FSTAB = initrdFstab; + boot.initrd.systemd.services.initrd-parse-etc.environment.SYSTEMD_SYSROOT_FSTAB = initrdFstab; # Provide a target that pulls in all filesystems. systemd.targets.fs = diff --git a/nixos/modules/tasks/filesystems/vfat.nix b/nixos/modules/tasks/filesystems/vfat.nix index 5baab1c802cf9..5421b617b43b9 100644 --- a/nixos/modules/tasks/filesystems/vfat.nix +++ b/nixos/modules/tasks/filesystems/vfat.nix @@ -11,7 +11,7 @@ in { config = mkIf (any (fs: fs == "vfat") config.boot.supportedFilesystems) { - system.fsPackages = [ pkgs.dosfstools ]; + system.fsPackages = [ pkgs.dosfstools pkgs.mtools ]; boot.initrd.kernelModules = mkIf inInitrd [ "vfat" "nls_cp437" "nls_iso8859-1" ]; diff --git a/nixos/modules/virtualisation/ec2-metadata-fetcher.sh b/nixos/modules/virtualisation/ec2-metadata-fetcher.sh index 9e204d45dbd83..716aff7c22fba 100644 --- a/nixos/modules/virtualisation/ec2-metadata-fetcher.sh +++ b/nixos/modules/virtualisation/ec2-metadata-fetcher.sh @@ -55,10 +55,9 @@ done echo "getting EC2 instance metadata..." get_imds() { - # Intentionally no --fail here, so that we proceed even if e.g. a - # 404 was returned (but we still fail if we can't reach the IMDS - # server). - curl --silent --show-error --header "X-aws-ec2-metadata-token: $IMDS_TOKEN" "$@" + # --fail to avoid populating missing files with 404 HTML response body + # || true to allow the script to continue even when encountering a 404 + curl --silent --show-error --fail --header "X-aws-ec2-metadata-token: $IMDS_TOKEN" "$@" || true } get_imds -o "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path diff --git a/nixos/modules/virtualisation/podman/default.nix b/nixos/modules/virtualisation/podman/default.nix index 83ddba3ce06ef..c3fae4bac41b3 100644 --- a/nixos/modules/virtualisation/podman/default.nix +++ b/nixos/modules/virtualisation/podman/default.nix @@ -142,6 +142,7 @@ in defaultNetwork.settings = lib.mkOption { type = json.type; default = { }; + example = lib.literalExpression "{ dns_enabled = true; }"; description = lib.mdDoc '' Settings for podman's default network. ''; @@ -149,7 +150,7 @@ in }; - config = lib.mkIf cfg.enable (lib.mkMerge [ + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ] ++ lib.optional cfg.dockerCompat dockerCompat; @@ -235,6 +236,5 @@ in ''; } ]; - } - ]); + }; } diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index ce2ee9b4c5d03..a55a21a46a538 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -1101,15 +1101,17 @@ in what = "overlay"; type = "overlay"; options = "lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/store,workdir=/sysroot/nix/.rw-store/work"; - wantedBy = ["local-fs.target"]; - before = ["local-fs.target"]; - requires = ["sysroot-nix-.ro\\x2dstore.mount" "sysroot-nix-.rw\\x2dstore.mount" "rw-store.service"]; - after = ["sysroot-nix-.ro\\x2dstore.mount" "sysroot-nix-.rw\\x2dstore.mount" "rw-store.service"]; - unitConfig.IgnoreOnIsolate = true; + wantedBy = ["initrd-fs.target"]; + before = ["initrd-fs.target"]; + requires = ["rw-store.service"]; + after = ["rw-store.service"]; + unitConfig.RequiresMountsFor = "/sysroot/nix/.ro-store"; }]; services.rw-store = { - after = ["sysroot-nix-.rw\\x2dstore.mount"]; - unitConfig.DefaultDependencies = false; + unitConfig = { + DefaultDependencies = false; + RequiresMountsFor = "/sysroot/nix/.rw-store"; + }; serviceConfig = { Type = "oneshot"; ExecStart = "/bin/mkdir -p -m 0755 /sysroot/nix/.rw-store/store /sysroot/nix/.rw-store/work /sysroot/nix/store"; |