diff options
author | Alyssa Ross <hi@alyssa.is> | 2022-03-15 10:36:38 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2022-03-16 11:37:19 +0000 |
commit | d435710923ac6e6f9fc155534800745004f2ce93 (patch) | |
tree | 386f9401476f96bdc6ec25173a090198942b5d5b /nixpkgs/nixos/modules | |
parent | c725f0011e91ae49d351b981690eb66b862b6104 (diff) | |
parent | 3239fd2b8f728106491154b44625662e10259af2 (diff) | |
download | nixlib-d435710923ac6e6f9fc155534800745004f2ce93.tar nixlib-d435710923ac6e6f9fc155534800745004f2ce93.tar.gz nixlib-d435710923ac6e6f9fc155534800745004f2ce93.tar.bz2 nixlib-d435710923ac6e6f9fc155534800745004f2ce93.tar.lz nixlib-d435710923ac6e6f9fc155534800745004f2ce93.tar.xz nixlib-d435710923ac6e6f9fc155534800745004f2ce93.tar.zst nixlib-d435710923ac6e6f9fc155534800745004f2ce93.zip |
Merge commit '3239fd2b8f728106491154b44625662e10259af2'
Conflicts: nixpkgs/pkgs/applications/window-managers/sway/default.nix
Diffstat (limited to 'nixpkgs/nixos/modules')
94 files changed, 3392 insertions, 1834 deletions
diff --git a/nixpkgs/nixos/modules/hardware/all-firmware.nix b/nixpkgs/nixos/modules/hardware/all-firmware.nix index 99bdb11b0112..5b60b17312f9 100644 --- a/nixpkgs/nixos/modules/hardware/all-firmware.nix +++ b/nixpkgs/nixos/modules/hardware/all-firmware.nix @@ -83,6 +83,7 @@ in { b43Firmware_5_1_138 b43Firmware_6_30_163_46 b43FirmwareCutter + xow_dongle-firmware ] ++ optional pkgs.stdenv.hostPlatform.isx86 facetimehd-firmware; }) (mkIf cfg.wirelessRegulatoryDatabase { diff --git a/nixpkgs/nixos/modules/hardware/xone.nix b/nixpkgs/nixos/modules/hardware/xone.nix new file mode 100644 index 000000000000..89690d8c6fb1 --- /dev/null +++ b/nixpkgs/nixos/modules/hardware/xone.nix @@ -0,0 +1,23 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.hardware.xone; +in +{ + options.hardware.xone = { + enable = mkEnableOption "the xone driver for Xbox One and Xbobx Series X|S accessories"; + }; + + config = mkIf cfg.enable { + boot = { + blacklistedKernelModules = [ "xpad" "mt76x2u" ]; + extraModulePackages = with config.boot.kernelPackages; [ xone ]; + }; + hardware.firmware = [ pkgs.xow_dongle-firmware ]; + }; + + meta = { + maintainers = with maintainers; [ rhysmdnz ]; + }; +} diff --git a/nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix b/nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix index 165e2aac27b4..321793882f4c 100644 --- a/nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix +++ b/nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix @@ -24,6 +24,9 @@ [pi3] kernel=u-boot-rpi3.bin + [pi02] + kernel=u-boot-rpi3.bin + [pi4] kernel=u-boot-rpi4.bin enable_gic=1 @@ -33,6 +36,9 @@ # what the pi3 firmware does by default. disable_overscan=1 + # Supported in newer board revisions + arm_boost=1 + [all] # Boot in 64-bit mode. arm_64bit=1 diff --git a/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix index 31aeaad80d60..dfafda77cb56 100644 --- a/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix +++ b/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix @@ -1,7 +1,7 @@ { - x86_64-linux = "/nix/store/67amfijcvhqfgz4bwf2izsvbnklwjbvk-nix-2.6.0"; - i686-linux = "/nix/store/kinl99f619b2xsma4qnzhidbp65axyzm-nix-2.6.0"; - aarch64-linux = "/nix/store/8zpm63nn7k4n1alp9a0fcilpgc8j014z-nix-2.6.0"; - x86_64-darwin = "/nix/store/hw5v03wnc0k1pwgiyhblwlxb1fx5zyx8-nix-2.6.0"; - aarch64-darwin = "/nix/store/669p1vjnzi56fib98qczwlaglcwcnip4-nix-2.6.0"; + x86_64-linux = "/nix/store/0n2wfvi1i3fg97cjc54wslvk0804y0sn-nix-2.7.0"; + i686-linux = "/nix/store/4p27c1k9z99pli6x8cxfph20yfyzn9nh-nix-2.7.0"; + aarch64-linux = "/nix/store/r9yr8ijsb0gi9r7y92y3yzyld59yp0kj-nix-2.7.0"; + x86_64-darwin = "/nix/store/hyfj5imsd0c4amlcjpf8l6w4q2draaj3-nix-2.7.0"; + aarch64-darwin = "/nix/store/9l96qllhbb6xrsjaai76dn74ap7rq92n-nix-2.7.0"; } diff --git a/nixpkgs/nixos/modules/misc/documentation.nix b/nixpkgs/nixos/modules/misc/documentation.nix index 550279ae72dc..dfad271bcf14 100644 --- a/nixpkgs/nixos/modules/misc/documentation.nix +++ b/nixpkgs/nixos/modules/misc/documentation.nix @@ -129,7 +129,7 @@ let genericName = "View NixOS documentation in a web browser"; icon = "nix-snowflake"; exec = "nixos-help"; - categories = "System"; + categories = ["System"]; }; in pkgs.symlinkJoin { diff --git a/nixpkgs/nixos/modules/misc/ids.nix b/nixpkgs/nixos/modules/misc/ids.nix index 6ede7fbe4bd5..e0418351df6f 100644 --- a/nixpkgs/nixos/modules/misc/ids.nix +++ b/nixpkgs/nixos/modules/misc/ids.nix @@ -82,14 +82,14 @@ in git = 41; #fourstore = 42; # dropped in 20.03 #fourstorehttp = 43; # dropped in 20.03 - virtuoso = 44; + #virtuoso = 44; dropped module #rtkit = 45; # dynamically allocated 2021-09-03 dovecot2 = 46; dovenull2 = 47; prayer = 49; mpd = 50; clamav = 51; - fprot = 52; + #fprot = 52; # unused # bind = 53; #dynamically allocated as of 2021-09-03 wwwrun = 54; #adm = 55; # unused @@ -412,7 +412,7 @@ in prayer = 49; mpd = 50; clamav = 51; - fprot = 52; + #fprot = 52; # unused #bind = 53; # unused wwwrun = 54; adm = 55; diff --git a/nixpkgs/nixos/modules/misc/version.nix b/nixpkgs/nixos/modules/misc/version.nix index 6c526f6d4f2d..6c072021ed83 100644 --- a/nixpkgs/nixos/modules/misc/version.nix +++ b/nixpkgs/nixos/modules/misc/version.nix @@ -1,12 +1,17 @@ { config, lib, options, pkgs, ... }: -with lib; - let cfg = config.system.nixos; opt = options.system.nixos; -in + inherit (lib) + concatStringsSep mapAttrsToList toLower + literalExpression mkRenamedOptionModule mkDefault mkOption trivial types; + + attrsToText = attrs: + concatStringsSep "\n" (mapAttrsToList (n: v: ''${n}="${toString v}"'') attrs); + +in { imports = [ (mkRenamedOptionModule [ "system" "nixosVersion" ] [ "system" "nixos" "version" ]) @@ -101,22 +106,30 @@ in # Generate /etc/os-release. See # https://www.freedesktop.org/software/systemd/man/os-release.html for the # format. - environment.etc.os-release.text = - '' - NAME=NixOS - ID=nixos - VERSION="${cfg.release} (${cfg.codeName})" - VERSION_CODENAME=${toLower cfg.codeName} - VERSION_ID="${cfg.release}" - BUILD_ID="${cfg.version}" - PRETTY_NAME="NixOS ${cfg.release} (${cfg.codeName})" - LOGO="nix-snowflake" - HOME_URL="https://nixos.org/" - DOCUMENTATION_URL="https://nixos.org/learn.html" - SUPPORT_URL="https://nixos.org/community.html" - BUG_REPORT_URL="https://github.com/NixOS/nixpkgs/issues" - ''; - + environment.etc = { + "lsb-release".text = attrsToText { + LSB_VERSION = "${cfg.release} (${cfg.codeName})"; + DISTRIB_ID = "nixos"; + DISTRIB_RELEASE = cfg.release; + DISTRIB_CODENAME = toLower cfg.codeName; + DISTRIB_DESCRIPTION = "NixOS ${cfg.release} (${cfg.codeName})"; + }; + + "os-release".text = attrsToText { + NAME = "NixOS"; + ID = "nixos"; + VERSION = "${cfg.release} (${cfg.codeName})"; + VERSION_CODENAME = toLower cfg.codeName; + VERSION_ID = cfg.release; + BUILD_ID = cfg.version; + PRETTY_NAME = "NixOS ${cfg.release} (${cfg.codeName})"; + LOGO = "nix-snowflake"; + HOME_URL = "https://nixos.org/"; + DOCUMENTATION_URL = "https://nixos.org/learn.html"; + SUPPORT_URL = "https://nixos.org/community.html"; + BUG_REPORT_URL = "https://github.com/NixOS/nixpkgs/issues"; + }; + }; }; # uses version info nixpkgs, which requires a full nixpkgs path diff --git a/nixpkgs/nixos/modules/misc/wordlist.nix b/nixpkgs/nixos/modules/misc/wordlist.nix new file mode 100644 index 000000000000..988b522d7431 --- /dev/null +++ b/nixpkgs/nixos/modules/misc/wordlist.nix @@ -0,0 +1,59 @@ +{ config, lib, pkgs, ... }: +with lib; +let + concatAndSort = name: files: pkgs.runCommand name {} '' + awk 1 ${lib.escapeShellArgs files} | sed '{ /^\s*$/d; s/^\s\+//; s/\s\+$// }' | sort | uniq > $out + ''; +in +{ + options = { + environment.wordlist = { + enable = mkEnableOption "environment variables for lists of words"; + + lists = mkOption { + type = types.attrsOf (types.nonEmptyListOf types.path); + + default = { + WORDLIST = [ "${pkgs.scowl}/share/dict/words.txt" ]; + }; + + defaultText = literalExpression '' + { + WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ]; + } + ''; + + description = '' + A set with the key names being the environment variable you'd like to + set and the values being a list of paths to text documents containing + lists of words. The various files will be merged, sorted, duplicates + removed, and extraneous spacing removed. + + If you have a handful of words that you want to add to an already + existing wordlist, you may find `builtins.toFile` useful for this + task. + ''; + + example = literalExpression '' + { + WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ]; + AUGMENTED_WORDLIST = [ + "''${pkgs.scowl}/share/dict/words.txt" + "''${pkgs.scowl}/share/dict/words.variants.txt" + (builtins.toFile "extra-words" ''' + desynchonization + oobleck''') + ]; + } + ''; + }; + }; + }; + + config = mkIf config.environment.wordlist.enable { + environment.variables = + lib.mapAttrs + (name: value: "${concatAndSort "wordlist-${name}" value}") + config.environment.wordlist.lists; + }; +} diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix index cf5303f81f23..12bca45a9958 100644 --- a/nixpkgs/nixos/modules/module-list.nix +++ b/nixpkgs/nixos/modules/module-list.nix @@ -91,6 +91,7 @@ ./hardware/video/switcheroo-control.nix ./hardware/video/uvcvideo/default.nix ./hardware/video/webcam/facetimehd.nix + ./hardware/xone.nix ./hardware/xpadneo.nix ./i18n/input-method/default.nix ./i18n/input-method/fcitx.nix @@ -115,6 +116,7 @@ ./misc/nixpkgs.nix ./misc/passthru.nix ./misc/version.nix + ./misc/wordlist.nix ./misc/nixops-autoluks.nix ./programs/adb.nix ./programs/appgate-sdp.nix @@ -166,6 +168,8 @@ ./programs/iftop.nix ./programs/iotop.nix ./programs/java.nix + ./programs/k40-whisperer.nix + ./programs/kclock.nix ./programs/kdeconnect.nix ./programs/kbdlight.nix ./programs/less.nix @@ -176,6 +180,7 @@ ./programs/msmtp.nix ./programs/mtr.nix ./programs/nano.nix + ./programs/nbd.nix ./programs/neovim.nix ./programs/nm-applet.nix ./programs/npm.nix @@ -252,6 +257,7 @@ ./security/tpm2.nix ./services/admin/meshcentral.nix ./services/admin/oxidized.nix + ./services/admin/pgadmin.nix ./services/admin/salt/master.nix ./services/admin/salt/minion.nix ./services/amqp/activemq/default.nix @@ -349,7 +355,6 @@ ./services/databases/redis.nix ./services/databases/riak.nix ./services/databases/victoriametrics.nix - ./services/databases/virtuoso.nix ./services/desktops/accountsservice.nix ./services/desktops/bamf.nix ./services/desktops/blueman.nix @@ -394,6 +399,7 @@ ./services/development/jupyterhub/default.nix ./services/development/rstudio-server/default.nix ./services/development/lorri.nix + ./services/development/zammad.nix ./services/display-managers/greetd.nix ./services/editors/emacs.nix ./services/editors/infinoted.nix @@ -452,6 +458,7 @@ ./services/hardware/vdr.nix ./services/hardware/xow.nix ./services/home-automation/home-assistant.nix + ./services/home-automation/zigbee2mqtt.nix ./services/logging/SystemdJournal2Gelf.nix ./services/logging/awstats.nix ./services/logging/filebeat.nix @@ -497,6 +504,7 @@ ./services/mail/roundcube.nix ./services/mail/sympa.nix ./services/mail/nullmailer.nix + ./services/matrix/matrix-synapse.nix ./services/matrix/mjolnir.nix ./services/matrix/pantalaimon.nix ./services/misc/ananicy.nix @@ -563,7 +571,6 @@ ./services/misc/matrix-appservice-discord.nix ./services/misc/matrix-appservice-irc.nix ./services/misc/matrix-conduit.nix - ./services/misc/matrix-synapse.nix ./services/misc/mautrix-facebook.nix ./services/misc/mautrix-telegram.nix ./services/misc/mbpfan.nix @@ -624,7 +631,6 @@ ./services/misc/weechat.nix ./services/misc/xmr-stak.nix ./services/misc/xmrig.nix - ./services/misc/zigbee2mqtt.nix ./services/misc/zoneminder.nix ./services/misc/zookeeper.nix ./services/monitoring/alerta.nix @@ -816,6 +822,7 @@ ./services/networking/nar-serve.nix ./services/networking/nat.nix ./services/networking/nats.nix + ./services/networking/nbd.nix ./services/networking/ndppd.nix ./services/networking/nebula.nix ./services/networking/networkmanager.nix @@ -875,6 +882,7 @@ ./services/networking/shorewall6.nix ./services/networking/shout.nix ./services/networking/sniproxy.nix + ./services/networking/snowflake-proxy.nix ./services/networking/smartdns.nix ./services/networking/smokeping.nix ./services/networking/softether.nix @@ -899,6 +907,7 @@ ./services/networking/tcpcrypt.nix ./services/networking/teamspeak3.nix ./services/networking/tedicross.nix + ./services/networking/tetrd.nix ./services/networking/teleport.nix ./services/networking/thelounge.nix ./services/networking/tinc.nix @@ -948,7 +957,6 @@ ./services/security/clamav.nix ./services/security/fail2ban.nix ./services/security/fprintd.nix - ./services/security/fprot.nix ./services/security/haka.nix ./services/security/haveged.nix ./services/security/hockeypuck.nix @@ -981,6 +989,7 @@ ./services/system/nscd.nix ./services/system/saslauthd.nix ./services/system/self-deploy.nix + ./services/system/systembus-notify.nix ./services/system/uptimed.nix ./services/torrent/deluge.nix ./services/torrent/flexget.nix diff --git a/nixpkgs/nixos/modules/programs/captive-browser.nix b/nixpkgs/nixos/modules/programs/captive-browser.nix index dc054504ea48..aad554c2bd66 100644 --- a/nixpkgs/nixos/modules/programs/captive-browser.nix +++ b/nixpkgs/nixos/modules/programs/captive-browser.nix @@ -1,8 +1,12 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.programs.captive-browser; + + inherit (lib) + concatStringsSep escapeShellArgs optionalString + literalExpression mkEnableOption mkIf mkOption mkOptionDefault types; + browserDefault = chromium: concatStringsSep " " [ ''env XDG_CONFIG_HOME="$PREV_CONFIG_HOME"'' ''${chromium}/bin/chromium'' @@ -15,6 +19,15 @@ let ''-no-default-browser-check'' ''http://cache.nixos.org/'' ]; + + desktopItem = pkgs.makeDesktopItem { + name = "captive-browser"; + desktopName = "Captive Portal Browser"; + exec = "/run/wrappers/bin/captive-browser"; + icon = "nix-snowflake"; + categories = [ "Network" ]; + }; + in { ###### interface @@ -84,6 +97,11 @@ in ###### implementation config = mkIf cfg.enable { + environment.systemPackages = [ + (pkgs.runCommandNoCC "captive-browser-desktop-item" { } '' + install -Dm444 -t $out/share/applications ${desktopItem}/share/applications/*.desktop + '') + ]; programs.captive-browser.dhcp-dns = let diff --git a/nixpkgs/nixos/modules/programs/firejail.nix b/nixpkgs/nixos/modules/programs/firejail.nix index 8c10d7c4df39..76b42168c198 100644 --- a/nixpkgs/nixos/modules/programs/firejail.nix +++ b/nixpkgs/nixos/modules/programs/firejail.nix @@ -17,8 +17,8 @@ let then value else { executable = value; profile = null; extraArgs = []; }; args = lib.escapeShellArgs ( - (optional (opts.profile != null) "--profile=${toString opts.profile}") - ++ opts.extraArgs + opts.extraArgs + ++ (optional (opts.profile != null) "--profile=${toString opts.profile}") ); in '' diff --git a/nixpkgs/nixos/modules/programs/k40-whisperer.nix b/nixpkgs/nixos/modules/programs/k40-whisperer.nix new file mode 100644 index 000000000000..3163e45f57e4 --- /dev/null +++ b/nixpkgs/nixos/modules/programs/k40-whisperer.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.k40-whisperer; + pkg = cfg.package.override { + udevGroup = cfg.group; + }; +in +{ + options.programs.k40-whisperer = { + enable = mkEnableOption "K40-Whisperer"; + + group = mkOption { + type = types.str; + description = '' + Group assigned to the device when connected. + ''; + default = "k40"; + }; + + package = mkOption { + type = types.package; + default = pkgs.k40-whisperer; + defaultText = literalExpression "pkgs.k40-whisperer"; + example = literalExpression "pkgs.k40-whisperer"; + description = '' + K40 Whisperer package to use. + ''; + }; + }; + + config = mkIf cfg.enable { + users.groups.${cfg.group} = {}; + + environment.systemPackages = [ pkg ]; + services.udev.packages = [ pkg ]; + }; +} diff --git a/nixpkgs/nixos/modules/programs/kclock.nix b/nixpkgs/nixos/modules/programs/kclock.nix new file mode 100644 index 000000000000..42d81d2798ba --- /dev/null +++ b/nixpkgs/nixos/modules/programs/kclock.nix @@ -0,0 +1,13 @@ +{ lib, pkgs, config, ... }: +with lib; +let + cfg = config.programs.kclock; + kclockPkg = pkgs.libsForQt5.kclock; +in { + options.programs.kclock = { enable = mkEnableOption "Enable KClock"; }; + + config = mkIf cfg.enable { + services.dbus.packages = [ kclockPkg ]; + environment.systemPackages = [ kclockPkg ]; + }; +} diff --git a/nixpkgs/nixos/modules/programs/nbd.nix b/nixpkgs/nixos/modules/programs/nbd.nix new file mode 100644 index 000000000000..fea9bc1ff71a --- /dev/null +++ b/nixpkgs/nixos/modules/programs/nbd.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.nbd; +in +{ + options = { + programs.nbd = { + enable = mkEnableOption "Network Block Device (nbd) support"; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = with pkgs; [ nbd ]; + boot.kernelModules = [ "nbd" ]; + }; +} diff --git a/nixpkgs/nixos/modules/programs/phosh.nix b/nixpkgs/nixos/modules/programs/phosh.nix index cba3f73768ec..ad875616ac9e 100644 --- a/nixpkgs/nixos/modules/programs/phosh.nix +++ b/nixpkgs/nixos/modules/programs/phosh.nix @@ -8,18 +8,17 @@ let # Based on https://source.puri.sm/Librem5/librem5-base/-/blob/4596c1056dd75ac7f043aede07887990fd46f572/default/sm.puri.OSK0.desktop oskItem = pkgs.makeDesktopItem { name = "sm.puri.OSK0"; - type = "Application"; desktopName = "On-screen keyboard"; exec = "${pkgs.squeekboard}/bin/squeekboard"; - categories = "GNOME;Core;"; - extraEntries = '' - OnlyShowIn=GNOME; - NoDisplay=true - X-GNOME-Autostart-Phase=Panel - X-GNOME-Provides=inputmethod - X-GNOME-Autostart-Notify=true - X-GNOME-AutoRestart=true - ''; + categories = [ "GNOME" "Core" ]; + onlyShowIn = [ "GNOME" ]; + noDisplay = true; + extraConfig = { + X-GNOME-Autostart-Phase = "Panel"; + X-GNOME-Provides = "inputmethod"; + X-GNOME-Autostart-Notify = "true"; + X-GNOME-AutoRestart = "true"; + }; }; phocConfigType = types.submodule { diff --git a/nixpkgs/nixos/modules/programs/sway.nix b/nixpkgs/nixos/modules/programs/sway.nix index bb9904d19560..01b047281344 100644 --- a/nixpkgs/nixos/modules/programs/sway.nix +++ b/nixpkgs/nixos/modules/programs/sway.nix @@ -134,6 +134,7 @@ in { ''; }; }; + security.polkit.enable = true; security.pam.services.swaylock = {}; hardware.opengl.enable = mkDefault true; fonts.enableDefaultFonts = mkDefault true; diff --git a/nixpkgs/nixos/modules/programs/zsh/zsh-autosuggestions.nix b/nixpkgs/nixos/modules/programs/zsh/zsh-autosuggestions.nix index fee324cc7326..2e53e907d547 100644 --- a/nixpkgs/nixos/modules/programs/zsh/zsh-autosuggestions.nix +++ b/nixpkgs/nixos/modules/programs/zsh/zsh-autosuggestions.nix @@ -22,17 +22,18 @@ in }; strategy = mkOption { - type = types.enum [ "history" "match_prev_cmd" ]; - default = "history"; + type = types.listOf (types.enum [ "history" "completion" "match_prev_cmd" ]); + default = [ "history" ]; description = '' - Set ZSH_AUTOSUGGEST_STRATEGY to choose the strategy for generating suggestions. - There are currently two to choose from: + `ZSH_AUTOSUGGEST_STRATEGY` is an array that specifies how suggestions should be generated. + The strategies in the array are tried successively until a suggestion is found. + There are currently three built-in strategies to choose from: - * history: Chooses the most recent match. - * match_prev_cmd: Chooses the most recent match whose preceding history item matches - the most recently executed command (more info). Note that this strategy won't work as - expected with ZSH options that don't preserve the history order such as - HIST_IGNORE_ALL_DUPS or HIST_EXPIRE_DUPS_FIRST. + - `history`: Chooses the most recent match from history. + - `completion`: Chooses a suggestion based on what tab-completion would suggest. (requires `zpty` module) + - `match_prev_cmd`: Like `history`, but chooses the most recent match whose preceding history item matches + the most recently executed command. Note that this strategy won't work as expected with ZSH options that + don't preserve the history order such as `HIST_IGNORE_ALL_DUPS` or `HIST_EXPIRE_DUPS_FIRST`. ''; }; @@ -62,7 +63,7 @@ in source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh export ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="${cfg.highlightStyle}" - export ZSH_AUTOSUGGEST_STRATEGY=("${cfg.strategy}") + export ZSH_AUTOSUGGEST_STRATEGY=(${concatStringsSep " " cfg.strategy}) ${optionalString (!cfg.async) "unset ZSH_AUTOSUGGEST_USE_ASYNC"} ${concatStringsSep "\n" (mapAttrsToList (key: value: ''export ${key}="${value}"'') cfg.extraConfig)} diff --git a/nixpkgs/nixos/modules/rename.nix b/nixpkgs/nixos/modules/rename.nix index c271d504b771..195cf87e6a85 100644 --- a/nixpkgs/nixos/modules/rename.nix +++ b/nixpkgs/nixos/modules/rename.nix @@ -50,6 +50,7 @@ with lib; (mkRemovedOptionModule [ "services" "flashpolicyd" ] "The flashpolicyd module has been removed. Adobe Flash Player is deprecated.") (mkRemovedOptionModule [ "services" "fourStore" ] "The fourStore module has been removed") (mkRemovedOptionModule [ "services" "fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed") + (mkRemovedOptionModule [ "services" "fprot" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "frab" ] "The frab module has been removed") (mkRemovedOptionModule [ "services" "kippo" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "mailpile" ] "The corresponding package was removed from nixpkgs.") @@ -87,10 +88,9 @@ with lib; (mkRemovedOptionModule [ "services" "racoon" ] '' The racoon module has been removed, because the software project was abandoned upstream. '') - (mkRemovedOptionModule [ "services" "shellinabox" ] "The corresponding package was removed from nixpkgs.") - (mkRemovedOptionModule [ "services" "gogoclient" ] "The corresponding package was removed from nixpkgs.") + (mkRemovedOptionModule [ "services" "virtuoso" ] "The corresponding package was removed from nixpkgs.") # Do NOT add any option renames here, see top of the file ]; diff --git a/nixpkgs/nixos/modules/security/pam.nix b/nixpkgs/nixos/modules/security/pam.nix index 9f295db84fd6..c0ef8b5f30bd 100644 --- a/nixpkgs/nixos/modules/security/pam.nix +++ b/nixpkgs/nixos/modules/security/pam.nix @@ -518,7 +518,7 @@ let auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"} '' + optionalString cfg.googleAuthenticator.enable '' - auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp + auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so no_increment_hotp '' + optionalString cfg.duoSecurity.enable '' auth required ${pkgs.duo-unix}/lib/security/pam_duo.so diff --git a/nixpkgs/nixos/modules/security/polkit.nix b/nixpkgs/nixos/modules/security/polkit.nix index d9c58152f1fa..1ba149745c65 100644 --- a/nixpkgs/nixos/modules/security/polkit.nix +++ b/nixpkgs/nixos/modules/security/polkit.nix @@ -12,11 +12,7 @@ in options = { - security.polkit.enable = mkOption { - type = types.bool; - default = true; - description = "Whether to enable PolKit."; - }; + security.polkit.enable = mkEnableOption "polkit"; security.polkit.extraConfig = mkOption { type = types.lines; diff --git a/nixpkgs/nixos/modules/security/systemd-confinement.nix b/nixpkgs/nixos/modules/security/systemd-confinement.nix index 0e3ec5af323e..f3a2de3bf87a 100644 --- a/nixpkgs/nixos/modules/security/systemd-confinement.nix +++ b/nixpkgs/nixos/modules/security/systemd-confinement.nix @@ -175,8 +175,8 @@ in { serviceName = "${name}.service"; excludedPath = rootPaths; } '' - mkdir -p "$out/lib/systemd/system" - serviceFile="$out/lib/systemd/system/$serviceName" + mkdir -p "$out/lib/systemd/system/$serviceName.d" + serviceFile="$out/lib/systemd/system/$serviceName.d/confinement.conf" echo '[Service]' > "$serviceFile" diff --git a/nixpkgs/nixos/modules/services/admin/pgadmin.nix b/nixpkgs/nixos/modules/services/admin/pgadmin.nix new file mode 100644 index 000000000000..80b681454104 --- /dev/null +++ b/nixpkgs/nixos/modules/services/admin/pgadmin.nix @@ -0,0 +1,127 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + pkg = pkgs.pgadmin4; + cfg = config.services.pgadmin; + + _base = with types; [ int bool str ]; + base = with types; oneOf ([ (listOf (oneOf _base)) (attrsOf (oneOf _base)) ] ++ _base); + + formatAttrset = attr: + "{${concatStringsSep "\n" (mapAttrsToList (key: value: "${builtins.toJSON key}: ${formatPyValue value},") attr)}}"; + + formatPyValue = value: + if builtins.isString value then builtins.toJSON value + else if value ? _expr then value._expr + else if builtins.isInt value then toString value + else if builtins.isBool value then (if value then "True" else "False") + else if builtins.isAttrs value then (formatAttrset value) + else if builtins.isList value then "[${concatStringsSep "\n" (map (v: "${formatPyValue v},") value)}]" + else throw "Unrecognized type"; + + formatPy = attrs: + concatStringsSep "\n" (mapAttrsToList (key: value: "${key} = ${formatPyValue value}") attrs); + + pyType = with types; attrsOf (oneOf [ (attrsOf base) (listOf base) base ]); +in +{ + options.services.pgadmin = { + enable = mkEnableOption "PostgreSQL Admin 4"; + + port = mkOption { + description = "Port for pgadmin4 to run on"; + type = types.port; + default = 5050; + }; + + initialEmail = mkOption { + description = "Initial email for the pgAdmin account."; + type = types.str; + }; + + initialPasswordFile = mkOption { + description = '' + Initial password file for the pgAdmin account. + NOTE: Should be string not a store path, to prevent the password from being world readable. + ''; + type = types.path; + }; + + openFirewall = mkEnableOption "firewall passthrough for pgadmin4"; + + settings = mkOption { + description = '' + Settings for pgadmin4. + <link xlink:href="https://www.pgadmin.org/docs/pgadmin4/development/config_py.html">Documentation</link>. + ''; + type = pyType; + default= {}; + }; + }; + + config = mkIf (cfg.enable) { + networking.firewall.allowedTCPPorts = mkIf (cfg.openFirewall) [ cfg.port ]; + + services.pgadmin.settings = { + DEFAULT_SERVER_PORT = cfg.port; + SERVER_MODE = true; + } // (optionalAttrs cfg.openFirewall { + DEFAULT_SERVER = mkDefault "::"; + }); + + systemd.services.pgadmin = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + requires = [ "network.target" ]; + # we're adding this optionally so just in case there's any race it'll be caught + # in case postgres doesn't start, pgadmin will just start normally + wants = [ "postgresql.service" ]; + + path = [ config.services.postgresql.package pkgs.coreutils pkgs.bash ]; + + preStart = '' + # NOTE: this is idempotent (aka running it twice has no effect) + ( + # Email address: + echo ${escapeShellArg cfg.initialEmail} + + # file might not contain newline. echo hack fixes that. + PW=$(cat ${escapeShellArg cfg.initialPasswordFile}) + + # Password: + echo "$PW" + # Retype password: + echo "$PW" + ) | ${pkg}/bin/pgadmin4-setup + ''; + + restartTriggers = [ + "/etc/pgadmin/config_system.py" + ]; + + serviceConfig = { + User = "pgadmin"; + DynamicUser = true; + LogsDirectory = "pgadmin"; + StateDirectory = "pgadmin"; + ExecStart = "${pkg}/bin/pgadmin4"; + }; + }; + + users.users.pgadmin = { + isSystemUser = true; + group = "pgadmin"; + }; + + users.groups.pgadmin = {}; + + environment.etc."pgadmin/config_system.py" = { + text = formatPy cfg.settings; + mode = "0600"; + user = "pgadmin"; + group = "pgadmin"; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/audio/snapserver.nix b/nixpkgs/nixos/modules/services/audio/snapserver.nix index b82aca3976f0..6d5ce98df895 100644 --- a/nixpkgs/nixos/modules/services/audio/snapserver.nix +++ b/nixpkgs/nixos/modules/services/audio/snapserver.nix @@ -44,24 +44,24 @@ let optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams # global options - ++ [ "--stream.bind_to_address ${cfg.listenAddress}" ] - ++ [ "--stream.port ${toString cfg.port}" ] - ++ optionalNull cfg.sampleFormat "--stream.sampleformat ${cfg.sampleFormat}" - ++ optionalNull cfg.codec "--stream.codec ${cfg.codec}" - ++ optionalNull cfg.streamBuffer "--stream.stream_buffer ${toString cfg.streamBuffer}" - ++ optionalNull cfg.buffer "--stream.buffer ${toString cfg.buffer}" + ++ [ "--stream.bind_to_address=${cfg.listenAddress}" ] + ++ [ "--stream.port=${toString cfg.port}" ] + ++ optionalNull cfg.sampleFormat "--stream.sampleformat=${cfg.sampleFormat}" + ++ optionalNull cfg.codec "--stream.codec=${cfg.codec}" + ++ optionalNull cfg.streamBuffer "--stream.stream_buffer=${toString cfg.streamBuffer}" + ++ optionalNull cfg.buffer "--stream.buffer=${toString cfg.buffer}" ++ optional cfg.sendToMuted "--stream.send_to_muted" # tcp json rpc - ++ [ "--tcp.enabled ${toString cfg.tcp.enable}" ] + ++ [ "--tcp.enabled=${toString cfg.tcp.enable}" ] ++ optionals cfg.tcp.enable [ - "--tcp.bind_to_address ${cfg.tcp.listenAddress}" - "--tcp.port ${toString cfg.tcp.port}" ] + "--tcp.bind_to_address=${cfg.tcp.listenAddress}" + "--tcp.port=${toString cfg.tcp.port}" ] # http json rpc - ++ [ "--http.enabled ${toString cfg.http.enable}" ] + ++ [ "--http.enabled=${toString cfg.http.enable}" ] ++ optionals cfg.http.enable [ - "--http.bind_to_address ${cfg.http.listenAddress}" - "--http.port ${toString cfg.http.port}" - ] ++ optional (cfg.http.docRoot != null) "--http.doc_root \"${toString cfg.http.docRoot}\""); + "--http.bind_to_address=${cfg.http.listenAddress}" + "--http.port=${toString cfg.http.port}" + ] ++ optional (cfg.http.docRoot != null) "--http.doc_root=\"${toString cfg.http.docRoot}\""); in { imports = [ diff --git a/nixpkgs/nixos/modules/services/audio/squeezelite.nix b/nixpkgs/nixos/modules/services/audio/squeezelite.nix index 05506f5bcc7a..36295e21c60f 100644 --- a/nixpkgs/nixos/modules/services/audio/squeezelite.nix +++ b/nixpkgs/nixos/modules/services/audio/squeezelite.nix @@ -1,50 +1,46 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkEnableOption mkIf mkOption optionalString types; + dataDir = "/var/lib/squeezelite"; cfg = config.services.squeezelite; + pkg = if cfg.pulseAudio then pkgs.squeezelite-pulse else pkgs.squeezelite; + bin = "${pkg}/bin/${pkg.pname}"; -in { +in +{ ###### interface - options = { - - services.squeezelite= { + options.services.squeezelite = { + enable = mkEnableOption "Squeezelite, a software Squeezebox emulator"; - enable = mkEnableOption "Squeezelite, a software Squeezebox emulator"; - - extraArguments = mkOption { - default = ""; - type = types.str; - description = '' - Additional command line arguments to pass to Squeezelite. - ''; - }; + pulseAudio = mkEnableOption "pulseaudio support"; + extraArguments = mkOption { + default = ""; + type = types.str; + description = '' + Additional command line arguments to pass to Squeezelite. + ''; }; - }; ###### implementation config = mkIf cfg.enable { - - systemd.services.squeezelite= { + systemd.services.squeezelite = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" "sound.target" ]; description = "Software Squeezebox emulator"; serviceConfig = { DynamicUser = true; - ExecStart = "${pkgs.squeezelite}/bin/squeezelite -N ${dataDir}/player-name ${cfg.extraArguments}"; + ExecStart = "${bin} -N ${dataDir}/player-name ${cfg.extraArguments}"; StateDirectory = builtins.baseNameOf dataDir; SupplementaryGroups = "audio"; }; }; - }; - } diff --git a/nixpkgs/nixos/modules/services/cluster/k3s/default.nix b/nixpkgs/nixos/modules/services/cluster/k3s/default.nix index 50b6780bbe66..3a36cfa3f37b 100644 --- a/nixpkgs/nixos/modules/services/cluster/k3s/default.nix +++ b/nixpkgs/nixos/modules/services/cluster/k3s/default.nix @@ -91,11 +91,6 @@ in virtualisation.docker = mkIf cfg.docker { enable = mkDefault true; }; - - # TODO: disable this once k3s supports cgroupsv2, either by docker - # supporting it, or their bundled containerd - systemd.enableUnifiedCgroupHierarchy = false; - environment.systemPackages = [ config.services.k3s.package ]; systemd.services.k3s = { @@ -119,6 +114,7 @@ in [ "${cfg.package}/bin/k3s ${cfg.role}" ] ++ (optional cfg.docker "--docker") + ++ (optional (cfg.docker && config.systemd.enableUnifiedCgroupHierarchy) "--kubelet-arg=cgroup-driver=systemd") ++ (optional cfg.disableAgent "--disable-agent") ++ (optional (cfg.serverAddr != "") "--server ${cfg.serverAddr}") ++ (optional (cfg.token != "") "--token ${cfg.token}") diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix index 88bde4e91557..7d9198d20e8c 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix @@ -266,7 +266,7 @@ in in '' export KUBECONFIG=${clusterAdminKubeconfig} - ${kubectl}/bin/kubectl apply -f ${concatStringsSep " \\\n -f " files} + ${kubernetes}/bin/kubectl apply -f ${concatStringsSep " \\\n -f " files} ''; })]); diff --git a/nixpkgs/nixos/modules/services/continuous-integration/github-runner.nix b/nixpkgs/nixos/modules/services/continuous-integration/github-runner.nix index c3bd8f99c57f..a7645e1f56e9 100644 --- a/nixpkgs/nixos/modules/services/continuous-integration/github-runner.nix +++ b/nixpkgs/nixos/modules/services/continuous-integration/github-runner.nix @@ -34,6 +34,14 @@ in Repository to add the runner to. Changing this option triggers a new runner registration. + + IMPORTANT: If your token is org-wide (not per repository), you need to + provide a github org link, not a single repository, so do it like this + <literal>https://github.com/nixos</literal>, not like this + <literal>https://github.com/nixos/nixpkgs</literal>. + Otherwise, you are going to get a <literal>404 NotFound</literal> + from <literal>POST https://api.github.com/actions/runner-registration</literal> + in the configure script. ''; example = "https://github.com/nixos/nixpkgs"; }; diff --git a/nixpkgs/nixos/modules/services/databases/redis.nix b/nixpkgs/nixos/modules/services/databases/redis.nix index e0269a962fdd..a1bd73c9e371 100644 --- a/nixpkgs/nixos/modules/services/databases/redis.nix +++ b/nixpkgs/nixos/modules/services/databases/redis.nix @@ -81,7 +81,9 @@ in { user = mkOption { type = types.str; default = redisName name; - defaultText = "\"redis\" or \"redis-\${name}\" if name != \"\""; + defaultText = literalExpression '' + if name == "" then "redis" else "redis-''${name}" + ''; description = "The username and groupname for redis-server."; }; @@ -105,8 +107,7 @@ in { bind = mkOption { type = with types; nullOr str; - default = if name == "" then "127.0.0.1" else null; - defaultText = literalExpression ''if name == "" then "127.0.0.1" else null''; + default = "127.0.0.1"; description = '' The IP interface to bind to. <literal>null</literal> means "all interfaces". @@ -117,7 +118,9 @@ in { unixSocket = mkOption { type = with types; nullOr path; default = "/run/${redisName name}/redis.sock"; - defaultText = "\"/run/redis/redis.sock\" or \"/run/redis-\${name}/redis.sock\" if name != \"\""; + defaultText = literalExpression '' + if name == "" then "/run/redis/redis.sock" else "/run/redis-''${name}/redis.sock" + ''; description = "The path to the socket to bind to."; }; @@ -370,7 +373,7 @@ in { ProtectKernelTunables = true; ProtectControlGroups = true; RestrictAddressFamilies = - optionals (conf.bind != null) ["AF_INET" "AF_INET6"] ++ + optionals (conf.port != 0) ["AF_INET" "AF_INET6"] ++ optional (conf.unixSocket != null) "AF_UNIX"; RestrictNamespaces = true; LockPersonality = true; diff --git a/nixpkgs/nixos/modules/services/databases/virtuoso.nix b/nixpkgs/nixos/modules/services/databases/virtuoso.nix deleted file mode 100644 index 8b01622ecb03..000000000000 --- a/nixpkgs/nixos/modules/services/databases/virtuoso.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ config, lib, pkgs, ... }: -let - cfg = config.services.virtuoso; - virtuosoUser = "virtuoso"; - stateDir = "/var/lib/virtuoso"; -in -with lib; -{ - - ###### interface - - options = { - - services.virtuoso = { - - enable = mkEnableOption "Virtuoso Opensource database server"; - - config = mkOption { - type = types.lines; - default = ""; - description = "Extra options to put into Virtuoso configuration file."; - }; - - parameters = mkOption { - type = types.lines; - default = ""; - description = "Extra options to put into [Parameters] section of Virtuoso configuration file."; - }; - - listenAddress = mkOption { - type = types.str; - default = "1111"; - example = "myserver:1323"; - description = "ip:port or port to listen on."; - }; - - httpListenAddress = mkOption { - type = types.nullOr types.str; - default = null; - example = "myserver:8080"; - description = "ip:port or port for Virtuoso HTTP server to listen on."; - }; - - dirsAllowed = mkOption { - type = types.nullOr types.str; # XXX Maybe use a list in the future? - default = null; - example = "/www, /home/"; - description = "A list of directories Virtuoso is allowed to access"; - }; - }; - - }; - - - ###### implementation - - config = mkIf cfg.enable { - - users.users.${virtuosoUser} = - { uid = config.ids.uids.virtuoso; - description = "virtuoso user"; - home = stateDir; - }; - - systemd.services.virtuoso = { - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - - preStart = '' - mkdir -p ${stateDir} - chown ${virtuosoUser} ${stateDir} - ''; - - script = '' - cd ${stateDir} - ${pkgs.virtuoso}/bin/virtuoso-t +foreground +configfile ${pkgs.writeText "virtuoso.ini" cfg.config} - ''; - }; - - services.virtuoso.config = '' - [Database] - DatabaseFile=${stateDir}/x-virtuoso.db - TransactionFile=${stateDir}/x-virtuoso.trx - ErrorLogFile=${stateDir}/x-virtuoso.log - xa_persistent_file=${stateDir}/x-virtuoso.pxa - - [Parameters] - ServerPort=${cfg.listenAddress} - RunAs=${virtuosoUser} - ${optionalString (cfg.dirsAllowed != null) "DirsAllowed=${cfg.dirsAllowed}"} - ${cfg.parameters} - - [HTTPServer] - ${optionalString (cfg.httpListenAddress != null) "ServerPort=${cfg.httpListenAddress}"} - ''; - - }; - -} diff --git a/nixpkgs/nixos/modules/services/desktops/flatpak.nix b/nixpkgs/nixos/modules/services/desktops/flatpak.nix index 7da92cc9f264..5fecc64b4f70 100644 --- a/nixpkgs/nixos/modules/services/desktops/flatpak.nix +++ b/nixpkgs/nixos/modules/services/desktops/flatpak.nix @@ -30,6 +30,8 @@ in { environment.systemPackages = [ pkgs.flatpak ]; + security.polkit.enable = true; + services.dbus.packages = [ pkgs.flatpak ]; systemd.packages = [ pkgs.flatpak ]; diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json b/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json index 284d8c394a61..9aa51b61431d 100644 --- a/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json +++ b/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json @@ -8,7 +8,7 @@ }, "context.modules": [ { - "name": "libpipewire-module-rtkit", + "name": "libpipewire-module-rt", "args": {}, "flags": [ "ifexists", diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json b/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json new file mode 100644 index 000000000000..c7f58fd5799a --- /dev/null +++ b/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json @@ -0,0 +1,118 @@ +{ + "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, + "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, + "position": "unknown" + } + } + } + ], + "context.exec": [] +} diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json b/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json index 3ed994f11145..df0f62556dff 100644 --- a/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json +++ b/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json @@ -6,8 +6,10 @@ }, "context.modules": [ { - "name": "libpipewire-module-rtkit", - "args": {}, + "name": "libpipewire-module-rt", + "args": { + "nice.level": -11 + }, "flags": [ "ifexists", "nofail" @@ -37,6 +39,61 @@ } } ], - "context.exec": [], - "stream.properties": {} + "context.exec": [ + { + "path": "pactl", + "args": "load-module module-always-sink" + } + ], + "stream.properties": {}, + "pulse.rules": [ + { + "matches": [ + {} + ], + "actions": { + "update-props": {} + } + }, + { + "matches": [ + { + "application.process.binary": "teams" + }, + { + "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": "1024/48000", + "pulse.min.quantum": "1024/48000" + } + } + } + ] } diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json b/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json index a923ab4db235..7c79f0168c02 100644 --- a/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json +++ b/nixpkgs/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json @@ -3,6 +3,7 @@ "link.max-buffers": 16, "core.daemon": true, "core.name": "pipewire-0", + "default.clock.min-quantum": 16, "vm.overrides": { "default.clock.min-quantum": 1024 } @@ -19,8 +20,10 @@ }, "context.modules": [ { - "name": "libpipewire-module-rtkit", - "args": {}, + "name": "libpipewire-module-rt", + "args": { + "nice.level": -11 + }, "flags": [ "ifexists", "nofail" diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix b/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix index f7a03a4a3eaf..109c91134b99 100644 --- a/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix +++ b/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix @@ -38,9 +38,8 @@ in { services.pipewire.media-session = { enable = mkOption { type = types.bool; - default = config.services.pipewire.enable; - defaultText = literalExpression "config.services.pipewire.enable"; - description = "Example pipewire session manager"; + default = false; + description = "Whether to enable the deprecated example Pipewire session manager"; }; package = mkOption { diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire.nix b/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire.nix index c3cfd46e61c2..59e9342a6ea1 100644 --- a/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire.nix +++ b/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire.nix @@ -25,15 +25,18 @@ let 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 defaults.pipewire cfg.config.pipewire; + pipewire = recursiveUpdate (if useSessionManager then defaults.pipewire else defaults.minimal) cfg.config.pipewire; pipewire-pulse = recursiveUpdate defaults.pipewire-pulse cfg.config.pipewire-pulse; }; in { diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/wireplumber.nix b/nixpkgs/nixos/modules/services/desktops/pipewire/wireplumber.nix index ad96dc1f9745..52ec17b95db4 100644 --- a/nixpkgs/nixos/modules/services/desktops/pipewire/wireplumber.nix +++ b/nixpkgs/nixos/modules/services/desktops/pipewire/wireplumber.nix @@ -8,15 +8,18 @@ in options = { services.pipewire.wireplumber = { - enable = lib.mkEnableOption "A modular session / policy manager for PipeWire"; + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.pipewire.enable; + defaultText = lib.literalExpression "config.services.pipewire.enable"; + description = "Whether to enable Wireplumber, a modular session / policy manager for PipeWire"; + }; package = lib.mkOption { type = lib.types.package; default = pkgs.wireplumber; defaultText = lib.literalExpression "pkgs.wireplumber"; - description = '' - The wireplumber derivation to use. - ''; + description = "The wireplumber derivation to use."; }; }; }; diff --git a/nixpkgs/nixos/modules/services/development/zammad.nix b/nixpkgs/nixos/modules/services/development/zammad.nix new file mode 100644 index 000000000000..d457a6071873 --- /dev/null +++ b/nixpkgs/nixos/modules/services/development/zammad.nix @@ -0,0 +1,323 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.zammad; + settingsFormat = pkgs.formats.yaml { }; + filterNull = filterAttrs (_: v: v != null); + serviceConfig = { + Type = "simple"; + Restart = "always"; + + User = "zammad"; + Group = "zammad"; + PrivateTmp = true; + StateDirectory = "zammad"; + WorkingDirectory = cfg.dataDir; + }; + environment = { + RAILS_ENV = "production"; + NODE_ENV = "production"; + RAILS_SERVE_STATIC_FILES = "true"; + RAILS_LOG_TO_STDOUT = "true"; + }; + databaseConfig = settingsFormat.generate "database.yml" cfg.database.settings; +in +{ + + options = { + services.zammad = { + enable = mkEnableOption "Zammad, a web-based, open source user support/ticketing solution."; + + package = mkOption { + type = types.package; + default = pkgs.zammad; + defaultText = literalExpression "pkgs.zammad"; + description = "Zammad package to use."; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/zammad"; + description = '' + Path to a folder that will contain Zammad working directory. + ''; + }; + + host = mkOption { + type = types.str; + default = "127.0.0.1"; + example = "192.168.23.42"; + description = "Host address."; + }; + + openPorts = mkOption { + type = types.bool; + default = false; + description = "Whether to open firewall ports for Zammad"; + }; + + port = mkOption { + type = types.port; + default = 3000; + description = "Web service port."; + }; + + websocketPort = mkOption { + type = types.port; + default = 6042; + description = "Websocket service port."; + }; + + database = { + type = mkOption { + type = types.enum [ "PostgreSQL" "MySQL" ]; + default = "PostgreSQL"; + example = "MySQL"; + description = "Database engine to use."; + }; + + host = mkOption { + type = types.nullOr types.str; + default = { + PostgreSQL = "/run/postgresql"; + MySQL = "localhost"; + }.${cfg.database.type}; + defaultText = literalExpression '' + { + PostgreSQL = "/run/postgresql"; + MySQL = "localhost"; + }.''${config.services.zammad.database.type}; + ''; + description = '' + Database host address. + ''; + }; + + port = mkOption { + type = types.nullOr types.port; + default = null; + description = "Database port. Use <literal>null</literal> for default port."; + }; + + name = mkOption { + type = types.str; + default = "zammad"; + description = '' + Database name. + ''; + }; + + user = mkOption { + type = types.nullOr types.str; + default = "zammad"; + description = "Database user."; + }; + + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/zammad-dbpassword"; + description = '' + A file containing the password for <option>services.zammad.database.user</option>. + ''; + }; + + createLocally = mkOption { + type = types.bool; + default = true; + description = "Whether to create a local database automatically."; + }; + + settings = mkOption { + type = settingsFormat.type; + default = { }; + example = literalExpression '' + { + } + ''; + description = '' + The <filename>database.yml</filename> configuration file as key value set. + See <link xlink:href='TODO' /> + for list of configuration parameters. + ''; + }; + }; + + secretKeyBaseFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/secret_key_base"; + description = '' + The path to a file containing the + <literal>secret_key_base</literal> secret. + + Zammad uses <literal>secret_key_base</literal> to encrypt + the cookie store, which contains session data, and to digest + user auth tokens. + + Needs to be a 64 byte long string of hexadecimal + characters. You can generate one by running + + <screen> + <prompt>$ </prompt>openssl rand -hex 64 >/path/to/secret_key_base_file + </screen> + + This should be a string, not a nix path, since nix paths are + copied into the world-readable nix store. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + + services.zammad.database.settings = { + production = mapAttrs (_: v: mkDefault v) (filterNull { + adapter = { + PostgreSQL = "postgresql"; + MySQL = "mysql2"; + }.${cfg.database.type}; + database = cfg.database.name; + pool = 50; + timeout = 5000; + encoding = "utf8"; + username = cfg.database.user; + host = cfg.database.host; + port = cfg.database.port; + }); + }; + + networking.firewall.allowedTCPPorts = mkIf cfg.openPorts [ + config.services.zammad.port + config.services.zammad.websocketPort + ]; + + users.users.zammad = { + isSystemUser = true; + home = cfg.dataDir; + group = "zammad"; + }; + + users.groups.zammad = { }; + + assertions = [ + { + assertion = cfg.database.createLocally -> cfg.database.user == "zammad"; + message = "services.zammad.database.user must be set to \"zammad\" if services.zammad.database.createLocally is set to true"; + } + { + assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; + message = "a password cannot be specified if services.zammad.database.createLocally is set to true"; + } + ]; + + services.mysql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "MySQL") { + enable = true; + package = mkDefault pkgs.mariadb; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { + name = cfg.database.user; + ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; }; + } + ]; + }; + + services.postgresql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "PostgreSQL") { + enable = true; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { + name = cfg.database.user; + ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; }; + } + ]; + }; + + systemd.services.zammad-web = { + inherit environment; + serviceConfig = serviceConfig // { + # loading all the gems takes time + TimeoutStartSec = 1200; + }; + after = [ + "network.target" + "postgresql.service" + ]; + requires = [ + "postgresql.service" + ]; + description = "Zammad web"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + # Blindly copy the whole project here. + chmod -R +w . + rm -rf ./public/assets/* + rm -rf ./tmp/* + rm -rf ./log/* + cp -r --no-preserve=owner ${cfg.package}/* . + chmod -R +w . + # config file + cp ${databaseConfig} ./config/database.yml + chmod -R +w . + ${optionalString (cfg.database.passwordFile != null) '' + { + echo -n " password: " + cat ${cfg.database.passwordFile} + } >> ./config/database.yml + ''} + ${optionalString (cfg.secretKeyBaseFile != null) '' + { + echo "production: " + echo -n " secret_key_base: " + cat ${cfg.secretKeyBaseFile} + } > ./config/secrets.yml + ''} + + if [ `${config.services.postgresql.package}/bin/psql \ + --host ${cfg.database.host} \ + ${optionalString + (cfg.database.port != null) + "--port ${toString cfg.database.port}"} \ + --username ${cfg.database.user} \ + --dbname ${cfg.database.name} \ + --command "SELECT COUNT(*) FROM pg_class c \ + JOIN pg_namespace s ON s.oid = c.relnamespace \ + WHERE s.nspname NOT IN ('pg_catalog', 'pg_toast', 'information_schema') \ + AND s.nspname NOT LIKE 'pg_temp%';" | sed -n 3p` -eq 0 ]; then + echo "Initialize database" + ./bin/rake --no-system db:migrate + ./bin/rake --no-system db:seed + else + echo "Migrate database" + ./bin/rake --no-system db:migrate + fi + echo "Done" + ''; + script = "./script/rails server -b ${cfg.host} -p ${toString cfg.port}"; + }; + + systemd.services.zammad-websocket = { + inherit serviceConfig environment; + after = [ "zammad-web.service" ]; + requires = [ "zammad-web.service" ]; + description = "Zammad websocket"; + wantedBy = [ "multi-user.target" ]; + script = "./script/websocket-server.rb -b ${cfg.host} -p ${toString cfg.websocketPort} start"; + }; + + systemd.services.zammad-scheduler = { + inherit environment; + serviceConfig = serviceConfig // { Type = "forking"; }; + after = [ "zammad-web.service" ]; + requires = [ "zammad-web.service" ]; + description = "Zammad scheduler"; + wantedBy = [ "multi-user.target" ]; + script = "./script/scheduler.rb start"; + }; + }; + + meta.maintainers = with lib.maintainers; [ garbas taeer ]; +} diff --git a/nixpkgs/nixos/modules/services/hardware/udisks2.nix b/nixpkgs/nixos/modules/services/hardware/udisks2.nix index e898f3260585..6be23f39754e 100644 --- a/nixpkgs/nixos/modules/services/hardware/udisks2.nix +++ b/nixpkgs/nixos/modules/services/hardware/udisks2.nix @@ -32,6 +32,8 @@ with lib; environment.systemPackages = [ pkgs.udisks2 ]; + security.polkit.enable = true; + services.dbus.packages = [ pkgs.udisks2 ]; systemd.tmpfiles.rules = [ "d /var/lib/udisks2 0755 root root -" ]; diff --git a/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix b/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix index f4197650ab23..6022227f6ea8 100644 --- a/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix +++ b/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix @@ -135,7 +135,7 @@ in { }; config = mkOption { - type = types.submodule { + type = types.nullOr (types.submodule { freeformType = format.type; options = { # This is a partial selection of the most common options, so new users can quickly @@ -244,7 +244,7 @@ in { }; }; }; - }; + }); example = literalExpression '' { homeassistant = { @@ -349,10 +349,6 @@ in { ''; description = '' The Home Assistant package to use. - Override <literal>extraPackages</literal> or <literal>extraComponents</literal> in order to add additional dependencies. - If you specify <option>config</option> and do not set <option>autoExtraComponents</option> - to <literal>false</literal>, overriding <literal>extraComponents</literal> will have no effect. - Avoid <literal>home-assistant.overridePythonAttrs</literal> if you use <literal>autoExtraComponents</literal>. ''; }; diff --git a/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix b/nixpkgs/nixos/modules/services/home-automation/zigbee2mqtt.nix index ff6d595e5a6e..ff6d595e5a6e 100644 --- a/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix +++ b/nixpkgs/nixos/modules/services/home-automation/zigbee2mqtt.nix diff --git a/nixpkgs/nixos/modules/services/logging/logrotate.nix b/nixpkgs/nixos/modules/services/logging/logrotate.nix index 8cef4e8c083a..082cf92ff4ef 100644 --- a/nixpkgs/nixos/modules/services/logging/logrotate.nix +++ b/nixpkgs/nixos/modules/services/logging/logrotate.nix @@ -4,7 +4,6 @@ with lib; let cfg = config.services.logrotate; - inherit (config.users) groups; pathOpts = { name, ... }: { options = { @@ -85,10 +84,6 @@ let }; config.name = name; - config.extraConfig = '' - missingok - notifempty - ''; }; mkConf = pathOpts: '' @@ -102,7 +97,11 @@ let ''; paths = sortProperties (attrValues (filterAttrs (_: pathOpts: pathOpts.enable) cfg.paths)); - configFile = pkgs.writeText "logrotate.conf" (concatStringsSep "\n" ((map mkConf paths) ++ [ cfg.extraConfig ])); + configFile = pkgs.writeText "logrotate.conf" ( + concatStringsSep "\n" ( + [ "missingok" "notifempty" cfg.extraConfig ] ++ (map mkConf paths) + ) + ); in { @@ -112,7 +111,10 @@ in options = { services.logrotate = { - enable = mkEnableOption "the logrotate systemd service"; + enable = mkEnableOption "the logrotate systemd service" // { + default = foldr (n: a: a || n.enable) false (attrValues cfg.paths); + defaultText = literalExpression "cfg.paths != {}"; + }; paths = mkOption { type = with types; attrsOf (submodule pathOpts); @@ -163,28 +165,8 @@ in } ) cfg.paths; - services.logrotate = { - paths = { - "/var/log/btmp" = { - frequency = mkDefault "monthly"; - keep = mkDefault 1; - extraConfig = '' - create 0660 root ${groups.utmp.name} - ''; - }; - "/var/log/wtmp" = { - frequency = mkDefault "monthly"; - keep = mkDefault 1; - extraConfig = '' - create 0664 root ${groups.utmp.name} - ''; - }; - }; - }; - systemd.services.logrotate = { description = "Logrotate Service"; - wantedBy = [ "multi-user.target" ]; startAt = "hourly"; serviceConfig = { diff --git a/nixpkgs/nixos/modules/services/misc/matrix-synapse-log_config.yaml b/nixpkgs/nixos/modules/services/matrix/matrix-synapse-log_config.yaml index d85bdd1208f9..d85bdd1208f9 100644 --- a/nixpkgs/nixos/modules/services/misc/matrix-synapse-log_config.yaml +++ b/nixpkgs/nixos/modules/services/matrix/matrix-synapse-log_config.yaml diff --git a/nixpkgs/nixos/modules/services/matrix/matrix-synapse.nix b/nixpkgs/nixos/modules/services/matrix/matrix-synapse.nix new file mode 100644 index 000000000000..c4d14dbd547e --- /dev/null +++ b/nixpkgs/nixos/modules/services/matrix/matrix-synapse.nix @@ -0,0 +1,773 @@ +{ config, lib, options, pkgs, ... }: + +with lib; + +let + cfg = config.services.matrix-synapse; + format = pkgs.formats.yaml {}; + + # remove null values from the final configuration + finalSettings = lib.filterAttrsRecursive (_: v: v != null) cfg.settings; + configFile = format.generate "homeserver.yaml" finalSettings; + logConfigFile = format.generate "log_config.yaml" cfg.logConfig; + + pluginsEnv = cfg.package.python.buildEnv.override { + extraLibs = cfg.plugins; + }; + + usePostgresql = cfg.settings.database.name == "psycopg2"; + hasLocalPostgresDB = let args = cfg.settings.database.args; in + usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ])); + + registerNewMatrixUser = + let + isIpv6 = x: lib.length (lib.splitString ":" x) > 1; + listener = + lib.findFirst ( + listener: lib.any ( + resource: lib.any ( + name: name == "client" + ) resource.names + ) listener.resources + ) (lib.last cfg.settings.listeners) cfg.settings.listeners; + # FIXME: Handle cases with missing client listener properly, + # don't rely on lib.last, this will not work. + + # add a tail, so that without any bind_addresses we still have a useable address + bindAddress = head (listener.bind_addresses ++ [ "127.0.0.1" ]); + listenerProtocol = if listener.tls + then "https" + else "http"; + in + pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" '' + exec ${cfg.package}/bin/register_new_matrix_user \ + $@ \ + ${lib.concatMapStringsSep " " (x: "-c ${x}") ([ configFile ] ++ cfg.extraConfigFiles)} \ + "${listenerProtocol}://${ + if (isIpv6 bindAddress) then + "[${bindAddress}]" + else + "${bindAddress}" + }:${builtins.toString listener.port}/" + ''; +in { + + imports = [ + + (mkRemovedOptionModule [ "services" "matrix-synapse" "trusted_third_party_id_servers" ] '' + The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0 + as the behavior is now obsolete. + '') + (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> + '') + (mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "") + (mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] '' + You may add additional event types via + `services.matrix-synapse.room_prejoin_state.additional_event_types` and + disable the default events via + `services.matrix-synapse.room_prejoin_state.disable_default_event_types`. + '') + + # options that don't exist in synapse anymore + (mkRemovedOptionModule [ "services" "matrix-synapse" "bind_host" ] "Use listener settings instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "bind_port" ] "Use listener settings instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "expire_access_tokens" ] "" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "no_tls" ] "It is no longer supported by synapse." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_dh_param_path" ] "It was removed from synapse." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "unsecure_port" ] "Use settings.listeners instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "user_creation_max_duration" ] "It is no longer supported by synapse." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "verbose" ] "Use a log config instead." ) + + # options that were moved into rfc42 style settigns + (mkRemovedOptionModule [ "services" "matrix-synapse" "app_service_config_files" ] "Use settings.app_service_config_Files instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "database_args" ] "Use settings.database.args instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "database_name" ] "Use settings.database.args.database instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "database_type" ] "Use settings.database.name instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "database_user" ] "Use settings.database.args.user instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "dynamic_thumbnails" ] "Use settings.dynamic_thumbnails instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_metrics" ] "Use settings.enable_metrics instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_registration" ] "Use settings.enable_registration instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "extraConfig" ] "Use settings instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "listeners" ] "Use settings.listeners instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "logConfig" ] "Use settings.log_config instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "max_image_pixels" ] "Use settings.max_image_pixels instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "max_upload_size" ] "Use settings.max_upload_size instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "presence" "enabled" ] "Use settings.presence.enabled instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "public_baseurl" ] "Use settings.public_baseurl instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "report_stats" ] "Use settings.report_stats instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "server_name" ] "Use settings.server_name instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "servers" ] "Use settings.trusted_key_servers instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_certificate_path" ] "Use settings.tls_certificate_path instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_private_key_path" ] "Use settings.tls_private_key_path instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_shared_secret" ] "Use settings.turn_shared_secret instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_uris" ] "Use settings.turn_uris instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_user_lifetime" ] "Use settings.turn_user_lifetime instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_enabled" ] "Use settings.url_preview_enabled instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_ip_range_blacklist" ] "Use settings.url_preview_ip_range_blacklist instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_ip_range_whitelist" ] "Use settings.url_preview_ip_range_whitelist instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_url_blacklist" ] "Use settings.url_preview_url_blacklist instead" ) + + # options that are too specific to mention them explicitly in settings + (mkRemovedOptionModule [ "services" "matrix-synapse" "account_threepid_delegates" "email" ] "Use settings.account_threepid_delegates.email instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "account_threepid_delegates" "msisdn" ] "Use settings.account_threepid_delegates.msisdn instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "allow_guest_access" ] "Use settings.allow_guest_access instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "bcrypt_rounds" ] "Use settings.bcrypt_rounds instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_registration_captcha" ] "Use settings.enable_registration_captcha instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "event_cache_size" ] "Use settings.event_cache_size instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_concurrent" ] "Use settings.rc_federation.concurrent instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_reject_limit" ] "Use settings.rc_federation.reject_limit instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_sleep_delay" ] "Use settings.rc_federation.sleep_delay instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_sleep_limit" ] "Use settings.rc_federation.sleep_limit instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_window_size" ] "Use settings.rc_federation.window_size instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "key_refresh_interval" ] "Use settings.key_refresh_interval instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "rc_messages_burst_count" ] "Use settings.rc_messages.burst_count instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "rc_messages_per_second" ] "Use settings.rc_messages.per_second instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "recaptcha_private_key" ] "Use settings.recaptcha_private_key instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "recaptcha_public_key" ] "Use settings.recaptcha_public_key instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "redaction_retention_period" ] "Use settings.redaction_retention_period instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "room_prejoin_state" "additional_event_types" ] "Use settings.room_prejoin_state.additional_event_types instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "room_prejoin_state" "disable_default_event_types" ] "Use settings.room_prejoin-state.disable_default_event_types instead" ) + + # Options that should be passed via extraConfigFiles, so they are not persisted into the nix store + (mkRemovedOptionModule [ "services" "matrix-synapse" "macaroon_secret_key" ] "Pass this value via extraConfigFiles instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "registration_shared_secret" ] "Pass this value via extraConfigFiles instead" ) + + ]; + + options = { + services.matrix-synapse = { + enable = mkEnableOption "matrix.org synapse"; + + configFile = mkOption { + type = types.str; + readOnly = true; + description = '' + Path to the configuration file on the target system. Useful to configure e.g. workers + that also need this. + ''; + }; + + package = mkOption { + type = types.package; + default = pkgs.matrix-synapse; + defaultText = literalExpression "pkgs.matrix-synapse"; + description = '' + Overridable attribute of the matrix synapse server package to use. + ''; + }; + + plugins = mkOption { + type = types.listOf types.package; + default = [ ]; + example = literalExpression '' + with config.services.matrix-synapse.package.plugins; [ + matrix-synapse-ldap3 + matrix-synapse-pam + ]; + ''; + description = '' + List of additional Matrix plugins to make available. + ''; + }; + + withJemalloc = mkOption { + type = types.bool; + default = false; + description = '' + Whether to preload jemalloc to reduce memory fragmentation and overall usage. + ''; + }; + + dataDir = mkOption { + type = types.str; + default = "/var/lib/matrix-synapse"; + description = '' + The directory where matrix-synapse stores its stateful data such as + certificates, media and uploads. + ''; + }; + + settings = mkOption { + default = {}; + description = '' + The primary synapse configuration. See the + <link xlink:href="https://github.com/matrix-org/synapse/blob/v${cfg.package.version}/docs/sample_config.yaml">sample configuration</link> + for possible values. + + Secrets should be passed in by using the <literal>extraConfigFiles</literal> option. + ''; + type = with types; submodule { + freeformType = format.type; + options = { + # This is a reduced set of popular options and defaults + # Do not add every available option here, they can be specified + # by the user at their own discretion. This is a freeform type! + + server_name = mkOption { + type = types.str; + example = "example.com"; + default = config.networking.hostName; + defaultText = literalExpression "config.networking.hostName"; + description = '' + The domain name of the server, with optional explicit port. + This is used by remote servers to look up the server address. + This is also the last part of your UserID. + + The server_name cannot be changed later so it is important to configure this correctly before you start Synapse. + ''; + }; + + enable_registration = mkOption { + type = types.bool; + default = false; + description = '' + Enable registration for new users. + ''; + }; + + registration_shared_secret = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + If set, allows registration by anyone who also has the shared + secret, even if registration is otherwise disabled. + + Secrets should be passed in via <literal>extraConfigFiles</literal>! + ''; + }; + + macaroon_secret_key = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Secret key for authentication tokens. If none is specified, + the registration_shared_secret is used, if one is given; otherwise, + a secret key is derived from the signing key. + + Secrets should be passed in via <literal>extraConfigFiles</literal>! + ''; + }; + + enable_metrics = mkOption { + type = types.bool; + default = false; + description = '' + Enable collection and rendering of performance metrics + ''; + }; + + report_stats = mkOption { + type = types.bool; + default = false; + description = '' + Whether or not to report anonymized homeserver usage statistics. + ''; + }; + + signing_key_path = mkOption { + type = types.path; + default = "${cfg.dataDir}/homeserver.signing.key"; + description = '' + Path to the signing key to sign messages with. + ''; + }; + + pid_file = mkOption { + type = types.path; + default = "/run/matrix-synapse.pid"; + readOnly = true; + description = '' + The file to store the PID in. + ''; + }; + + log_config = mkOption { + type = types.path; + default = ./matrix-synapse-log_config.yaml; + description = '' + The file that holds the logging configuration. + ''; + }; + + media_store_path = mkOption { + type = types.path; + default = if lib.versionAtLeast config.system.stateVersion "22.05" + then "${cfg.dataDir}/media_store" + else "${cfg.dataDir}/media"; + description = '' + Directory where uploaded images and attachments are stored. + ''; + }; + + public_baseurl = mkOption { + type = types.nullOr types.str; + default = null; + example = "https://example.com:8448/"; + description = '' + The public-facing base URL for the client API (not including _matrix/...) + ''; + }; + + tls_certificate_path = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/acme/example.com/fullchain.pem"; + description = '' + PEM encoded X509 certificate for TLS. + You can replace the self-signed certificate that synapse + autogenerates on launch with your own SSL certificate + key pair + if you like. Any required intermediary certificates can be + appended after the primary certificate in hierarchical order. + ''; + }; + + tls_private_key_path = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/acme/example.com/key.pem"; + description = '' + PEM encoded private key for TLS. Specify null if synapse is not + speaking TLS directly. + ''; + }; + + presence.enabled = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + Whether to enable presence tracking. + + Presence tracking allows users to see the state (e.g online/offline) + of other local and remote users. + ''; + }; + + listeners = mkOption { + type = types.listOf (types.submodule { + options = { + port = mkOption { + type = types.port; + example = 8448; + description = '' + The port to listen for HTTP(S) requests on. + ''; + }; + + bind_addresses = mkOption { + type = types.listOf types.str; + default = [ + "::1" + "127.0.0.1" + ]; + example = literalExpression '' + [ + "::" + "0.0.0.0" + ] + ''; + description = '' + IP addresses to bind the listener to. + ''; + }; + + type = mkOption { + type = types.enum [ + "http" + "manhole" + "metrics" + "replication" + ]; + default = "http"; + example = "metrics"; + description = '' + The type of the listener, usually http. + ''; + }; + + tls = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + Whether to enable TLS on the listener socket. + ''; + }; + + x_forwarded = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Use the X-Forwarded-For (XFF) header as the client IP and not the + actual client IP. + ''; + }; + + resources = mkOption { + type = types.listOf (types.submodule { + options = { + names = mkOption { + type = types.listOf (types.enum [ + "client" + "consent" + "federation" + "keys" + "media" + "metrics" + "openid" + "replication" + "static" + ]); + description = '' + List of resources to host on this listener. + ''; + example = [ + "client" + ]; + }; + compress = mkOption { + type = types.bool; + description = '' + Should synapse compress HTTP responses to clients that support it? + This should be disabled if running synapse behind a load balancer + that can do automatic compression. + ''; + }; + }; + }); + description = '' + List of HTTP resources to serve on this listener. + ''; + }; + }; + }); + default = [ { + port = 8008; + bind_addresses = [ "127.0.0.1" ]; + type = "http"; + tls = false; + x_forwarded = true; + resources = [ { + names = [ "client" ]; + compress = true; + } { + names = [ "federation" ]; + compress = false; + } ]; + } ]; + description = '' + List of ports that Synapse should listen on, their purpose and their configuration. + ''; + }; + + database.name = mkOption { + type = types.enum [ + "sqlite3" + "psycopg2" + ]; + default = if versionAtLeast config.system.stateVersion "18.03" + then "psycopg2" + else "sqlite3"; + defaultText = literalExpression '' + if versionAtLeast config.system.stateVersion "18.03" + then "psycopg2" + else "sqlite3" + ''; + description = '' + The database engine name. Can be sqlite3 or psycopg2. + ''; + }; + + database.args.database = mkOption { + type = types.str; + default = { + sqlite3 = "${cfg.dataDir}/homeserver.db"; + psycopg2 = "matrix-synapse"; + }.${cfg.settings.database.name}; + defaultText = literalExpression '' + { + sqlite3 = "''${${options.services.matrix-synapse.dataDir}}/homeserver.db"; + psycopg2 = "matrix-synapse"; + }.''${${options.services.matrix-synapse.settings}.database.name}; + ''; + description = '' + Name of the database when using the psycopg2 backend, + path to the database location when using sqlite3. + ''; + }; + + database.args.user = mkOption { + type = types.nullOr types.str; + default = { + sqlite3 = null; + psycopg2 = "matrix-synapse"; + }.${cfg.settings.database.name}; + description = '' + Username to connect with psycopg2, set to null + when using sqlite3. + ''; + }; + + url_preview_enabled = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + Is the preview URL API enabled? If enabled, you *must* specify an + explicit url_preview_ip_range_blacklist of IPs that the spider is + denied from accessing. + ''; + }; + + url_preview_ip_range_blacklist = mkOption { + type = types.listOf types.str; + default = [ + "10.0.0.0/8" + "100.64.0.0/10" + "127.0.0.0/8" + "169.254.0.0/16" + "172.16.0.0/12" + "192.0.0.0/24" + "192.0.2.0/24" + "192.168.0.0/16" + "192.88.99.0/24" + "198.18.0.0/15" + "198.51.100.0/24" + "2001:db8::/32" + "203.0.113.0/24" + "224.0.0.0/4" + "::1/128" + "fc00::/7" + "fe80::/10" + "fec0::/10" + "ff00::/8" + ]; + description = '' + List of IP address CIDR ranges that the URL preview spider is denied + from accessing. + ''; + }; + + url_preview_ip_range_whitelist = mkOption { + type = types.listOf types.str; + default = []; + description = '' + List of IP address CIDR ranges that the URL preview spider is allowed + to access even if they are specified in url_preview_ip_range_blacklist. + ''; + }; + + url_preview_url_blacklist = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Optional list of URL matches that the URL preview spider is + denied from accessing. + ''; + }; + + max_upload_size = mkOption { + type = types.str; + default = "50M"; + example = "100M"; + description = '' + The largest allowed upload size in bytes + ''; + }; + + max_image_pixels = mkOption { + type = types.str; + default = "32M"; + example = "64M"; + description = '' + Maximum number of pixels that will be thumbnailed + ''; + }; + + dynamic_thumbnails = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Whether to generate new thumbnails on the fly to precisely match + the resolution requested by the client. If true then whenever + a new resolution is requested by the client the server will + generate a new thumbnail. If false the server will pick a thumbnail + from a precalculated list. + ''; + }; + + turn_uris = mkOption { + type = types.listOf types.str; + default = []; + example = [ + "turn:turn.example.com:3487?transport=udp" + "turn:turn.example.com:3487?transport=tcp" + "turns:turn.example.com:5349?transport=udp" + "turns:turn.example.com:5349?transport=tcp" + ]; + description = '' + The public URIs of the TURN server to give to clients + ''; + }; + turn_shared_secret = mkOption { + type = types.str; + default = ""; + example = literalExpression '' + config.services.coturn.static-auth-secret + ''; + description = '' + The shared secret used to compute passwords for the TURN server. + + Secrets should be passed in via <literal>extraConfigFiles</literal>! + ''; + }; + + trusted_key_servers = mkOption { + type = types.listOf (types.submodule { + options = { + server_name = mkOption { + type = types.str; + example = "matrix.org"; + description = '' + Hostname of the trusted server. + ''; + }; + + verify_keys = mkOption { + type = types.nullOr (types.attrsOf types.str); + default = null; + example = literalExpression '' + { + "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + } + ''; + description = '' + Attribute set from key id to base64 encoded public key. + + If specified synapse will check that the response is signed + by at least one of the given keys. + ''; + }; + }; + }); + default = [ { + server_name = "matrix.org"; + verify_keys = { + "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + }; + } ]; + description = '' + The trusted servers to download signing keys from. + ''; + }; + + app_service_config_files = mkOption { + type = types.listOf types.path; + default = [ ]; + description = '' + A list of application service config file to use + ''; + }; + + }; + }; + }; + + extraConfigFiles = mkOption { + type = types.listOf types.path; + default = []; + description = '' + Extra config files to include. + + The configuration files will be included based on the command line + argument --config-path. This allows to configure secrets without + having to go through the Nix store, e.g. based on deployment keys if + NixOps is in use. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + { assertion = hasLocalPostgresDB -> config.services.postgresql.enable; + message = '' + Cannot deploy matrix-synapse with a configuration for a local postgresql database + and a missing postgresql service. Since 20.03 it's mandatory to manually configure the + database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for + further reference). + + 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> + - update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true` + to your configuration. + + For further information about this update, please read the release-notes of 20.03 carefully. + ''; + } + ]; + + services.matrix-synapse.configFile = configFile; + + users.users.matrix-synapse = { + group = "matrix-synapse"; + home = cfg.dataDir; + createHome = true; + shell = "${pkgs.bash}/bin/bash"; + uid = config.ids.uids.matrix-synapse; + }; + + users.groups.matrix-synapse = { + gid = config.ids.gids.matrix-synapse; + }; + + systemd.services.matrix-synapse = { + description = "Synapse Matrix homeserver"; + after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + ${cfg.package}/bin/synapse_homeserver \ + --config-path ${configFile} \ + --keys-directory ${cfg.dataDir} \ + --generate-keys + ''; + environment = { + PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ]; + } // optionalAttrs (cfg.withJemalloc) { + LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so"; + }; + serviceConfig = { + Type = "notify"; + User = "matrix-synapse"; + Group = "matrix-synapse"; + WorkingDirectory = cfg.dataDir; + ExecStartPre = [ ("+" + (pkgs.writeShellScript "matrix-synapse-fix-permissions" '' + chown matrix-synapse:matrix-synapse ${cfg.dataDir}/homeserver.signing.key + chmod 0600 ${cfg.dataDir}/homeserver.signing.key + '')) ]; + ExecStart = '' + ${cfg.package}/bin/synapse_homeserver \ + ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) } + --keys-directory ${cfg.dataDir} + ''; + ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; + Restart = "on-failure"; + UMask = "0077"; + }; + }; + + environment.systemPackages = [ registerNewMatrixUser ]; + }; + + meta = { + buildDocsInSandbox = false; + doc = ./matrix-synapse.xml; + maintainers = teams.matrix.members; + }; + +} diff --git a/nixpkgs/nixos/modules/services/misc/matrix-synapse.xml b/nixpkgs/nixos/modules/services/matrix/matrix-synapse.xml index 41a56df0f2b5..cdc4b4de1a73 100644 --- a/nixpkgs/nixos/modules/services/misc/matrix-synapse.xml +++ b/nixpkgs/nixos/modules/services/matrix/matrix-synapse.xml @@ -115,20 +115,21 @@ in { }; services.matrix-synapse = { <link linkend="opt-services.matrix-synapse.enable">enable</link> = true; - <link linkend="opt-services.matrix-synapse.server_name">server_name</link> = config.networking.domain; - <link linkend="opt-services.matrix-synapse.listeners">listeners</link> = [ + <link linkend="opt-services.matrix-synapse.settings.server_name">server_name</link> = config.networking.domain; + <link linkend="opt-services.matrix-synapse.settings.listeners">listeners</link> = [ { - <link linkend="opt-services.matrix-synapse.listeners._.port">port</link> = 8008; - <link linkend="opt-services.matrix-synapse.listeners._.bind_address">bind_address</link> = "::1"; - <link linkend="opt-services.matrix-synapse.listeners._.type">type</link> = "http"; - <link linkend="opt-services.matrix-synapse.listeners._.tls">tls</link> = false; - <link linkend="opt-services.matrix-synapse.listeners._.x_forwarded">x_forwarded</link> = true; - <link linkend="opt-services.matrix-synapse.listeners._.resources">resources</link> = [ - { - <link linkend="opt-services.matrix-synapse.listeners._.resources._.names">names</link> = [ "client" "federation" ]; - <link linkend="opt-services.matrix-synapse.listeners._.resources._.compress">compress</link> = false; - } - ]; + <link linkend="opt-services.matrix-synapse.settings.listeners._.port">port</link> = 8008; + <link linkend="opt-services.matrix-synapse.settings.listeners._.bind_addresses">bind_address</link> = [ "::1" ]; + <link linkend="opt-services.matrix-synapse.settings.listeners._.type">type</link> = "http"; + <link linkend="opt-services.matrix-synapse.settings.listeners._.tls">tls</link> = false; + <link linkend="opt-services.matrix-synapse.settings.listeners._.x_forwarded">x_forwarded</link> = true; + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources">resources</link> = [ { + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.names">names</link> = [ "client" ]; + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.compress">compress</link> = true; + } { + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.names">names</link> = [ "federation" ]; + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.compress">compress</link> = false; + } ]; } ]; }; @@ -151,11 +152,11 @@ in { <para> If you want to run a server with public registration by anybody, you can - then enable <literal><link linkend="opt-services.matrix-synapse.enable_registration">services.matrix-synapse.enable_registration</link> = + then enable <literal><link linkend="opt-services.matrix-synapse.settings.enable_registration">services.matrix-synapse.enable_registration</link> = true;</literal>. Otherwise, or you can generate a registration secret with <command>pwgen -s 64 1</command> and set it with - <option><link linkend="opt-services.matrix-synapse.registration_shared_secret">services.matrix-synapse.registration_shared_secret</link></option>. To - create a new user or admin, run the following after you have set the secret + <option><link linkend="opt-services.matrix-synapse.settings.registration_shared_secret">services.matrix-synapse.registration_shared_secret</link></option>. + To create a new user or admin, run the following after you have set the secret and have rebuilt NixOS: <screen> <prompt>$ </prompt>nix run nixpkgs.matrix-synapse @@ -170,7 +171,7 @@ Success! <literal>@your-username:example.org</literal>. Note that the registration secret ends up in the nix store and therefore is world-readable by any user on your machine, so it makes sense to only temporarily activate the - <link linkend="opt-services.matrix-synapse.registration_shared_secret">registration_shared_secret</link> + <link linkend="opt-services.matrix-synapse.settings.registration_shared_secret">registration_shared_secret</link> option until a better solution for NixOS is in place. </para> </section> diff --git a/nixpkgs/nixos/modules/services/misc/dendrite.nix b/nixpkgs/nixos/modules/services/misc/dendrite.nix index c967fc3a362a..b2885b094153 100644 --- a/nixpkgs/nixos/modules/services/misc/dendrite.nix +++ b/nixpkgs/nixos/modules/services/misc/dendrite.nix @@ -110,6 +110,15 @@ in ''; }; }; + options.app_service_api.database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:federationapi.db"; + description = '' + Database for the Appservice API. + ''; + }; + }; options.client_api = { registration_disabled = lib.mkOption { type = lib.types.bool; @@ -120,6 +129,91 @@ in ''; }; }; + options.federation_api.database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:federationapi.db"; + description = '' + Database for the Federation API. + ''; + }; + }; + options.key_server.database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:keyserver.db"; + description = '' + Database for the Key Server (for end-to-end encryption). + ''; + }; + }; + options.media_api = { + database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:mediaapi.db"; + description = '' + Database for the Media API. + ''; + }; + }; + base_path = lib.mkOption { + type = lib.types.str; + default = "${workingDir}/media_store"; + description = '' + Storage path for uploaded media. + ''; + }; + }; + options.room_server.database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:roomserver.db"; + description = '' + Database for the Room Server. + ''; + }; + }; + options.sync_api.database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:syncserver.db"; + description = '' + Database for the Sync API. + ''; + }; + }; + options.user_api = { + account_database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:userapi_accounts.db"; + description = '' + Database for the User API, accounts. + ''; + }; + }; + device_database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:userapi_devices.db"; + description = '' + Database for the User API, devices. + ''; + }; + }; + }; + options.mscs = { + database = { + connection_string = lib.mkOption { + type = lib.types.str; + default = "file:mscs.db"; + description = '' + Database for exerimental MSC's. + ''; + }; + }; + }; }; default = { }; description = '' diff --git a/nixpkgs/nixos/modules/services/misc/input-remapper.nix b/nixpkgs/nixos/modules/services/misc/input-remapper.nix index c2da0d616a31..f5fb2bf53086 100644 --- a/nixpkgs/nixos/modules/services/misc/input-remapper.nix +++ b/nixpkgs/nixos/modules/services/misc/input-remapper.nix @@ -7,23 +7,24 @@ let cfg = config.services.input-remapper; in options = { services.input-remapper = { enable = mkEnableOption "input-remapper, an easy to use tool to change the mapping of your input device buttons."; - package = mkOption { - type = types.package; - default = pkgs.input-remapper; - defaultText = literalExpression "pkgs.input-remapper"; - description = '' - The input-remapper package to use. - ''; + package = options.mkPackageOption pkgs "input-remapper" { }; + enableUdevRules = mkEnableOption "udev rules added by input-remapper to handle hotplugged devices. Currently disabled by default due to https://github.com/sezanzeb/input-remapper/issues/140"; + serviceWantedBy = mkOption { + default = [ "graphical.target" ]; + example = [ "multi-user.target" ]; + type = types.listOf types.str; + description = "Specifies the WantedBy setting for the input-remapper service."; }; }; }; config = mkIf cfg.enable { - # FIXME: udev rule hangs sometimes when lots of devices connected, so let's not use it - # config.services.udev.packages = mapper-pkg; - services.dbus.packages = cfg.package; - systemd.packages = cfg.package; - environment.systemPackages = cfg.package; - systemd.services.input-remapper.wantedBy = [ "graphical.target" ]; + services.udev.packages = mkIf cfg.enableUdevRules [ cfg.package ]; + services.dbus.packages = [ cfg.package ]; + systemd.packages = [ cfg.package ]; + environment.systemPackages = [ cfg.package ]; + systemd.services.input-remapper.wantedBy = cfg.serviceWantedBy; }; + + meta.maintainers = with lib.maintainers; [ LunNova ]; } diff --git a/nixpkgs/nixos/modules/services/misc/jellyfin.nix b/nixpkgs/nixos/modules/services/misc/jellyfin.nix index b9d54f27edc2..04cf82f8a46b 100644 --- a/nixpkgs/nixos/modules/services/misc/jellyfin.nix +++ b/nixpkgs/nixos/modules/services/misc/jellyfin.nix @@ -70,10 +70,12 @@ in LockPersonality = true; PrivateTmp = true; - PrivateDevices = true; + # Disabled to allow Jellyfin to access hw accel devices endpoints + # PrivateDevices = true; PrivateUsers = true; - ProtectClock = true; + # Disabled as it does not allow Jellyfin to interface with CUDA devices + # ProtectClock = true; ProtectControlGroups = true; ProtectHostname = true; ProtectKernelLogs = true; @@ -84,7 +86,7 @@ in RestrictNamespaces = true; # AF_NETLINK needed because Jellyfin monitors the network connection - RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET" "AF_INET6" ]; + RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET" "AF_INET6" "AF_UNIX" ]; RestrictRealtime = true; RestrictSUIDSGID = true; diff --git a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix deleted file mode 100644 index feca4c5465ff..000000000000 --- a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix +++ /dev/null @@ -1,844 +0,0 @@ -{ config, lib, options, pkgs, ... }: - -with lib; - -let - cfg = config.services.matrix-synapse; - opt = options.services.matrix-synapse; - pg = config.services.postgresql; - usePostgresql = cfg.database_type == "psycopg2"; - logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig; - mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${boolToString r.compress}}''; - mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${boolToString l.tls}, x_forwarded: ${boolToString l.x_forwarded}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}''; - pluginsEnv = cfg.package.python.buildEnv.override { - extraLibs = cfg.plugins; - }; - configFile = pkgs.writeText "homeserver.yaml" '' -${optionalString (cfg.tls_certificate_path != null) '' -tls_certificate_path: "${cfg.tls_certificate_path}" -''} -${optionalString (cfg.tls_private_key_path != null) '' -tls_private_key_path: "${cfg.tls_private_key_path}" -''} -${optionalString (cfg.tls_dh_params_path != null) '' -tls_dh_params_path: "${cfg.tls_dh_params_path}" -''} -no_tls: ${boolToString cfg.no_tls} -${optionalString (cfg.bind_port != null) '' -bind_port: ${toString cfg.bind_port} -''} -${optionalString (cfg.unsecure_port != null) '' -unsecure_port: ${toString cfg.unsecure_port} -''} -${optionalString (cfg.bind_host != null) '' -bind_host: "${cfg.bind_host}" -''} -server_name: "${cfg.server_name}" -pid_file: "/run/matrix-synapse.pid" -${optionalString (cfg.public_baseurl != null) '' -public_baseurl: "${cfg.public_baseurl}" -''} -listeners: [${concatStringsSep "," (map mkListener cfg.listeners)}] -database: { - name: "${cfg.database_type}", - args: { - ${concatStringsSep ",\n " ( - mapAttrsToList (n: v: "\"${n}\": ${builtins.toJSON v}") cfg.database_args - )} - } -} -event_cache_size: "${cfg.event_cache_size}" -verbose: ${cfg.verbose} -log_config: "${logConfigFile}" -rc_messages_per_second: ${cfg.rc_messages_per_second} -rc_message_burst_count: ${cfg.rc_message_burst_count} -federation_rc_window_size: ${cfg.federation_rc_window_size} -federation_rc_sleep_limit: ${cfg.federation_rc_sleep_limit} -federation_rc_sleep_delay: ${cfg.federation_rc_sleep_delay} -federation_rc_reject_limit: ${cfg.federation_rc_reject_limit} -federation_rc_concurrent: ${cfg.federation_rc_concurrent} -media_store_path: "${cfg.dataDir}/media" -uploads_path: "${cfg.dataDir}/uploads" -max_upload_size: "${cfg.max_upload_size}" -max_image_pixels: "${cfg.max_image_pixels}" -dynamic_thumbnails: ${boolToString cfg.dynamic_thumbnails} -url_preview_enabled: ${boolToString cfg.url_preview_enabled} -${optionalString (cfg.url_preview_enabled == true) '' -url_preview_ip_range_blacklist: ${builtins.toJSON cfg.url_preview_ip_range_blacklist} -url_preview_ip_range_whitelist: ${builtins.toJSON cfg.url_preview_ip_range_whitelist} -url_preview_url_blacklist: ${builtins.toJSON cfg.url_preview_url_blacklist} -''} -recaptcha_private_key: "${cfg.recaptcha_private_key}" -recaptcha_public_key: "${cfg.recaptcha_public_key}" -enable_registration_captcha: ${boolToString cfg.enable_registration_captcha} -turn_uris: ${builtins.toJSON cfg.turn_uris} -turn_shared_secret: "${cfg.turn_shared_secret}" -enable_registration: ${boolToString cfg.enable_registration} -${optionalString (cfg.registration_shared_secret != null) '' -registration_shared_secret: "${cfg.registration_shared_secret}" -''} -recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify" -turn_user_lifetime: "${cfg.turn_user_lifetime}" -user_creation_max_duration: ${cfg.user_creation_max_duration} -bcrypt_rounds: ${cfg.bcrypt_rounds} -allow_guest_access: ${boolToString cfg.allow_guest_access} - -account_threepid_delegates: - ${optionalString (cfg.account_threepid_delegates.email != null) "email: ${cfg.account_threepid_delegates.email}"} - ${optionalString (cfg.account_threepid_delegates.msisdn != null) "msisdn: ${cfg.account_threepid_delegates.msisdn}"} - -room_prejoin_state: - disable_default_event_types: ${boolToString cfg.room_prejoin_state.disable_default_event_types} - additional_event_types: ${builtins.toJSON cfg.room_prejoin_state.additional_event_types} -${optionalString (cfg.macaroon_secret_key != null) '' - macaroon_secret_key: "${cfg.macaroon_secret_key}" -''} -expire_access_token: ${boolToString cfg.expire_access_token} -enable_metrics: ${boolToString cfg.enable_metrics} -report_stats: ${boolToString cfg.report_stats} -signing_key_path: "${cfg.dataDir}/homeserver.signing.key" -key_refresh_interval: "${cfg.key_refresh_interval}" -perspectives: - servers: { - ${concatStringsSep "},\n" (mapAttrsToList (n: v: '' - "${n}": { - "verify_keys": { - ${concatStringsSep "},\n" (mapAttrsToList (n: v: '' - "${n}": { - "key": "${v}" - }'') v)} - } - '') cfg.servers)} - } - } -redaction_retention_period: ${toString cfg.redaction_retention_period} -app_service_config_files: ${builtins.toJSON cfg.app_service_config_files} - -${cfg.extraConfig} -''; - - hasLocalPostgresDB = let args = cfg.database_args; in - usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ])); - - registerNewMatrixUser = - let - isIpv6 = x: lib.length (lib.splitString ":" x) > 1; - listener = - lib.findFirst ( - listener: lib.any ( - resource: lib.any ( - name: name == "client" - ) resource.names - ) listener.resources - ) (lib.last cfg.listeners) cfg.listeners; - in - pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" '' - exec ${cfg.package}/bin/register_new_matrix_user \ - $@ \ - ${lib.concatMapStringsSep " " (x: "-c ${x}") ([ configFile ] ++ cfg.extraConfigFiles)} \ - "${listener.type}://${ - if (isIpv6 listener.bind_address) then - "[${listener.bind_address}]" - else - "${listener.bind_address}" - }:${builtins.toString listener.port}/" - ''; -in { - options = { - services.matrix-synapse = { - enable = mkEnableOption "matrix.org synapse"; - configFile = mkOption { - type = types.str; - readOnly = true; - description = '' - Path to the configuration file on the target system. Useful to configure e.g. workers - that also need this. - ''; - }; - package = mkOption { - type = types.package; - default = pkgs.matrix-synapse; - defaultText = literalExpression "pkgs.matrix-synapse"; - description = '' - Overridable attribute of the matrix synapse server package to use. - ''; - }; - plugins = mkOption { - type = types.listOf types.package; - default = [ ]; - example = literalExpression '' - with config.services.matrix-synapse.package.plugins; [ - matrix-synapse-ldap3 - matrix-synapse-pam - ]; - ''; - description = '' - List of additional Matrix plugins to make available. - ''; - }; - withJemalloc = mkOption { - type = types.bool; - default = false; - description = '' - Whether to preload jemalloc to reduce memory fragmentation and overall usage. - ''; - }; - no_tls = mkOption { - type = types.bool; - default = false; - description = '' - Don't bind to the https port - ''; - }; - bind_port = mkOption { - type = types.nullOr types.int; - default = null; - example = 8448; - description = '' - DEPRECATED: Use listeners instead. - The port to listen for HTTPS requests on. - For when matrix traffic is sent directly to synapse. - ''; - }; - unsecure_port = mkOption { - type = types.nullOr types.int; - default = null; - example = 8008; - description = '' - DEPRECATED: Use listeners instead. - The port to listen for HTTP requests on. - For when matrix traffic passes through loadbalancer that unwraps TLS. - ''; - }; - bind_host = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - DEPRECATED: Use listeners instead. - Local interface to listen on. - The empty string will cause synapse to listen on all interfaces. - ''; - }; - tls_certificate_path = mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.crt"; - description = '' - PEM encoded X509 certificate for TLS. - You can replace the self-signed certificate that synapse - autogenerates on launch with your own SSL certificate + key pair - if you like. Any required intermediary certificates can be - appended after the primary certificate in hierarchical order. - ''; - }; - tls_private_key_path = mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.key"; - description = '' - PEM encoded private key for TLS. Specify null if synapse is not - speaking TLS directly. - ''; - }; - tls_dh_params_path = mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.dh"; - description = '' - PEM dh parameters for ephemeral keys - ''; - }; - server_name = mkOption { - type = types.str; - example = "example.com"; - default = config.networking.hostName; - defaultText = literalExpression "config.networking.hostName"; - description = '' - The domain name of the server, with optional explicit port. - This is used by remote servers to look up the server address. - This is also the last part of your UserID. - - The server_name cannot be changed later so it is important to configure this correctly before you start Synapse. - ''; - }; - public_baseurl = mkOption { - type = types.nullOr types.str; - default = null; - example = "https://example.com:8448/"; - description = '' - The public-facing base URL for the client API (not including _matrix/...) - ''; - }; - listeners = mkOption { - type = types.listOf (types.submodule { - options = { - port = mkOption { - type = types.port; - example = 8448; - description = '' - The port to listen for HTTP(S) requests on. - ''; - }; - bind_address = mkOption { - type = types.str; - default = ""; - example = "203.0.113.42"; - description = '' - Local interface to listen on. - The empty string will cause synapse to listen on all interfaces. - ''; - }; - type = mkOption { - type = types.str; - default = "http"; - description = '' - Type of listener. - ''; - }; - tls = mkOption { - type = types.bool; - default = true; - description = '' - Whether to listen for HTTPS connections rather than HTTP. - ''; - }; - x_forwarded = mkOption { - type = types.bool; - default = false; - description = '' - Use the X-Forwarded-For (XFF) header as the client IP and not the - actual client IP. - ''; - }; - resources = mkOption { - type = types.listOf (types.submodule { - options = { - names = mkOption { - type = types.listOf types.str; - description = '' - List of resources to host on this listener. - ''; - example = ["client" "federation"]; - }; - compress = mkOption { - type = types.bool; - description = '' - Should synapse compress HTTP responses to clients that support it? - This should be disabled if running synapse behind a load balancer - that can do automatic compression. - ''; - }; - }; - }); - description = '' - List of HTTP resources to serve on this listener. - ''; - }; - }; - }); - default = [{ - port = 8448; - bind_address = ""; - type = "http"; - tls = true; - x_forwarded = false; - resources = [ - { names = ["client"]; compress = true; } - { names = ["federation"]; compress = false; } - ]; - }]; - description = '' - List of ports that Synapse should listen on, their purpose and their configuration. - ''; - }; - verbose = mkOption { - type = types.str; - default = "0"; - description = "Logging verbosity level."; - }; - rc_messages_per_second = mkOption { - type = types.str; - default = "0.2"; - description = "Number of messages a client can send per second"; - }; - rc_message_burst_count = mkOption { - type = types.str; - default = "10.0"; - description = "Number of message a client can send before being throttled"; - }; - federation_rc_window_size = mkOption { - type = types.str; - default = "1000"; - description = "The federation window size in milliseconds"; - }; - federation_rc_sleep_limit = mkOption { - type = types.str; - default = "10"; - description = '' - The number of federation requests from a single server in a window - before the server will delay processing the request. - ''; - }; - federation_rc_sleep_delay = mkOption { - type = types.str; - default = "500"; - description = '' - The duration in milliseconds to delay processing events from - remote servers by if they go over the sleep limit. - ''; - }; - federation_rc_reject_limit = mkOption { - type = types.str; - default = "50"; - description = '' - The maximum number of concurrent federation requests allowed - from a single server - ''; - }; - federation_rc_concurrent = mkOption { - type = types.str; - default = "3"; - description = "The number of federation requests to concurrently process from a single server"; - }; - database_type = mkOption { - type = types.enum [ "sqlite3" "psycopg2" ]; - default = if versionAtLeast config.system.stateVersion "18.03" - then "psycopg2" - else "sqlite3"; - defaultText = literalExpression '' - if versionAtLeast config.system.stateVersion "18.03" - then "psycopg2" - else "sqlite3" - ''; - description = '' - The database engine name. Can be sqlite or psycopg2. - ''; - }; - database_name = mkOption { - type = types.str; - default = "matrix-synapse"; - description = "Database name."; - }; - database_user = mkOption { - type = types.str; - default = "matrix-synapse"; - description = "Database user name."; - }; - database_args = mkOption { - type = types.attrs; - default = { - sqlite3 = { database = "${cfg.dataDir}/homeserver.db"; }; - psycopg2 = { - user = cfg.database_user; - database = cfg.database_name; - }; - }.${cfg.database_type}; - defaultText = literalDocBook '' - <variablelist> - <varlistentry> - <term>using sqlite3</term> - <listitem> - <programlisting> - { database = "''${config.${opt.dataDir}}/homeserver.db"; } - </programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term>using psycopg2</term> - <listitem> - <programlisting> - psycopg2 = { - user = config.${opt.database_user}; - database = config.${opt.database_name}; - } - </programlisting> - </listitem> - </varlistentry> - </variablelist> - ''; - description = '' - Arguments to pass to the engine. - ''; - }; - event_cache_size = mkOption { - type = types.str; - default = "10K"; - description = "Number of events to cache in memory."; - }; - url_preview_enabled = mkOption { - type = types.bool; - default = false; - description = '' - Is the preview URL API enabled? If enabled, you *must* specify an - explicit url_preview_ip_range_blacklist of IPs that the spider is - denied from accessing. - ''; - }; - url_preview_ip_range_blacklist = mkOption { - type = types.listOf types.str; - default = [ - "127.0.0.0/8" - "10.0.0.0/8" - "172.16.0.0/12" - "192.168.0.0/16" - "100.64.0.0/10" - "169.254.0.0/16" - "::1/128" - "fe80::/64" - "fc00::/7" - ]; - description = '' - List of IP address CIDR ranges that the URL preview spider is denied - from accessing. - ''; - }; - url_preview_ip_range_whitelist = mkOption { - type = types.listOf types.str; - default = []; - description = '' - List of IP address CIDR ranges that the URL preview spider is allowed - to access even if they are specified in - url_preview_ip_range_blacklist. - ''; - }; - url_preview_url_blacklist = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Optional list of URL matches that the URL preview spider is - denied from accessing. - ''; - }; - recaptcha_private_key = mkOption { - type = types.str; - default = ""; - description = '' - This Home Server's ReCAPTCHA private key. - ''; - }; - recaptcha_public_key = mkOption { - type = types.str; - default = ""; - description = '' - This Home Server's ReCAPTCHA public key. - ''; - }; - enable_registration_captcha = mkOption { - type = types.bool; - default = false; - description = '' - Enables ReCaptcha checks when registering, preventing signup - unless a captcha is answered. Requires a valid ReCaptcha - public/private key. - ''; - }; - turn_uris = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The public URIs of the TURN server to give to clients - ''; - }; - turn_shared_secret = mkOption { - type = types.str; - default = ""; - description = '' - The shared secret used to compute passwords for the TURN server - ''; - }; - turn_user_lifetime = mkOption { - type = types.str; - default = "1h"; - description = "How long generated TURN credentials last"; - }; - enable_registration = mkOption { - type = types.bool; - default = false; - description = '' - Enable registration for new users. - ''; - }; - registration_shared_secret = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - If set, allows registration by anyone who also has the shared - secret, even if registration is otherwise disabled. - ''; - }; - enable_metrics = mkOption { - type = types.bool; - default = false; - description = '' - Enable collection and rendering of performance metrics - ''; - }; - report_stats = mkOption { - type = types.bool; - default = false; - description = ""; - }; - servers = mkOption { - type = types.attrsOf (types.attrsOf types.str); - default = { - "matrix.org" = { - "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; - }; - }; - description = '' - The trusted servers to download signing keys from. - ''; - }; - max_upload_size = mkOption { - type = types.str; - default = "10M"; - description = "The largest allowed upload size in bytes"; - }; - max_image_pixels = mkOption { - type = types.str; - default = "32M"; - description = "Maximum number of pixels that will be thumbnailed"; - }; - dynamic_thumbnails = mkOption { - type = types.bool; - default = false; - description = '' - Whether to generate new thumbnails on the fly to precisely match - the resolution requested by the client. If true then whenever - a new resolution is requested by the client the server will - generate a new thumbnail. If false the server will pick a thumbnail - from a precalculated list. - ''; - }; - user_creation_max_duration = mkOption { - type = types.str; - default = "1209600000"; - description = '' - Sets the expiry for the short term user creation in - milliseconds. The default value is two weeks. - ''; - }; - bcrypt_rounds = mkOption { - type = types.str; - default = "12"; - description = '' - Set the number of bcrypt rounds used to generate password hash. - Larger numbers increase the work factor needed to generate the hash. - ''; - }; - allow_guest_access = mkOption { - type = types.bool; - default = false; - description = '' - Allows users to register as guests without a password/email/etc, and - participate in rooms hosted on this server which have been made - accessible to anonymous users. - ''; - }; - account_threepid_delegates.email = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Delegate email sending to https://example.org - ''; - }; - account_threepid_delegates.msisdn = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Delegate SMS sending to this local process (https://localhost:8090) - ''; - }; - room_prejoin_state.additional_event_types = mkOption { - default = []; - type = types.listOf types.str; - description = '' - Additional events to share with users who received an invite. - ''; - }; - room_prejoin_state.disable_default_event_types = mkOption { - default = false; - type = types.bool; - description = '' - Whether to disable the default state-event types for users invited to a room. - These are: - - <itemizedlist> - <listitem><para>m.room.join_rules</para></listitem> - <listitem><para>m.room.canonical_alias</para></listitem> - <listitem><para>m.room.avatar</para></listitem> - <listitem><para>m.room.encryption</para></listitem> - <listitem><para>m.room.name</para></listitem> - <listitem><para>m.room.create</para></listitem> - </itemizedlist> - ''; - }; - macaroon_secret_key = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Secret key for authentication tokens - ''; - }; - expire_access_token = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable access token expiration. - ''; - }; - key_refresh_interval = mkOption { - type = types.str; - default = "1d"; - description = '' - How long key response published by this server is valid for. - Used to set the valid_until_ts in /key/v2 APIs. - Determines how quickly servers will query to check which keys - are still valid. - ''; - }; - app_service_config_files = mkOption { - type = types.listOf types.path; - default = [ ]; - description = '' - A list of application service config file to use - ''; - }; - redaction_retention_period = mkOption { - type = types.int; - default = 7; - description = '' - How long to keep redacted events in unredacted form in the database. - ''; - }; - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Extra config options for matrix-synapse. - ''; - }; - extraConfigFiles = mkOption { - type = types.listOf types.path; - default = []; - description = '' - Extra config files to include. - - The configuration files will be included based on the command line - argument --config-path. This allows to configure secrets without - having to go through the Nix store, e.g. based on deployment keys if - NixOPS is in use. - ''; - }; - logConfig = mkOption { - type = types.lines; - default = readFile ./matrix-synapse-log_config.yaml; - description = '' - A yaml python logging config file - ''; - }; - dataDir = mkOption { - type = types.str; - default = "/var/lib/matrix-synapse"; - description = '' - The directory where matrix-synapse stores its stateful data such as - certificates, media and uploads. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - assertions = [ - { assertion = hasLocalPostgresDB -> config.services.postgresql.enable; - message = '' - Cannot deploy matrix-synapse with a configuration for a local postgresql database - and a missing postgresql service. Since 20.03 it's mandatory to manually configure the - database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for - further reference). - - 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> - - update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true` - to your configuration. - - For further information about this update, please read the release-notes of 20.03 carefully. - ''; - } - ]; - - services.matrix-synapse.configFile = "${configFile}"; - - users.users.matrix-synapse = { - group = "matrix-synapse"; - home = cfg.dataDir; - createHome = true; - shell = "${pkgs.bash}/bin/bash"; - uid = config.ids.uids.matrix-synapse; - }; - - users.groups.matrix-synapse = { - gid = config.ids.gids.matrix-synapse; - }; - - systemd.services.matrix-synapse = { - description = "Synapse Matrix homeserver"; - after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - ${cfg.package}/bin/synapse_homeserver \ - --config-path ${configFile} \ - --keys-directory ${cfg.dataDir} \ - --generate-keys - ''; - environment = { - PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ]; - } // optionalAttrs (cfg.withJemalloc) { - LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so"; - }; - serviceConfig = { - Type = "notify"; - User = "matrix-synapse"; - Group = "matrix-synapse"; - WorkingDirectory = cfg.dataDir; - ExecStartPre = [ ("+" + (pkgs.writeShellScript "matrix-synapse-fix-permissions" '' - chown matrix-synapse:matrix-synapse ${cfg.dataDir}/homeserver.signing.key - chmod 0600 ${cfg.dataDir}/homeserver.signing.key - '')) ]; - ExecStart = '' - ${cfg.package}/bin/synapse_homeserver \ - ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) } - --keys-directory ${cfg.dataDir} - ''; - ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; - Restart = "on-failure"; - UMask = "0077"; - }; - }; - - environment.systemPackages = [ registerNewMatrixUser ]; - }; - - imports = [ - (mkRemovedOptionModule [ "services" "matrix-synapse" "trusted_third_party_id_servers" ] '' - The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0 - as the behavior is now obsolete. - '') - (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> - '') - (mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "") - (mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] '' - You may add additional event types via - `services.matrix-synapse.room_prejoin_state.additional_event_types` and - disable the default events via - `services.matrix-synapse.room_prejoin_state.disable_default_event_types`. - '') - ]; - - meta.doc = ./matrix-synapse.xml; - meta.maintainers = teams.matrix.members; - -} diff --git a/nixpkgs/nixos/modules/services/misc/nitter.nix b/nixpkgs/nixos/modules/services/misc/nitter.nix index 6a9eeb02095c..97005c9d914f 100644 --- a/nixpkgs/nixos/modules/services/misc/nitter.nix +++ b/nixpkgs/nixos/modules/services/misc/nitter.nix @@ -49,6 +49,13 @@ in services.nitter = { enable = mkEnableOption "If enabled, start Nitter."; + package = mkOption { + default = pkgs.nitter; + type = types.package; + defaultText = literalExpression "pkgs.nitter"; + description = "The nitter derivation to use."; + }; + server = { address = mkOption { type = types.str; @@ -78,8 +85,8 @@ in staticDir = mkOption { type = types.path; - default = "${pkgs.nitter}/share/nitter/public"; - defaultText = literalExpression ''"''${pkgs.nitter}/share/nitter/public"''; + default = "${cfg.package}/share/nitter/public"; + defaultText = literalExpression ''"''${config.services.nitter.package}/share/nitter/public"''; description = "Path to the static files directory."; }; @@ -306,8 +313,8 @@ in Environment = [ "NITTER_CONF_FILE=/var/lib/nitter/nitter.conf" ]; # Some parts of Nitter expect `public` folder in working directory, # see https://github.com/zedeus/nitter/issues/414 - WorkingDirectory = "${pkgs.nitter}/share/nitter"; - ExecStart = "${pkgs.nitter}/bin/nitter"; + WorkingDirectory = "${cfg.package}/share/nitter"; + ExecStart = "${cfg.package}/bin/nitter"; ExecStartPre = "${preStart}"; AmbientCapabilities = lib.mkIf (cfg.server.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; Restart = "on-failure"; diff --git a/nixpkgs/nixos/modules/services/misc/nix-daemon.nix b/nixpkgs/nixos/modules/services/misc/nix-daemon.nix index ca59ea293783..2b21df91b82f 100644 --- a/nixpkgs/nixos/modules/services/misc/nix-daemon.nix +++ b/nixpkgs/nixos/modules/services/misc/nix-daemon.nix @@ -730,6 +730,40 @@ in }; restartTriggers = [ nixConf ]; + + # `stopIfChanged = false` changes to switch behavior + # from stop -> update units -> start + # to update units -> restart + # + # The `stopIfChanged` setting therefore controls a trade-off between a + # more predictable lifecycle, which runs the correct "version" of + # the `ExecStop` line, and on the other hand the availability of + # sockets during the switch, as the effectiveness of the stop operation + # depends on the socket being stopped as well. + # + # As `nix-daemon.service` does not make use of `ExecStop`, we prefer + # to keep the socket up and available. This is important for machines + # that run Nix-based services, such as automated build, test, and deploy + # services, that expect the daemon socket to be available at all times. + # + # Notably, the Nix client does not retry on failure to connect to the + # daemon socket, and the in-process RemoteStore instance will disable + # itself. This makes retries infeasible even for services that are + # aware of the issue. Failure to connect can affect not only new client + # processes, but also new RemoteStore instances in existing processes, + # as well as existing RemoteStore instances that have not saturated + # their connection pool. + # + # Also note that `stopIfChanged = true` does not kill existing + # connection handling daemons, as one might wish to happen before a + # breaking Nix upgrade (which is rare). The daemon forks that handle + # the individual connections split off into their own sessions, causing + # them not to be stopped by systemd. + # If a Nix upgrade does require all existing daemon processes to stop, + # nix-daemon must do so on its own accord, and only when the new version + # starts and detects that Nix's persistent state needs an upgrade. + stopIfChanged = false; + }; # Set up the environment variables for running Nix. diff --git a/nixpkgs/nixos/modules/services/misc/plex.nix b/nixpkgs/nixos/modules/services/misc/plex.nix index 7000d45975fc..1cd8da768f48 100644 --- a/nixpkgs/nixos/modules/services/misc/plex.nix +++ b/nixpkgs/nixos/modules/services/misc/plex.nix @@ -55,6 +55,19 @@ in symlinks in Plex's plugin directory will be cleared and this module will symlink all of the paths specified here to that directory. ''; + example = literalExpression '' + [ + (builtins.path { + name = "Audnexus.bundle"; + path = pkgs.fetchFromGitHub { + owner = "djdembeck"; + repo = "Audnexus.bundle"; + rev = "v0.2.8"; + sha256 = "sha256-IWOSz3vYL7zhdHan468xNc6C/eQ2C2BukQlaJNLXh7E="; + }; + }) + ] + ''; }; extraScanners = mkOption { diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix index d29d50706ef6..41302d6d3ceb 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -29,6 +29,7 @@ let "blackbox" "buildkite-agent" "collectd" + "dmarc" "dnsmasq" "domain" "dovecot" @@ -55,6 +56,7 @@ let "postfix" "postgres" "process" + "pve" "py-air-control" "redis" "rspamd" diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix new file mode 100644 index 000000000000..330610a15d9e --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix @@ -0,0 +1,117 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.dmarc; + + json = builtins.toJSON { + inherit (cfg) folders port; + listen_addr = cfg.listenAddress; + storage_path = "$STATE_DIRECTORY"; + imap = (builtins.removeAttrs cfg.imap [ "passwordFile" ]) // { password = "$IMAP_PASSWORD"; use_ssl = true; }; + poll_interval_seconds = cfg.pollIntervalSeconds; + deduplication_max_seconds = cfg.deduplicationMaxSeconds; + logging = { + version = 1; + disable_existing_loggers = false; + }; + }; +in { + port = 9797; + extraOpts = { + imap = { + host = mkOption { + type = types.str; + default = "localhost"; + description = '' + Hostname of IMAP server to connect to. + ''; + }; + port = mkOption { + type = types.port; + default = 993; + description = '' + Port of the IMAP server to connect to. + ''; + }; + username = mkOption { + type = types.str; + example = "postmaster@example.org"; + description = '' + Login username for the IMAP connection. + ''; + }; + passwordFile = mkOption { + type = types.str; + example = "/run/secrets/dovecot_pw"; + description = '' + File containing the login password for the IMAP connection. + ''; + }; + }; + folders = { + inbox = mkOption { + type = types.str; + default = "INBOX"; + description = '' + IMAP mailbox that is checked for incoming DMARC aggregate reports + ''; + }; + done = mkOption { + type = types.str; + default = "Archive"; + description = '' + IMAP mailbox that successfully processed reports are moved to. + ''; + }; + error = mkOption { + type = types.str; + default = "Invalid"; + description = '' + IMAP mailbox that emails are moved to that could not be processed. + ''; + }; + }; + pollIntervalSeconds = mkOption { + type = types.ints.unsigned; + default = 60; + description = '' + How often to poll the IMAP server in seconds. + ''; + }; + deduplicationMaxSeconds = mkOption { + type = types.ints.unsigned; + default = 604800; + defaultText = "7 days (in seconds)"; + description = '' + How long individual report IDs will be remembered to avoid + counting double delivered reports twice. + ''; + }; + debug = mkOption { + type = types.bool; + default = false; + description = '' + Whether to declare enable <literal>--debug</literal>. + ''; + }; + }; + serviceOpts = { + path = with pkgs; [ envsubst coreutils ]; + serviceConfig = { + StateDirectory = "prometheus-dmarc-exporter"; + WorkingDirectory = "/var/lib/prometheus-dmarc-exporter"; + ExecStart = "${pkgs.writeShellScript "setup-cfg" '' + export IMAP_PASSWORD="$(<${cfg.imap.passwordFile})" + envsubst \ + -i ${pkgs.writeText "dmarc-exporter.json.template" json} \ + -o ''${STATE_DIRECTORY}/dmarc-exporter.json + + exec ${pkgs.prometheus-dmarc-exporter}/bin/prometheus-dmarc-exporter \ + --configuration /var/lib/prometheus-dmarc-exporter/dmarc-exporter.json \ + ${optionalString cfg.debug "--debug"} + ''}"; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix new file mode 100644 index 000000000000..ef708414c95e --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix @@ -0,0 +1,118 @@ +{ config, lib, pkgs, options }: + +with lib; +let + cfg = config.services.prometheus.exporters.pve; + + # pve exporter requires a config file so create an empty one if configFile is not provided + emptyConfigFile = pkgs.writeTextFile { + name = "pve.yml"; + text = "default:"; + }; + + computedConfigFile = "${if cfg.configFile == null then emptyConfigFile else cfg.configFile}"; +in +{ + port = 9221; + extraOpts = { + package = mkOption { + type = types.package; + default = pkgs.prometheus-pve-exporter; + defaultText = literalExpression "pkgs.prometheus-pve-exporter"; + example = literalExpression "pkgs.prometheus-pve-exporter"; + description = '' + The package to use for prometheus-pve-exporter + ''; + }; + + environmentFile = mkOption { + type = with types; nullOr path; + default = null; + example = "/etc/prometheus-pve-exporter/pve.env"; + description = '' + Path to the service's environment file. This path can either be a computed path in /nix/store or a path in the local filesystem. + + The environment file should NOT be stored in /nix/store as it contains passwords and/or keys in plain text. + + Environment reference: https://github.com/prometheus-pve/prometheus-pve-exporter#authentication + ''; + }; + + configFile = mkOption { + type = with types; nullOr path; + default = null; + example = "/etc/prometheus-pve-exporter/pve.yml"; + description = '' + Path to the service's config file. This path can either be a computed path in /nix/store or a path in the local filesystem. + + The config file should NOT be stored in /nix/store as it will contain passwords and/or keys in plain text. + + If both configFile and environmentFile are provided, the configFile option will be ignored. + + Configuration reference: https://github.com/prometheus-pve/prometheus-pve-exporter/#authentication + ''; + }; + + collectors = { + status = mkOption { + type = types.bool; + default = true; + description = '' + Collect Node/VM/CT status + ''; + }; + version = mkOption { + type = types.bool; + default = true; + description = '' + Collect PVE version info + ''; + }; + node = mkOption { + type = types.bool; + default = true; + description = '' + Collect PVE node info + ''; + }; + cluster = mkOption { + type = types.bool; + default = true; + description = '' + Collect PVE cluster info + ''; + }; + resources = mkOption { + type = types.bool; + default = true; + description = '' + Collect PVE resources info + ''; + }; + config = mkOption { + type = types.bool; + default = true; + description = '' + Collect PVE onboot status + ''; + }; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${cfg.package}/bin/pve_exporter \ + --${if cfg.collectors.status == true then "" else "no-"}collector.status \ + --${if cfg.collectors.version == true then "" else "no-"}collector.version \ + --${if cfg.collectors.node == true then "" else "no-"}collector.node \ + --${if cfg.collectors.cluster == true then "" else "no-"}collector.cluster \ + --${if cfg.collectors.resources == true then "" else "no-"}collector.resources \ + --${if cfg.collectors.config == true then "" else "no-"}collector.config \ + ${computedConfigFile} \ + ${toString cfg.port} ${cfg.listenAddress} + ''; + } // optionalAttrs (cfg.environmentFile != null) { + EnvironmentFile = cfg.environmentFile; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix index c0a50f07d717..2edd1de83e1b 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix @@ -11,7 +11,7 @@ in { serviceConfig = { ExecStart = '' ${pkgs.prometheus-systemd-exporter}/bin/systemd_exporter \ - --web.listen-address ${cfg.listenAddress}:${toString cfg.port} + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} ${concatStringsSep " " cfg.extraFlags} ''; RestrictAddressFamilies = [ # Need AF_UNIX to collect data diff --git a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix index b311b91b4a03..17da020bf3e2 100644 --- a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix +++ b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix @@ -259,7 +259,7 @@ in ipfs --offline config Mounts.IPFS ${cfg.ipfsMountDir} ipfs --offline config Mounts.IPNS ${cfg.ipnsMountDir} '' + optionalString cfg.autoMigrate '' - ${pkgs.ipfs-migrator}/bin/fs-repo-migrations -y + ${pkgs.ipfs-migrator}/bin/fs-repo-migrations -to '${cfg.package.repoVersion}' -y '' + '' ipfs --offline config show \ | ${pkgs.jq}/bin/jq '. * $extraConfig' --argjson extraConfig ${ diff --git a/nixpkgs/nixos/modules/services/networking/amuled.nix b/nixpkgs/nixos/modules/services/networking/amuled.nix index e55ac7a6b18b..aa72a047526b 100644 --- a/nixpkgs/nixos/modules/services/networking/amuled.nix +++ b/nixpkgs/nixos/modules/services/networking/amuled.nix @@ -76,7 +76,7 @@ in script = '' ${pkgs.su}/bin/su -s ${pkgs.runtimeShell} ${user} \ - -c 'HOME="${cfg.dataDir}" ${pkgs.amuleDaemon}/bin/amuled' + -c 'HOME="${cfg.dataDir}" ${pkgs.amule-daemon}/bin/amuled' ''; }; }; diff --git a/nixpkgs/nixos/modules/services/networking/bird.nix b/nixpkgs/nixos/modules/services/networking/bird.nix index fc06cdaa6e58..3049c4f2bce9 100644 --- a/nixpkgs/nixos/modules/services/networking/bird.nix +++ b/nixpkgs/nixos/modules/services/networking/bird.nix @@ -3,103 +3,101 @@ let inherit (lib) mkEnableOption mkIf mkOption optionalString types; - generic = variant: - let - cfg = config.services.${variant}; - pkg = pkgs.${variant}; - birdBin = if variant == "bird6" then "bird6" else "bird"; - birdc = if variant == "bird6" then "birdc6" else "birdc"; - descr = - { bird = "1.6.x with IPv4 support"; - bird6 = "1.6.x with IPv6 support"; - bird2 = "2.x"; - }.${variant}; - in { - ###### interface - options = { - services.${variant} = { - enable = mkEnableOption "BIRD Internet Routing Daemon (${descr})"; - config = mkOption { - type = types.lines; - description = '' - BIRD Internet Routing Daemon configuration file. - <link xlink:href='http://bird.network.cz/'/> - ''; - }; - checkConfig = mkOption { - type = types.bool; - default = true; - description = '' - Whether the config should be checked at build time. - When the config can't be checked during build time, for example when it includes - other files, either disable this option or use <code>preCheckConfig</code> to create - the included files before checking. - ''; - }; - preCheckConfig = mkOption { - type = types.lines; - default = ""; - example = '' - echo "cost 100;" > include.conf - ''; - description = '' - Commands to execute before the config file check. The file to be checked will be - available as <code>${variant}.conf</code> in the current directory. + cfg = config.services.bird2; + caps = [ "CAP_NET_ADMIN" "CAP_NET_BIND_SERVICE" "CAP_NET_RAW" ]; +in +{ + ###### interface + options = { + services.bird2 = { + enable = mkEnableOption "BIRD Internet Routing Daemon"; + config = mkOption { + type = types.lines; + description = '' + BIRD Internet Routing Daemon configuration file. + <link xlink:href='http://bird.network.cz/'/> + ''; + }; + checkConfig = mkOption { + type = types.bool; + default = true; + description = '' + Whether the config should be checked at build time. + When the config can't be checked during build time, for example when it includes + other files, either disable this option or use <code>preCheckConfig</code> to create + the included files before checking. + ''; + }; + preCheckConfig = mkOption { + type = types.lines; + default = ""; + example = '' + echo "cost 100;" > include.conf + ''; + description = '' + Commands to execute before the config file check. The file to be checked will be + available as <code>bird2.conf</code> in the current directory. - Files created with this option will not be available at service runtime, only during - build time checking. - ''; - }; - }; + Files created with this option will not be available at service runtime, only during + build time checking. + ''; }; + }; + }; - ###### implementation - config = mkIf cfg.enable { - environment.systemPackages = [ pkg ]; - environment.etc."bird/${variant}.conf".source = pkgs.writeTextFile { - name = "${variant}.conf"; - text = cfg.config; - checkPhase = optionalString cfg.checkConfig '' - ln -s $out ${variant}.conf - ${cfg.preCheckConfig} - ${pkg}/bin/${birdBin} -d -p -c ${variant}.conf - ''; - }; + imports = [ + (lib.mkRemovedOptionModule [ "services" "bird" ] "Use services.bird2 instead") + (lib.mkRemovedOptionModule [ "services" "bird6" ] "Use services.bird2 instead") + ]; - systemd.services.${variant} = { - description = "BIRD Internet Routing Daemon (${descr})"; - wantedBy = [ "multi-user.target" ]; - reloadIfChanged = true; - restartTriggers = [ config.environment.etc."bird/${variant}.conf".source ]; - serviceConfig = { - Type = "forking"; - Restart = "on-failure"; - ExecStart = "${pkg}/bin/${birdBin} -c /etc/bird/${variant}.conf -u ${variant} -g ${variant}"; - ExecReload = "/bin/sh -c '${pkg}/bin/${birdBin} -c /etc/bird/${variant}.conf -p && ${pkg}/bin/${birdc} configure'"; - ExecStop = "${pkg}/bin/${birdc} down"; - CapabilityBoundingSet = [ "CAP_CHOWN" "CAP_FOWNER" "CAP_DAC_OVERRIDE" "CAP_SETUID" "CAP_SETGID" - # see bird/sysdep/linux/syspriv.h - "CAP_NET_BIND_SERVICE" "CAP_NET_BROADCAST" "CAP_NET_ADMIN" "CAP_NET_RAW" ]; - ProtectSystem = "full"; - ProtectHome = "yes"; - SystemCallFilter="~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io"; - MemoryDenyWriteExecute = "yes"; - }; - }; - users = { - users.${variant} = { - description = "BIRD Internet Routing Daemon user"; - group = variant; - isSystemUser = true; - }; - groups.${variant} = {}; - }; - }; - }; + ###### implementation + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.bird ]; -in + environment.etc."bird/bird2.conf".source = pkgs.writeTextFile { + name = "bird2"; + text = cfg.config; + checkPhase = optionalString cfg.checkConfig '' + ln -s $out bird2.conf + ${cfg.preCheckConfig} + ${pkgs.bird}/bin/bird -d -p -c bird2.conf + ''; + }; -{ - imports = map generic [ "bird" "bird6" "bird2" ]; + systemd.services.bird2 = { + description = "BIRD Internet Routing Daemon"; + wantedBy = [ "multi-user.target" ]; + reloadIfChanged = true; + restartTriggers = [ config.environment.etc."bird/bird2.conf".source ]; + serviceConfig = { + Type = "forking"; + Restart = "on-failure"; + User = "bird2"; + Group = "bird2"; + ExecStart = "${pkgs.bird}/bin/bird -c /etc/bird/bird2.conf"; + ExecReload = "${pkgs.bird}/bin/birdc configure"; + ExecStop = "${pkgs.bird}/bin/birdc down"; + RuntimeDirectory = "bird"; + CapabilityBoundingSet = caps; + AmbientCapabilities = caps; + ProtectSystem = "full"; + ProtectHome = "yes"; + ProtectKernelTunables = true; + ProtectControlGroups = true; + PrivateTmp = true; + PrivateDevices = true; + SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io"; + MemoryDenyWriteExecute = "yes"; + }; + }; + users = { + users.bird2 = { + description = "BIRD Internet Routing Daemon user"; + group = "bird2"; + isSystemUser = true; + }; + groups.bird2 = { }; + }; + }; } diff --git a/nixpkgs/nixos/modules/services/networking/murmur.nix b/nixpkgs/nixos/modules/services/networking/murmur.nix index 992678c43ebe..06ec04dbbf16 100644 --- a/nixpkgs/nixos/modules/services/networking/murmur.nix +++ b/nixpkgs/nixos/modules/services/networking/murmur.nix @@ -306,7 +306,7 @@ in Type = if forking then "forking" else "simple"; PIDFile = mkIf forking "/run/murmur/murmurd.pid"; EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; - ExecStart = "${cfg.package}/bin/murmurd -ini /run/murmur/murmurd.ini"; + ExecStart = "${cfg.package}/bin/mumble-server -ini /run/murmur/murmurd.ini"; Restart = "always"; RuntimeDirectory = "murmur"; RuntimeDirectoryMode = "0700"; diff --git a/nixpkgs/nixos/modules/services/networking/nbd.nix b/nixpkgs/nixos/modules/services/networking/nbd.nix new file mode 100644 index 000000000000..87f8c41a8e5c --- /dev/null +++ b/nixpkgs/nixos/modules/services/networking/nbd.nix @@ -0,0 +1,146 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.nbd; + configFormat = pkgs.formats.ini { }; + iniFields = with types; attrsOf (oneOf [ bool int float str ]); + serverConfig = configFormat.generate "nbd-server-config" + ({ + generic = + (cfg.server.extraOptions // { + user = "root"; + group = "root"; + port = cfg.server.listenPort; + } // (optionalAttrs (cfg.server.listenAddress != null) { + listenaddr = cfg.server.listenAddress; + })); + } + // (mapAttrs + (_: { path, allowAddresses, extraOptions }: + extraOptions // { + exportname = path; + } // (optionalAttrs (allowAddresses != null) { + authfile = pkgs.writeText "authfile" (concatStringsSep "\n" allowAddresses); + })) + cfg.server.exports) + ); + splitLists = + partition + (path: hasPrefix "/dev/" path) + (mapAttrsToList (_: { path, ... }: path) cfg.server.exports); + allowedDevices = splitLists.right; + boundPaths = splitLists.wrong; +in +{ + options = { + services.nbd = { + server = { + enable = mkEnableOption "the Network Block Device (nbd) server"; + + listenPort = mkOption { + type = types.port; + default = 10809; + description = "Port to listen on. The port is NOT automatically opened in the firewall."; + }; + + extraOptions = mkOption { + type = iniFields; + default = { + allowlist = false; + }; + description = '' + Extra options for the server. See + <citerefentry><refentrytitle>nbd-server</refentrytitle> + <manvolnum>5</manvolnum></citerefentry>. + ''; + }; + + exports = mkOption { + description = "Files or block devices to make available over the network."; + default = { }; + type = with types; attrsOf + (submodule { + options = { + path = mkOption { + type = str; + description = "File or block device to export."; + example = "/dev/sdb1"; + }; + + allowAddresses = mkOption { + type = nullOr (listOf str); + default = null; + example = [ "10.10.0.0/24" "127.0.0.1" ]; + description = "IPs and subnets that are authorized to connect for this device. If not specified, the server will allow all connections."; + }; + + extraOptions = mkOption { + type = iniFields; + default = { + flush = true; + fua = true; + }; + description = '' + Extra options for this export. See + <citerefentry><refentrytitle>nbd-server</refentrytitle> + <manvolnum>5</manvolnum></citerefentry>. + ''; + }; + }; + }); + }; + + listenAddress = mkOption { + type = with types; nullOr str; + description = "Address to listen on. If not specified, the server will listen on all interfaces."; + default = null; + example = "10.10.0.1"; + }; + }; + }; + }; + + config = mkIf cfg.server.enable { + boot.kernelModules = [ "nbd" ]; + + systemd.services.nbd-server = { + after = [ "network-online.target" ]; + before = [ "multi-user.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.nbd}/bin/nbd-server -C ${serverConfig}"; + Type = "forking"; + + DeviceAllow = map (path: "${path} rw") allowedDevices; + BindPaths = boundPaths; + + CapabilityBoundingSet = ""; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = false; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "noaccess"; + ProtectSystem = "strict"; + RestrictAddressFamilies = "AF_INET AF_INET6"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + UMask = "0077"; + }; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/networking/networkmanager.nix b/nixpkgs/nixos/modules/services/networking/networkmanager.nix index a9801036b00c..7a9d9e5428a7 100644 --- a/nixpkgs/nixos/modules/services/networking/networkmanager.nix +++ b/nixpkgs/nixos/modules/services/networking/networkmanager.nix @@ -556,6 +556,7 @@ in { boot.kernelModules = [ "ctr" ]; + security.polkit.enable = true; security.polkit.extraConfig = polkitConf; services.dbus.packages = cfg.packages diff --git a/nixpkgs/nixos/modules/services/networking/snowflake-proxy.nix b/nixpkgs/nixos/modules/services/networking/snowflake-proxy.nix new file mode 100644 index 000000000000..2124644ed9b5 --- /dev/null +++ b/nixpkgs/nixos/modules/services/networking/snowflake-proxy.nix @@ -0,0 +1,81 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.snowflake-proxy; +in +{ + options = { + services.snowflake-proxy = { + enable = mkEnableOption "System to defeat internet censorship"; + + broker = mkOption { + description = "Broker URL (default \"https://snowflake-broker.torproject.net/\")"; + type = with types; nullOr str; + default = null; + }; + + capacity = mkOption { + description = "Limits the amount of maximum concurrent clients allowed."; + type = with types; nullOr int; + default = null; + }; + + relay = mkOption { + description = "websocket relay URL (default \"wss://snowflake.bamsoftware.com/\")"; + type = with types; nullOr str; + default = null; + }; + + stun = mkOption { + description = "STUN broker URL (default \"stun:stun.stunprotocol.org:3478\")"; + type = with types; nullOr str; + default = null; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.snowflake-proxy = { + wantedBy = [ "network-online.target" ]; + serviceConfig = { + ExecStart = + "${pkgs.snowflake}/bin/proxy " + concatStringsSep " " ( + optional (cfg.broker != null) "-broker ${cfg.broker}" + ++ optional (cfg.capacity != null) "-capacity ${builtins.toString cfg.capacity}" + ++ optional (cfg.relay != null) "-relay ${cfg.relay}" + ++ optional (cfg.stun != null) "-stun ${cfg.stun}" + ); + + # Security Hardening + # Refer to systemd.exec(5) for option descriptions. + CapabilityBoundingSet = ""; + + # implies RemoveIPC=, PrivateTmp=, NoNewPrivileges=, RestrictSUIDSGID=, + # ProtectSystem=strict, ProtectHome=read-only + DynamicUser = true; + LockPersonality = true; + PrivateDevices = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectProc = "invisible"; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "~@clock @cpu-emulation @debug @mount @obsolete @reboot @swap @privileged @resources"; + UMask = "0077"; + }; + }; + }; + + meta.maintainers = with maintainers; [ yayayayaka ]; +} diff --git a/nixpkgs/nixos/modules/services/networking/tetrd.nix b/nixpkgs/nixos/modules/services/networking/tetrd.nix index ead73c497764..0801ce129246 100644 --- a/nixpkgs/nixos/modules/services/networking/tetrd.nix +++ b/nixpkgs/nixos/modules/services/networking/tetrd.nix @@ -1,7 +1,7 @@ { config, lib, pkgs, ... }: { - options.services.tetrd.enable = lib.mkEnableOption pkgs.tetrd.meta.description; + options.services.tetrd.enable = lib.mkEnableOption "tetrd"; config = lib.mkIf config.services.tetrd.enable { environment = { diff --git a/nixpkgs/nixos/modules/services/networking/tox-node.nix b/nixpkgs/nixos/modules/services/networking/tox-node.nix index c24e7fd12850..c6e5c2d6e819 100644 --- a/nixpkgs/nixos/modules/services/networking/tox-node.nix +++ b/nixpkgs/nixos/modules/services/networking/tox-node.nix @@ -8,12 +8,7 @@ let homeDir = "/var/lib/tox-node"; configFile = let - # fetchurl should be switched to getting this file from tox-node.src once - # the dpkg directory is in a release - src = pkgs.fetchurl { - url = "https://raw.githubusercontent.com/tox-rs/tox-node/master/dpkg/config.yml"; - sha256 = "1431wzpzm786mcvyzk1rp7ar418n45dr75hdggxvlm7pkpam31xa"; - }; + src = "${pkg.src}/dpkg/config.yml"; confJSON = pkgs.writeText "config.json" ( builtins.toJSON { log-type = cfg.logType; diff --git a/nixpkgs/nixos/modules/services/security/clamav.nix b/nixpkgs/nixos/modules/services/security/clamav.nix index 340cbbf02fb4..95a0ad8770e2 100644 --- a/nixpkgs/nixos/modules/services/security/clamav.nix +++ b/nixpkgs/nixos/modules/services/security/clamav.nix @@ -9,7 +9,7 @@ let pkg = pkgs.clamav; toKeyValue = generators.toKeyValue { - mkKeyValue = generators.mkKeyValueDefault {} " "; + mkKeyValue = generators.mkKeyValueDefault { } " "; listsAsDuplicateKeys = true; }; @@ -30,7 +30,7 @@ in settings = mkOption { type = with types; attrsOf (oneOf [ bool int str (listOf str) ]); - default = {}; + default = { }; description = '' ClamAV configuration. Refer to <link xlink:href="https://linux.die.net/man/5/clamd.conf"/>, for details on supported values. @@ -59,7 +59,7 @@ in settings = mkOption { type = with types; attrsOf (oneOf [ bool int str (listOf str) ]); - default = {}; + default = { }; description = '' freshclam configuration. Refer to <link xlink:href="https://linux.die.net/man/5/freshclam.conf"/>, for details on supported values. @@ -104,7 +104,6 @@ in systemd.services.clamav-daemon = mkIf cfg.daemon.enable { description = "ClamAV daemon (clamd)"; after = optional cfg.updater.enable "clamav-freshclam.service"; - requires = optional cfg.updater.enable "clamav-freshclam.service"; wantedBy = [ "multi-user.target" ]; restartTriggers = [ clamdConfigFile ]; @@ -134,7 +133,7 @@ in systemd.services.clamav-freshclam = mkIf cfg.updater.enable { description = "ClamAV virus database updater (freshclam)"; restartTriggers = [ freshclamConfigFile ]; - + after = [ "network-online.target" ]; preStart = '' mkdir -m 0755 -p ${stateDir} chown ${clamavUser}:${clamavGroup} ${stateDir} diff --git a/nixpkgs/nixos/modules/services/security/fprot.nix b/nixpkgs/nixos/modules/services/security/fprot.nix deleted file mode 100644 index df60d553e85b..000000000000 --- a/nixpkgs/nixos/modules/services/security/fprot.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ config, lib, pkgs, ... }: -with lib; -let - fprotUser = "fprot"; - stateDir = "/var/lib/fprot"; - fprotGroup = fprotUser; - cfg = config.services.fprot; -in { - options = { - - services.fprot = { - updater = { - enable = mkEnableOption "automatic F-Prot virus definitions database updates"; - - productData = mkOption { - description = '' - product.data file. Defaults to the one supplied with installation package. - ''; - type = types.path; - }; - - frequency = mkOption { - default = 30; - type = types.int; - description = '' - Update virus definitions every X minutes. - ''; - }; - - licenseKeyfile = mkOption { - type = types.path; - description = '' - License keyfile. Defaults to the one supplied with installation package. - ''; - }; - - }; - }; - }; - - ###### implementation - - config = mkIf cfg.updater.enable { - - services.fprot.updater.productData = mkDefault "${pkgs.fprot}/opt/f-prot/product.data"; - services.fprot.updater.licenseKeyfile = mkDefault "${pkgs.fprot}/opt/f-prot/license.key"; - - environment.systemPackages = [ pkgs.fprot ]; - environment.etc."f-prot.conf" = { - source = "${pkgs.fprot}/opt/f-prot/f-prot.conf"; - }; - - users.users.${fprotUser} = - { uid = config.ids.uids.fprot; - description = "F-Prot daemon user"; - home = stateDir; - }; - - users.groups.${fprotGroup} = - { gid = config.ids.gids.fprot; }; - - services.cron.systemCronJobs = [ "*/${toString cfg.updater.frequency} * * * * root start fprot-updater" ]; - - systemd.services.fprot-updater = { - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = false; - }; - wantedBy = [ "multi-user.target" ]; - - # have to copy fpupdate executable because it insists on storing the virus database in the same dir - preStart = '' - mkdir -m 0755 -p ${stateDir} - chown ${fprotUser}:${fprotGroup} ${stateDir} - cp ${pkgs.fprot}/opt/f-prot/fpupdate ${stateDir} - ln -sf ${cfg.updater.productData} ${stateDir}/product.data - ''; - - script = "/var/lib/fprot/fpupdate --keyfile ${cfg.updater.licenseKeyfile}"; - }; - }; -} diff --git a/nixpkgs/nixos/modules/services/security/opensnitch.nix b/nixpkgs/nixos/modules/services/security/opensnitch.nix index 919346cf2bb1..f9b4985e1991 100644 --- a/nixpkgs/nixos/modules/services/security/opensnitch.nix +++ b/nixpkgs/nixos/modules/services/security/opensnitch.nix @@ -3,22 +3,123 @@ with lib; let - name = "opensnitch"; cfg = config.services.opensnitch; + format = pkgs.formats.json {}; in { options = { services.opensnitch = { enable = mkEnableOption "Opensnitch application firewall"; + settings = mkOption { + type = types.submodule { + freeformType = format.type; + + options = { + Server = { + + Address = mkOption { + type = types.str; + description = '' + Unix socket path (unix:///tmp/osui.sock, the "unix:///" part is + mandatory) or TCP socket (192.168.1.100:50051). + ''; + }; + + LogFile = mkOption { + type = types.path; + description = '' + File to write logs to (use /dev/stdout to write logs to standard + output). + ''; + }; + + }; + + DefaultAction = mkOption { + type = types.enum [ "allow" "deny" ]; + description = '' + Default action whether to block or allow application internet + access. + ''; + }; + + DefaultDuration = mkOption { + type = types.enum [ + "once" "always" "until restart" "30s" "5m" "15m" "30m" "1h" + ]; + description = '' + Default duration of firewall rule. + ''; + }; + + InterceptUnknown = mkOption { + type = types.bool; + description = '' + Wheter to intercept spare connections. + ''; + }; + + ProcMonitorMethod = mkOption { + type = types.enum [ "ebpf" "proc" "ftrace" "audit" ]; + description = '' + Which process monitoring method to use. + ''; + }; + + LogLevel = mkOption { + type = types.enum [ 0 1 2 3 4 ]; + description = '' + Default log level from 0 to 4 (debug, info, important, warning, + error). + ''; + }; + + Firewall = mkOption { + type = types.enum [ "iptables" "nftables" ]; + description = '' + Which firewall backend to use. + ''; + }; + + Stats = { + + MaxEvents = mkOption { + type = types.int; + description = '' + Max events to send to the GUI. + ''; + }; + + MaxStats = mkOption { + type = types.int; + description = '' + Max stats per item to keep in backlog. + ''; + }; + + }; + }; + }; + description = '' + opensnitchd configuration. Refer to + <link xlink:href="https://github.com/evilsocket/opensnitch/wiki/Configurations"/> + for details on supported values. + ''; + }; }; }; config = mkIf cfg.enable { + # pkg.opensnitch is referred to elsewhere in the module so we don't need to worry about it being garbage collected + services.opensnitch.settings = mapAttrs (_: v: mkDefault v) (builtins.fromJSON (builtins.unsafeDiscardStringContext (builtins.readFile "${pkgs.opensnitch}/etc/default-config.json"))); + systemd = { packages = [ pkgs.opensnitch ]; services.opensnitchd.wantedBy = [ "multi-user.target" ]; }; + environment.etc."opensnitchd/default-config.json".source = format.generate "default-config.json" cfg.settings; + }; } diff --git a/nixpkgs/nixos/modules/services/security/step-ca.nix b/nixpkgs/nixos/modules/services/security/step-ca.nix index db7f81acd2a3..95183078d7b6 100644 --- a/nixpkgs/nixos/modules/services/security/step-ca.nix +++ b/nixpkgs/nixos/modules/services/security/step-ca.nix @@ -106,6 +106,9 @@ in ConditionFileNotEmpty = ""; # override upstream }; serviceConfig = { + User = "step-ca"; + Group = "step-ca"; + UMask = "0077"; Environment = "HOME=%S/step-ca"; WorkingDirectory = ""; # override upstream ReadWriteDirectories = ""; # override upstream @@ -127,6 +130,14 @@ in }; }; + users.users.step-ca = { + home = "/var/lib/step-ca"; + group = "step-ca"; + isSystemUser = true; + }; + + users.groups.step-ca = {}; + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; diff --git a/nixpkgs/nixos/modules/services/security/tor.nix b/nixpkgs/nixos/modules/services/security/tor.nix index cafb44e12429..3bf70c4aa4fc 100644 --- a/nixpkgs/nixos/modules/services/security/tor.nix +++ b/nixpkgs/nixos/modules/services/security/tor.nix @@ -962,7 +962,7 @@ in '') onion.authorizedClients ++ optional (onion.secretKey != null) '' install -d -o tor -g tor -m 0700 ${escapeShellArg onion.path} - key="$(cut -f1 -d: ${escapeShellArg onion.secretKey})" + key="$(cut -f1 -d: ${escapeShellArg onion.secretKey} | head -1)" case "$key" in ("== ed25519v"*"-secret") install -o tor -g tor -m 0400 ${escapeShellArg onion.secretKey} ${escapeShellArg onion.path}/hs_ed25519_secret_key;; diff --git a/nixpkgs/nixos/modules/services/security/vaultwarden/default.nix b/nixpkgs/nixos/modules/services/security/vaultwarden/default.nix index fd459f70ccde..8277f493639c 100644 --- a/nixpkgs/nixos/modules/services/security/vaultwarden/default.nix +++ b/nixpkgs/nixos/modules/services/security/vaultwarden/default.nix @@ -151,7 +151,7 @@ in { }; systemd.services.backup-vaultwarden = mkIf (cfg.backupDir != null) { - aliases = [ "backup-bitwarden_rs" ]; + aliases = [ "backup-bitwarden_rs.service" ]; description = "Backup vaultwarden"; environment = { DATA_FOLDER = "/var/lib/bitwarden_rs"; @@ -169,7 +169,7 @@ in { }; systemd.timers.backup-vaultwarden = mkIf (cfg.backupDir != null) { - aliases = [ "backup-bitwarden_rs" ]; + aliases = [ "backup-bitwarden_rs.service" ]; description = "Backup vaultwarden on time"; timerConfig = { OnCalendar = mkDefault "23:00"; diff --git a/nixpkgs/nixos/modules/services/system/earlyoom.nix b/nixpkgs/nixos/modules/services/system/earlyoom.nix index 452efc736439..ddd5bcebcdd5 100644 --- a/nixpkgs/nixos/modules/services/system/earlyoom.nix +++ b/nixpkgs/nixos/modules/services/system/earlyoom.nix @@ -1,124 +1,104 @@ { config, lib, pkgs, ... }: -with lib; - let - ecfg = config.services.earlyoom; + cfg = config.services.earlyoom; + + inherit (lib) + mkDefault mkEnableOption mkIf mkOption types + mkRemovedOptionModule + concatStringsSep optional; + in { - options = { - services.earlyoom = { - - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable early out of memory killing. - ''; - }; + options.services.earlyoom = { + enable = mkEnableOption "Early out of memory killing"; - freeMemThreshold = mkOption { - type = types.int; - default = 10; - description = '' - Minimum of availabe memory (in percent). - If the free memory falls below this threshold and the analog is true for - <option>services.earlyoom.freeSwapThreshold</option> - the killing begins. - ''; - }; + freeMemThreshold = mkOption { + type = types.ints.between 1 100; + default = 10; + description = '' + Minimum of availabe memory (in percent). + If the free memory falls below this threshold and the analog is true for + <option>services.earlyoom.freeSwapThreshold</option> + the killing begins. + ''; + }; - freeSwapThreshold = mkOption { - type = types.int; - default = 10; - description = '' - Minimum of availabe swap space (in percent). - If the available swap space falls below this threshold and the analog - is true for <option>services.earlyoom.freeMemThreshold</option> - the killing begins. - ''; - }; + freeSwapThreshold = mkOption { + type = types.ints.between 1 100; + default = 10; + description = '' + Minimum of availabe swap space (in percent). + If the available swap space falls below this threshold and the analog + is true for <option>services.earlyoom.freeMemThreshold</option> + the killing begins. + ''; + }; - useKernelOOMKiller= mkOption { - type = types.bool; - default = false; - description = '' - Use kernel OOM killer instead of own user-space implementation. - ''; - }; + # TODO: remove or warn after 1.7 (https://github.com/rfjakob/earlyoom/commit/7ebc4554) + ignoreOOMScoreAdjust = mkOption { + type = types.bool; + default = false; + description = '' + Ignore oom_score_adjust values of processes. + ''; + }; - ignoreOOMScoreAdjust = mkOption { - type = types.bool; - default = false; - description = '' - Ignore oom_score_adjust values of processes. - User-space implementation only. - ''; - }; + enableDebugInfo = mkOption { + type = types.bool; + default = false; + description = '' + Enable debugging messages. + ''; + }; - enableDebugInfo = mkOption { - type = types.bool; - default = false; - description = '' - Enable debugging messages. - ''; - }; + enableNotifications = mkOption { + type = types.bool; + default = false; + description = '' + Send notifications about killed processes via the system d-bus. - notificationsCommand = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - This option is deprecated and ignored by earlyoom since 1.6. - Use <option>services.earlyoom.enableNotifications</option> instead. - ''; - }; + WARNING: enabling this option (while convenient) should *not* be done on a + machine where you do not trust the other users as it allows any other + local user to DoS your session by spamming notifications. - enableNotifications = mkOption { - type = types.bool; - default = false; - description = '' - Send notifications about killed processes via the system d-bus. - To actually see the notifications in your GUI session, you need to have - <literal>systembus-notify</literal> running as your user. + To actually see the notifications in your GUI session, you need to have + <literal>systembus-notify</literal> running as your user which this + option handles. - See <link xlink:href="https://github.com/rfjakob/earlyoom#notifications">README</link> for details. - ''; - }; + See <link xlink:href="https://github.com/rfjakob/earlyoom#notifications">README</link> for details. + ''; }; }; - config = mkIf ecfg.enable { - assertions = [ - { assertion = ecfg.freeMemThreshold > 0 && ecfg.freeMemThreshold <= 100; - message = "Needs to be a positive percentage"; } - { assertion = ecfg.freeSwapThreshold > 0 && ecfg.freeSwapThreshold <= 100; - message = "Needs to be a positive percentage"; } - { assertion = !ecfg.useKernelOOMKiller || !ecfg.ignoreOOMScoreAdjust; - message = "Both options in conjunction do not make sense"; } - ]; + imports = [ + (mkRemovedOptionModule [ "services" "earlyoom" "useKernelOOMKiller" ] '' + This option is deprecated and ignored by earlyoom since 1.2. + '') + (mkRemovedOptionModule [ "services" "earlyoom" "notificationsCommand" ] '' + This option is deprecated and ignored by earlyoom since 1.6. + '') + ]; - warnings = optional (ecfg.notificationsCommand != null) - "`services.earlyoom.notificationsCommand` is deprecated and ignored by earlyoom since 1.6."; + config = mkIf cfg.enable { + services.systembus-notify.enable = mkDefault cfg.enableNotifications; systemd.services.earlyoom = { description = "Early OOM Daemon for Linux"; wantedBy = [ "multi-user.target" ]; - path = optional ecfg.enableNotifications pkgs.dbus; + path = optional cfg.enableNotifications pkgs.dbus; serviceConfig = { - StandardOutput = "null"; StandardError = "journal"; - ExecStart = '' - ${pkgs.earlyoom}/bin/earlyoom \ - -m ${toString ecfg.freeMemThreshold} \ - -s ${toString ecfg.freeSwapThreshold} \ - ${optionalString ecfg.useKernelOOMKiller "-k"} \ - ${optionalString ecfg.ignoreOOMScoreAdjust "-i"} \ - ${optionalString ecfg.enableDebugInfo "-d"} \ - ${optionalString ecfg.enableNotifications "-n"} - ''; + ExecStart = concatStringsSep " " ([ + "${pkgs.earlyoom}/bin/earlyoom" + "-m ${toString cfg.freeMemThreshold}" + "-s ${toString cfg.freeSwapThreshold}" + ] + ++ optional cfg.ignoreOOMScoreAdjust "-i" + ++ optional cfg.enableDebugInfo "-d" + ++ optional cfg.enableNotifications "-n" + ); }; }; - - environment.systemPackages = optional ecfg.enableNotifications pkgs.systembus-notify; }; } diff --git a/nixpkgs/nixos/modules/services/system/systembus-notify.nix b/nixpkgs/nixos/modules/services/system/systembus-notify.nix new file mode 100644 index 000000000000..e918bc552ece --- /dev/null +++ b/nixpkgs/nixos/modules/services/system/systembus-notify.nix @@ -0,0 +1,27 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.systembus-notify; + + inherit (lib) mkEnableOption mkIf; + +in +{ + options.services.systembus-notify = { + enable = mkEnableOption '' + System bus notification support + + WARNING: enabling this option (while convenient) should *not* be done on a + machine where you do not trust the other users as it allows any other + local user to DoS your session by spamming notifications. + ''; + }; + + config = mkIf cfg.enable { + systemd = { + packages = with pkgs; [ systembus-notify ]; + + user.services.systembus-notify.wantedBy = [ "graphical-session.target" ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/video/epgstation/default.nix b/nixpkgs/nixos/modules/services/video/epgstation/default.nix index 41613dcbb3ba..191f6eb52e57 100644 --- a/nixpkgs/nixos/modules/services/video/epgstation/default.nix +++ b/nixpkgs/nixos/modules/services/video/epgstation/default.nix @@ -1,30 +1,40 @@ { config, lib, options, pkgs, ... }: -with lib; - let cfg = config.services.epgstation; opt = options.services.epgstation; + description = "EPGStation: DVR system for Mirakurun-managed TV tuners"; + username = config.users.users.epgstation.name; groupname = config.users.users.epgstation.group; + mirakurun = { + sock = config.services.mirakurun.unixSocket; + option = options.services.mirakurun.unixSocket; + }; - settingsFmt = pkgs.formats.json {}; - settingsTemplate = settingsFmt.generate "config.json" cfg.settings; + yaml = pkgs.formats.yaml { }; + settingsTemplate = yaml.generate "config.yml" cfg.settings; preStartScript = pkgs.writeScript "epgstation-prestart" '' #!${pkgs.runtimeShell} - PASSWORD="$(head -n1 "${cfg.basicAuth.passwordFile}")" - DB_PASSWORD="$(head -n1 "${cfg.database.passwordFile}")" + DB_PASSWORD_FILE=${lib.escapeShellArg cfg.database.passwordFile} + + if [[ ! -f "$DB_PASSWORD_FILE" ]]; then + printf "[FATAL] File containing the DB password was not found in '%s'. Double check the NixOS option '%s'." \ + "$DB_PASSWORD_FILE" ${lib.escapeShellArg opt.database.passwordFile} >&2 + exit 1 + fi + + DB_PASSWORD="$(head -n1 ${lib.escapeShellArg cfg.database.passwordFile})" # setup configuration - touch /etc/epgstation/config.json - chmod 640 /etc/epgstation/config.json + touch /etc/epgstation/config.yml + chmod 640 /etc/epgstation/config.yml sed \ - -e "s,@password@,$PASSWORD,g" \ -e "s,@dbPassword@,$DB_PASSWORD,g" \ - ${settingsTemplate} > /etc/epgstation/config.json - chown "${username}:${groupname}" /etc/epgstation/config.json + ${settingsTemplate} > /etc/epgstation/config.yml + chown "${username}:${groupname}" /etc/epgstation/config.yml # NOTE: Use password authentication, since mysqljs does not yet support auth_socket if [ ! -e /var/lib/epgstation/db-created ]; then @@ -35,7 +45,7 @@ let ''; streamingConfig = lib.importJSON ./streaming.json; - logConfig = { + logConfig = yaml.generate "logConfig.yml" { appenders.stdout.type = "stdout"; categories = { default = { appenders = [ "stdout" ]; level = "info"; }; @@ -45,53 +55,51 @@ let }; }; - defaultPassword = "INSECURE_GO_CHECK_CONFIGURATION_NIX\n"; + # Deprecate top level options that are redundant. + deprecateTopLevelOption = config: + lib.mkRenamedOptionModule + ([ "services" "epgstation" ] ++ config) + ([ "services" "epgstation" "settings" ] ++ config); + + removeOption = config: instruction: + lib.mkRemovedOptionModule + ([ "services" "epgstation" ] ++ config) + instruction; in { - options.services.epgstation = { - enable = mkEnableOption "EPGStation: DTV Software in Japan"; + meta.maintainers = with lib.maintainers; [ midchildan ]; - usePreconfiguredStreaming = mkOption { - type = types.bool; - default = true; - description = '' - Use preconfigured default streaming options. + imports = [ + (deprecateTopLevelOption [ "port" ]) + (deprecateTopLevelOption [ "socketioPort" ]) + (deprecateTopLevelOption [ "clientSocketioPort" ]) + (removeOption [ "basicAuth" ] + "Use a TLS-terminated reverse proxy with authentication instead.") + ]; - Upstream defaults: - <link xlink:href="https://github.com/l3tnun/EPGStation/blob/master/config/config.sample.json"/> - ''; - }; + options.services.epgstation = { + enable = lib.mkEnableOption description; - port = mkOption { - type = types.port; - default = 20772; - description = '' - HTTP port for EPGStation to listen on. - ''; + package = lib.mkOption { + default = pkgs.epgstation; + type = lib.types.package; + defaultText = lib.literalExpression "pkgs.epgstation"; + description = "epgstation package to use"; }; - socketioPort = mkOption { - type = types.port; - default = cfg.port + 1; - defaultText = literalExpression "config.${opt.port} + 1"; + usePreconfiguredStreaming = lib.mkOption { + type = lib.types.bool; + default = true; description = '' - Socket.io port for EPGStation to listen on. - ''; - }; + Use preconfigured default streaming options. - clientSocketioPort = mkOption { - type = types.port; - default = cfg.socketioPort; - defaultText = literalExpression "config.${opt.socketioPort}"; - description = '' - Socket.io port that the web client is going to connect to. This may be - different from <option>socketioPort</option> if EPGStation is hidden - behind a reverse proxy. + Upstream defaults: + <link xlink:href="https://github.com/l3tnun/EPGStation/blob/master/config/config.yml.template"/> ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open ports in the firewall for the EPGStation web interface. @@ -106,50 +114,17 @@ in ''; }; - basicAuth = { - user = mkOption { - type = with types; nullOr str; - default = null; - example = "epgstation"; - description = '' - Basic auth username for EPGStation. If <literal>null</literal>, basic - auth will be disabled. - - <warning> - <para> - Basic authentication has known weaknesses, the most critical being - that it sends passwords over the network in clear text. Use this - feature to control access to EPGStation within your family and - friends, but don't rely on it for security. - </para> - </warning> - ''; - }; - - passwordFile = mkOption { - type = types.path; - default = pkgs.writeText "epgstation-password" defaultPassword; - defaultText = literalDocBook ''a file containing <literal>${defaultPassword}</literal>''; - example = "/run/keys/epgstation-password"; - description = '' - A file containing the password for <option>basicAuth.user</option>. - ''; - }; - }; - - database = { - name = mkOption { - type = types.str; + database = { + name = lib.mkOption { + type = lib.types.str; default = "epgstation"; description = '' Name of the MySQL database that holds EPGStation's data. ''; }; - passwordFile = mkOption { - type = types.path; - default = pkgs.writeText "epgstation-db-password" defaultPassword; - defaultText = literalDocBook ''a file containing <literal>${defaultPassword}</literal>''; + passwordFile = lib.mkOption { + type = lib.types.path; example = "/run/keys/epgstation-db-password"; description = '' A file containing the password for the database named @@ -158,69 +133,106 @@ in }; }; - settings = mkOption { + # The defaults for some options come from the upstream template + # configuration, which is the one that users would get if they follow the + # upstream instructions. This is, in some cases, different from the + # application defaults. Some options like encodeProcessNum and + # concurrentEncodeNum doesn't have an optimal default value that works for + # all hardware setups and/or performance requirements. For those kind of + # options, the application default wouldn't always result in the expected + # out-of-the-box behavior because it's the responsibility of the user to + # configure them according to their needs. In these cases, the value in the + # upstream template configuration should serve as a "good enough" default. + settings = lib.mkOption { description = '' - Options to add to config.json. + Options to add to config.yml. Documentation: <link xlink:href="https://github.com/l3tnun/EPGStation/blob/master/doc/conf-manual.md"/> ''; - default = {}; + default = { }; example = { recPriority = 20; conflictPriority = 10; }; - type = types.submodule { - freeformType = settingsFmt.type; + type = lib.types.submodule { + freeformType = yaml.type; + + options.port = lib.mkOption { + type = lib.types.port; + default = 20772; + description = '' + HTTP port for EPGStation to listen on. + ''; + }; - options.readOnlyOnce = mkOption { - type = types.bool; - default = false; - description = "Don't reload configuration files at runtime."; + options.socketioPort = lib.mkOption { + type = lib.types.port; + default = cfg.settings.port + 1; + defaultText = lib.literalExpression "config.${opt.settings}.port + 1"; + description = '' + Socket.io port for EPGStation to listen on. It is valid to share + ports with <option>${opt.settings}.port</option>. + ''; }; - options.mirakurunPath = mkOption (let - sockPath = config.services.mirakurun.unixSocket; - in { - type = types.str; - default = "http+unix://${replaceStrings ["/"] ["%2F"] sockPath}"; - defaultText = literalExpression '' - "http+unix://''${replaceStrings ["/"] ["%2F"] config.${options.services.mirakurun.unixSocket}}" + options.clientSocketioPort = lib.mkOption { + type = lib.types.port; + default = cfg.settings.socketioPort; + defaultText = lib.literalExpression "config.${opt.settings}.socketioPort"; + description = '' + Socket.io port that the web client is going to connect to. This may + be different from <option>${opt.settings}.socketioPort</option> if + EPGStation is hidden behind a reverse proxy. + ''; + }; + + options.mirakurunPath = with mirakurun; lib.mkOption { + type = lib.types.str; + default = "http+unix://${lib.replaceStrings ["/"] ["%2F"] sock}"; + defaultText = lib.literalExpression '' + "http+unix://''${lib.replaceStrings ["/"] ["%2F"] config.${option}}" ''; example = "http://localhost:40772"; description = "URL to connect to Mirakurun."; - }); + }; + + options.encodeProcessNum = lib.mkOption { + type = lib.types.ints.positive; + default = 4; + description = '' + The maximum number of processes that EPGStation would allow to run + at the same time for encoding or streaming videos. + ''; + }; + + options.concurrentEncodeNum = lib.mkOption { + type = lib.types.ints.positive; + default = 1; + description = '' + The maximum number of encoding jobs that EPGStation would run at the + same time. + ''; + }; - options.encode = mkOption { - type = with types; listOf attrs; + options.encode = lib.mkOption { + type = with lib.types; listOf attrs; description = "Encoding presets for recorded videos."; default = [ { - name = "H264"; - cmd = "${pkgs.epgstation}/libexec/enc.sh main"; + name = "H.264"; + cmd = "%NODE% ${cfg.package}/libexec/enc.js"; suffix = ".mp4"; - default = true; - } - { - name = "H264-sub"; - cmd = "${pkgs.epgstation}/libexec/enc.sh sub"; - suffix = "-sub.mp4"; } ]; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' [ { - name = "H264"; - cmd = "''${pkgs.epgstation}/libexec/enc.sh main"; + name = "H.264"; + cmd = "%NODE% config.${opt.package}/libexec/enc.js"; suffix = ".mp4"; - default = true; - } - { - name = "H264-sub"; - cmd = "''${pkgs.epgstation}/libexec/enc.sh sub"; - suffix = "-sub.mp4"; } ] ''; @@ -229,14 +241,25 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = !(lib.hasAttr "readOnlyOnce" cfg.settings); + message = '' + The option config.${opt.settings}.readOnlyOnce can no longer be used + since it's been removed. No replacements are available. + ''; + } + ]; + environment.etc = { - "epgstation/operatorLogConfig.json".text = builtins.toJSON logConfig; - "epgstation/serviceLogConfig.json".text = builtins.toJSON logConfig; + "epgstation/epgUpdaterLogConfig.yml".source = logConfig; + "epgstation/operatorLogConfig.yml".source = logConfig; + "epgstation/serviceLogConfig.yml".source = logConfig; }; - networking.firewall = mkIf cfg.openFirewall { - allowedTCPPorts = with cfg; [ port socketioPort ]; + networking.firewall = lib.mkIf cfg.openFirewall { + allowedTCPPorts = with cfg.settings; [ port socketioPort ]; }; users.users.epgstation = { @@ -245,13 +268,13 @@ in isSystemUser = true; }; - users.groups.epgstation = {}; + users.groups.epgstation = { }; - services.mirakurun.enable = mkDefault true; + services.mirakurun.enable = lib.mkDefault true; services.mysql = { - enable = mkDefault true; - package = mkDefault pkgs.mariadb; + enable = lib.mkDefault true; + package = lib.mkDefault pkgs.mariadb; ensureDatabases = [ cfg.database.name ]; # FIXME: enable once mysqljs supports auth_socket # ensureUsers = [ { @@ -260,39 +283,28 @@ in # } ]; }; - services.epgstation.settings = let - defaultSettings = { - serverPort = cfg.port; - socketioPort = cfg.socketioPort; - clientSocketioPort = cfg.clientSocketioPort; - - dbType = mkDefault "mysql"; - mysql = { - user = username; - database = cfg.database.name; - socketPath = mkDefault "/run/mysqld/mysqld.sock"; - password = mkDefault "@dbPassword@"; - connectTimeout = mkDefault 1000; - connectionLimit = mkDefault 10; + services.epgstation.settings = + let + defaultSettings = { + dbtype = lib.mkDefault "mysql"; + mysql = { + socketPath = lib.mkDefault "/run/mysqld/mysqld.sock"; + user = username; + password = lib.mkDefault "@dbPassword@"; + database = cfg.database.name; + }; + + ffmpeg = lib.mkDefault "${pkgs.ffmpeg-full}/bin/ffmpeg"; + ffprobe = lib.mkDefault "${pkgs.ffmpeg-full}/bin/ffprobe"; + + # for disambiguation with TypeScript files + recordedFileExtension = lib.mkDefault ".m2ts"; }; - - basicAuth = mkIf (cfg.basicAuth.user != null) { - user = mkDefault cfg.basicAuth.user; - password = mkDefault "@password@"; - }; - - ffmpeg = mkDefault "${pkgs.ffmpeg-full}/bin/ffmpeg"; - ffprobe = mkDefault "${pkgs.ffmpeg-full}/bin/ffprobe"; - - fileExtension = mkDefault ".m2ts"; - maxEncode = mkDefault 2; - maxStreaming = mkDefault 2; - }; - in - mkMerge [ - defaultSettings - (mkIf cfg.usePreconfiguredStreaming streamingConfig) - ]; + in + lib.mkMerge [ + defaultSettings + (lib.mkIf cfg.usePreconfiguredStreaming streamingConfig) + ]; systemd.tmpfiles.rules = [ "d '/var/lib/epgstation/streamfiles' - ${username} ${groupname} - -" @@ -301,15 +313,15 @@ in ]; systemd.services.epgstation = { - description = pkgs.epgstation.meta.description; + inherit description; + wantedBy = [ "multi-user.target" ]; - after = [ - "network.target" - ] ++ optional config.services.mirakurun.enable "mirakurun.service" - ++ optional config.services.mysql.enable "mysql.service"; + after = [ "network.target" ] + ++ lib.optional config.services.mirakurun.enable "mirakurun.service" + ++ lib.optional config.services.mysql.enable "mysql.service"; serviceConfig = { - ExecStart = "${pkgs.epgstation}/bin/epgstation start"; + ExecStart = "${cfg.package}/bin/epgstation start"; ExecStartPre = "+${preStartScript}"; User = username; Group = groupname; diff --git a/nixpkgs/nixos/modules/services/video/epgstation/streaming.json b/nixpkgs/nixos/modules/services/video/epgstation/streaming.json index 8eb99cf85584..7f8df0817fc3 100644 --- a/nixpkgs/nixos/modules/services/video/epgstation/streaming.json +++ b/nixpkgs/nixos/modules/services/video/epgstation/streaming.json @@ -1,119 +1,140 @@ { - "liveHLS": [ - { - "name": "720p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" + "urlscheme": { + "m2ts": { + "ios": "vlc-x-callback://x-callback-url/stream?url=PROTOCOL://ADDRESS", + "android": "intent://ADDRESS#Intent;package=org.videolan.vlc;type=video;scheme=PROTOCOL;end" }, - { - "name": "480p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" + "video": { + "ios": "infuse://x-callback-url/play?url=PROTOCOL://ADDRESS", + "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=PROTOCOL;end" }, - { - "name": "180p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 48k -ac 2 -c:v libx264 -vf yadif,scale=-2:180 -b:v 100k -preset veryfast -maxrate 110k -bufsize 1000k -flags +loop-global_header %OUTPUT%" + "download": { + "ios": "vlc-x-callback://x-callback-url/download?url=PROTOCOL://ADDRESS&filename=FILENAME" } - ], - "liveMP4": [ - { - "name": "720p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" - }, - { - "name": "480p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" - } - ], - "liveWebM": [ - { - "name": "720p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" - }, - { - "name": "480p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" - } - ], - "mpegTsStreaming": [ - { - "name": "720p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1" - }, - { - "name": "480p", - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1" - }, - { - "name": "Original" - } - ], - "mpegTsViewer": { - "ios": "vlc-x-callback://x-callback-url/stream?url=http://ADDRESS", - "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end" - }, - "recordedDownloader": { - "ios": "vlc-x-callback://x-callback-url/download?url=http://ADDRESS&filename=FILENAME", - "android": "intent://ADDRESS#Intent;package=com.dv.adm;type=video;scheme=http;end" }, - "recordedStreaming": { - "webm": [ - { - "name": "720p", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", - "vb": "3000k", - "ab": "192k" - }, - { - "name": "360p", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", - "vb": "1500k", - "ab": "128k" - } - ], - "mp4": [ - { - "name": "720p", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", - "vb": "3000k", - "ab": "192k" - }, - { - "name": "360p", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", - "vb": "1500k", - "ab": "128k" + "stream": { + "live": { + "ts": { + "m2ts": [ + { + "name": "720p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1" + }, + { + "name": "無変換" + } + ], + "m2tsll": [ + { + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1 -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1 -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1" + } + ], + "webm": [ + { + "name": "720p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" + } + ], + "mp4": [ + { + "name": "720p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" + } + ], + "hls": [ + { + "name": "720p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" + } + ] } - ], - "mpegTs": [ - { - "name": "720p (H.264)", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1", - "vb": "3000k", - "ab": "192k" + }, + "recorded": { + "ts": { + "webm": [ + { + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" + } + ], + "mp4": [ + { + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" + } + ], + "hls": [ + { + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" + } + ] }, - { - "name": "360p (H.264)", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1", - "vb": "1500k", - "ab": "128k" + "encoded": { + "webm": [ + { + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" + } + ], + "mp4": [ + { + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" + } + ], + "hls": [ + { + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf scale=-2:480 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" + } + ] } - ] - }, - "recordedHLS": [ - { - "name": "720p", - "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" - }, - { - "name": "480p", - "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" - }, - { - "name": "480p(h265)", - "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_type fmp4 -hls_fmp4_init_filename stream%streamNum%-init.mp4 -hls_segment_filename stream%streamNum%-%09d.m4s -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx265 -vf yadif,scale=-2:480 -b:v 350k -preset veryfast -tag:v hvc1 %OUTPUT%" } - ], - "recordedViewer": { - "ios": "infuse://x-callback-url/play?url=http://ADDRESS", - "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end" } } diff --git a/nixpkgs/nixos/modules/services/wayland/cage.nix b/nixpkgs/nixos/modules/services/wayland/cage.nix index d2bbc4fc057b..a32b81a916fc 100644 --- a/nixpkgs/nixos/modules/services/wayland/cage.nix +++ b/nixpkgs/nixos/modules/services/wayland/cage.nix @@ -81,6 +81,8 @@ in { }; }; + security.polkit.enable = true; + security.pam.services.cage.text = '' auth required pam_unix.so nullok account required pam_unix.so diff --git a/nixpkgs/nixos/modules/services/web-apps/keycloak.nix b/nixpkgs/nixos/modules/services/web-apps/keycloak.nix index a01f0049b2c7..22c16be76139 100644 --- a/nixpkgs/nixos/modules/services/web-apps/keycloak.nix +++ b/nixpkgs/nixos/modules/services/web-apps/keycloak.nix @@ -693,6 +693,7 @@ in RemainAfterExit = true; User = "postgres"; Group = "postgres"; + LoadCredential = [ "db_password:${cfg.database.passwordFile}" ]; }; script = '' set -o errexit -o pipefail -o nounset -o errtrace @@ -701,7 +702,8 @@ in create_role="$(mktemp)" trap 'rm -f "$create_role"' ERR EXIT - echo "CREATE ROLE keycloak WITH LOGIN PASSWORD '$(<'${cfg.database.passwordFile}')' CREATEDB" > "$create_role" + db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")" + echo "CREATE ROLE keycloak WITH LOGIN PASSWORD '$db_password' CREATEDB" > "$create_role" psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='keycloak'" | grep -q 1 || psql -tA --file="$create_role" psql -tAc "SELECT 1 FROM pg_database WHERE datname = 'keycloak'" | grep -q 1 || psql -tAc 'CREATE DATABASE "keycloak" OWNER "keycloak"' ''; @@ -717,14 +719,14 @@ in RemainAfterExit = true; User = config.services.mysql.user; Group = config.services.mysql.group; + LoadCredential = [ "db_password:${cfg.database.passwordFile}" ]; }; script = '' set -o errexit -o pipefail -o nounset -o errtrace shopt -s inherit_errexit - - db_password="$(<'${cfg.database.passwordFile}')" + db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")" ( echo "CREATE USER IF NOT EXISTS 'keycloak'@'localhost' IDENTIFIED BY '$db_password';" - echo "CREATE DATABASE keycloak CHARACTER SET utf8 COLLATE utf8_unicode_ci;" + echo "CREATE DATABASE IF NOT EXISTS keycloak CHARACTER SET utf8 COLLATE utf8_unicode_ci;" echo "GRANT ALL PRIVILEGES ON keycloak.* TO 'keycloak'@'localhost';" ) | mysql -N ''; diff --git a/nixpkgs/nixos/modules/services/web-apps/peertube.nix b/nixpkgs/nixos/modules/services/web-apps/peertube.nix index a65428018260..e195e6e6e824 100644 --- a/nixpkgs/nixos/modules/services/web-apps/peertube.nix +++ b/nixpkgs/nixos/modules/services/web-apps/peertube.nix @@ -320,6 +320,7 @@ in { }; storage = { tmp = lib.mkDefault "/var/lib/peertube/storage/tmp/"; + bin = lib.mkDefault "/var/lib/peertube/storage/bin/"; avatars = lib.mkDefault "/var/lib/peertube/storage/avatars/"; videos = lib.mkDefault "/var/lib/peertube/storage/videos/"; streaming_playlists = lib.mkDefault "/var/lib/peertube/storage/streaming-playlists/"; @@ -333,6 +334,15 @@ in { plugins = lib.mkDefault "/var/lib/peertube/storage/plugins/"; client_overrides = lib.mkDefault "/var/lib/peertube/storage/client-overrides/"; }; + import = { + videos = { + http = { + youtube_dl_release = { + python_path = "${pkgs.python3}/bin/python"; + }; + }; + }; + }; } (lib.mkIf cfg.redis.enableUnixSocket { redis = { socket = "/run/redis/redis.sock"; }; }) ]; @@ -380,7 +390,7 @@ in { environment = env; - path = with pkgs; [ bashInteractive ffmpeg nodejs-16_x openssl yarn youtube-dl ]; + path = with pkgs; [ bashInteractive ffmpeg nodejs-16_x openssl yarn python3 ]; script = '' #!/bin/sh diff --git a/nixpkgs/nixos/modules/services/web-apps/plantuml-server.nix b/nixpkgs/nixos/modules/services/web-apps/plantuml-server.nix index f4bf43f56b98..9ea37b8a4cad 100644 --- a/nixpkgs/nixos/modules/services/web-apps/plantuml-server.nix +++ b/nixpkgs/nixos/modules/services/web-apps/plantuml-server.nix @@ -20,6 +20,21 @@ in description = "PlantUML server package to use"; }; + packages = { + jdk = mkOption { + type = types.package; + default = pkgs.jdk; + defaultText = literalExpression "pkgs.jdk"; + description = "JDK package to use for the server"; + }; + jetty = mkOption { + type = types.package; + default = pkgs.jetty; + defaultText = literalExpression "pkgs.jetty"; + description = "Jetty package to use for the server"; + }; + }; + user = mkOption { type = types.str; default = "plantuml"; @@ -105,10 +120,10 @@ in ALLOW_PLANTUML_INCLUDE = if cfg.allowPlantumlInclude then "true" else "false"; }; script = '' - ${pkgs.jre}/bin/java \ - -jar ${pkgs.jetty}/start.jar \ + ${cfg.packages.jdk}/bin/java \ + -jar ${cfg.packages.jetty}/start.jar \ --module=deploy,http,jsp \ - jetty.home=${pkgs.jetty} \ + jetty.home=${cfg.packages.jetty} \ jetty.base=${cfg.package} \ jetty.http.host=${cfg.listenHost} \ jetty.http.port=${builtins.toString cfg.listenPort} diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix index 6876dbf39d84..e046c28dd6bb 100644 --- a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix @@ -924,7 +924,8 @@ in PrivateMounts = true; # System Call Filtering SystemCallArchitectures = "native"; - SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid" ] ++ optionals (cfg.package != pkgs.tengine) [ "~@ipc" ]; + SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid" ] + ++ optionals ((cfg.package != pkgs.tengine) && (!lib.any (mod: (mod.disableIPC or false)) cfg.package.modules)) [ "~@ipc" ]; }; }; @@ -988,5 +989,17 @@ in nginx.gid = config.ids.gids.nginx; }; + services.logrotate.paths.nginx = mapAttrs (_: mkDefault) { + path = "/var/log/nginx/*.log"; + frequency = "weekly"; + keep = 26; + extraConfig = '' + compress + delaycompress + postrotate + [ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid` + endscript + ''; + }; }; } diff --git a/nixpkgs/nixos/modules/services/web-servers/pomerium.nix b/nixpkgs/nixos/modules/services/web-servers/pomerium.nix index 2bc7d01c7c28..0b460755f50e 100644 --- a/nixpkgs/nixos/modules/services/web-servers/pomerium.nix +++ b/nixpkgs/nixos/modules/services/web-servers/pomerium.nix @@ -69,11 +69,16 @@ in CERTIFICATE_KEY_FILE = "key.pem"; }; startLimitIntervalSec = 60; + script = '' + if [[ -v CREDENTIALS_DIRECTORY ]]; then + cd "$CREDENTIALS_DIRECTORY" + fi + exec "${pkgs.pomerium}/bin/pomerium" -config "${cfgFile}" + ''; serviceConfig = { DynamicUser = true; StateDirectory = [ "pomerium" ]; - ExecStart = "${pkgs.pomerium}/bin/pomerium -config ${cfgFile}"; PrivateUsers = false; # breaks CAP_NET_BIND_SERVICE MemoryDenyWriteExecute = false; # breaks LuaJIT @@ -99,7 +104,6 @@ in AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; - WorkingDirectory = mkIf (cfg.useACMEHost != null) "$CREDENTIALS_DIRECTORY"; LoadCredential = optionals (cfg.useACMEHost != null) [ "fullchain.pem:/var/lib/acme/${cfg.useACMEHost}/fullchain.pem" "key.pem:/var/lib/acme/${cfg.useACMEHost}/key.pem" @@ -124,7 +128,7 @@ in Type = "oneshot"; TimeoutSec = 60; ExecCondition = "/run/current-system/systemd/bin/systemctl -q is-active pomerium.service"; - ExecStart = "/run/current-system/systemd/bin/systemctl restart pomerium.service"; + ExecStart = "/run/current-system/systemd/bin/systemctl --no-block restart pomerium.service"; }; }; }); diff --git a/nixpkgs/nixos/modules/services/web-servers/tomcat.nix b/nixpkgs/nixos/modules/services/web-servers/tomcat.nix index f9446fe125a3..877097cf3781 100644 --- a/nixpkgs/nixos/modules/services/web-servers/tomcat.nix +++ b/nixpkgs/nixos/modules/services/web-servers/tomcat.nix @@ -23,8 +23,8 @@ in package = mkOption { type = types.package; - default = pkgs.tomcat85; - defaultText = literalExpression "pkgs.tomcat85"; + default = pkgs.tomcat9; + defaultText = literalExpression "pkgs.tomcat9"; example = lib.literalExpression "pkgs.tomcat9"; description = '' Which tomcat package to use. @@ -127,7 +127,7 @@ in webapps = mkOption { type = types.listOf types.path; default = [ tomcat.webapps ]; - defaultText = literalExpression "[ pkgs.tomcat85.webapps ]"; + defaultText = literalExpression "[ config.services.tomcat.package.webapps ]"; description = "List containing WAR files or directories with WAR files which are web applications to be deployed on Tomcat"; }; @@ -201,6 +201,7 @@ in { uid = config.ids.uids.tomcat; description = "Tomcat user"; home = "/homeless-shelter"; + group = "tomcat"; extraGroups = cfg.extraGroups; }; diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix index f8f47a061452..a7fda4be9796 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix @@ -74,11 +74,9 @@ in # Debugging environment.sessionVariables.MATE_SESSION_DEBUG = mkIf cfg.debug "1"; - environment.systemPackages = - pkgs.mate.basePackages ++ - (pkgs.gnome.removePackagesByName - pkgs.mate.extraPackages - config.environment.mate.excludePackages) ++ + environment.systemPackages = pkgs.gnome.removePackagesByName + (pkgs.mate.basePackages ++ + pkgs.mate.extraPackages ++ [ pkgs.desktop-file-utils pkgs.glib @@ -87,7 +85,8 @@ in pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/ pkgs.mate.mate-settings-daemon pkgs.yelp # for 'Contents' in 'Help' menus - ]; + ]) + config.environment.mate.excludePackages; programs.dconf.enable = true; # Shell integration for VTE terminals diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix index 6a7d2a8aa6cd..8ff9b0b756d3 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix @@ -227,6 +227,7 @@ in # Settings from elementary-default-settings environment.etc."gtk-3.0/settings.ini".source = "${pkgs.pantheon.elementary-default-settings}/etc/gtk-3.0/settings.ini"; + xdg.portal.enable = true; xdg.portal.extraPortals = with pkgs.pantheon; [ elementary-files elementary-settings-daemon diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix index 84b75c83aeab..27dfed3cc14c 100644 --- a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix @@ -267,6 +267,8 @@ in # Enable the accounts daemon to find lightdm's dbus interface environment.systemPackages = [ lightdm ]; + security.polkit.enable = true; + security.pam.services.lightdm.text = '' auth substack login account include login diff --git a/nixpkgs/nixos/modules/services/x11/xserver.nix b/nixpkgs/nixos/modules/services/x11/xserver.nix index ec6d86d59bdf..0c50d82b23be 100644 --- a/nixpkgs/nixos/modules/services/x11/xserver.nix +++ b/nixpkgs/nixos/modules/services/x11/xserver.nix @@ -620,9 +620,6 @@ in in optional (driver != null) ({ inherit name; modules = []; driverName = name; display = true; } // driver)); assertions = [ - { assertion = config.security.polkit.enable; - message = "X11 requires Polkit to be enabled (‘security.polkit.enable = true’)."; - } (let primaryHeads = filter (x: x.primary) cfg.xrandrHeads; in { assertion = length primaryHeads < 2; message = "Only one head is allowed to be primary in " diff --git a/nixpkgs/nixos/modules/system/activation/switch-to-configuration.pl b/nixpkgs/nixos/modules/system/activation/switch-to-configuration.pl index a8fe14c58f05..459d09faa53b 100644..100755 --- a/nixpkgs/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixpkgs/nixos/modules/system/activation/switch-to-configuration.pl @@ -10,6 +10,8 @@ use Net::DBus; use Sys::Syslog qw(:standard :macros); use Cwd 'abs_path'; +## no critic(CodeLayout::ProhibitParensWithBuiltins) + my $out = "@out@"; my $curSystemd = abs_path("/run/current-system/sw/bin"); @@ -36,13 +38,13 @@ my $dryReloadByActivationFile = "/run/nixos/dry-activation-reload-list"; make_path("/run/nixos", { mode => oct(755) }); -my $action = shift @ARGV; +my $action = shift(@ARGV); if ("@localeArchive@" ne "") { $ENV{LOCALE_ARCHIVE} = "@localeArchive@"; } -if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test" && $action ne "dry-activate")) { +if (!defined($action) || ($action ne "switch" && $action ne "boot" && $action ne "test" && $action ne "dry-activate")) { print STDERR <<EOF; Usage: $0 [switch|boot|test] @@ -51,27 +53,30 @@ boot: make the configuration the boot default test: activate the configuration, but don\'t make it the boot default dry-activate: show what would be done if this configuration were activated EOF - exit 1; + exit(1); } $ENV{NIXOS_ACTION} = $action; # This is a NixOS installation if it has /etc/NIXOS or a proper # /etc/os-release. -die "This is not a NixOS installation!\n" unless - -f "/etc/NIXOS" || (read_file("/etc/os-release", err_mode => 'quiet') // "") =~ /ID=nixos/s; +die("This is not a NixOS installation!\n") unless + -f "/etc/NIXOS" || (read_file("/etc/os-release", err_mode => 'quiet') // "") =~ /ID="?nixos"?/s; openlog("nixos", "", LOG_USER); # Install or update the bootloader. if ($action eq "switch" || $action eq "boot") { - system("@installBootLoader@ $out") == 0 or exit 1; + chomp(my $installBootLoader = <<'EOFBOOTLOADER'); +@installBootLoader@ +EOFBOOTLOADER + system("$installBootLoader $out") == 0 or exit 1; } # Just in case the new configuration hangs the system, do a sync now. system("@coreutils@/bin/sync", "-f", "/nix/store") unless ($ENV{"NIXOS_NO_SYNC"} // "") eq "1"; -exit 0 if $action eq "boot"; +exit(0) if $action eq "boot"; # Check if we can activate the new configuration. my $oldVersion = read_file("/run/current-system/init-interface-version", err_mode => 'quiet') // ""; @@ -83,7 +88,7 @@ Warning: the new NixOS configuration has an ‘init’ that is incompatible with the current configuration. The new configuration won\'t take effect until you reboot the system. EOF - exit 100; + exit(100); } # Ignore SIGHUP so that we're not killed if we're running on (say) @@ -104,14 +109,27 @@ sub getActiveUnits { return $res; } +# Returns whether a systemd unit is active +sub unit_is_active { + my ($unit_name) = @_; + + my $mgr = Net::DBus->system->get_service('org.freedesktop.systemd1')->get_object('/org/freedesktop/systemd1'); + my $units = $mgr->ListUnitsByNames([$unit_name]); + if (scalar(@{$units}) == 0) { + return 0; + } + my $active_state = $units->[0]->[3]; ## no critic (ValuesAndExpressions::ProhibitMagicNumbers) + return $active_state eq 'active' || $active_state eq 'activating'; +} + sub parseFstab { my ($filename) = @_; my ($fss, $swaps); foreach my $line (read_file($filename, err_mode => 'quiet')) { - chomp $line; + chomp($line); $line =~ s/^\s*#.*//; next if $line =~ /^\s*$/; - my @xs = split / /, $line; + my @xs = split(/ /, $line); if ($xs[2] eq "swap") { $swaps->{$xs[0]} = { options => $xs[3] // "" }; } else { @@ -133,17 +151,16 @@ sub parseFstab { sub parseSystemdIni { my ($unitContents, $path) = @_; # Tie the ini file to a hash for easier access - my %fileContents; - tie %fileContents, "Config::IniFiles", (-file => $path, -allowempty => 1, -allowcontinue => 1); + tie(my %fileContents, 'Config::IniFiles', (-file => $path, -allowempty => 1, -allowcontinue => 1)); ## no critic(Miscellanea::ProhibitTies) # Copy over all sections - foreach my $sectionName (keys %fileContents) { + foreach my $sectionName (keys(%fileContents)) { if ($sectionName eq "Install") { # Skip the [Install] section because it has no relevant keys for us next; } # Copy over all keys - foreach my $iniKey (keys %{$fileContents{$sectionName}}) { + foreach my $iniKey (keys(%{$fileContents{$sectionName}})) { # Ensure the value is an array so it's easier to work with my $iniValue = $fileContents{$sectionName}{$iniKey}; my @iniValues; @@ -181,7 +198,7 @@ sub parse_unit { # Replace \ with \\ so glob() still works with units that have a \ in them # Valid characters in unit names are ASCII letters, digits, ":", "-", "_", ".", and "\" $unit_path =~ s/\\/\\\\/gmsx; - foreach (glob "${unit_path}{,.d/*.conf}") { + foreach (glob("${unit_path}{,.d/*.conf}")) { parseSystemdIni(\%unit_data, "$_") } return %unit_data; @@ -194,7 +211,7 @@ sub parseSystemdBool { my @values = @{$unitConfig->{$sectionName}{$boolName} // []}; # Return default if value is not set - if (scalar @values lt 1 || not defined $values[-1]) { + if (scalar(@values) lt 1 || not defined($values[-1])) { return $default; } # If value is defined multiple times, use the last definition @@ -211,7 +228,7 @@ sub recordUnit { # The opposite of recordUnit, removes a unit name from a file sub unrecord_unit { my ($fn, $unit) = @_; - edit_file { s/^$unit\n//msx } $fn if $action ne "dry-activate"; + edit_file(sub { s/^$unit\n//msx }, $fn) if $action ne "dry-activate"; } # Compare the contents of two unit files and return whether the unit @@ -226,6 +243,16 @@ sub unrecord_unit { sub compare_units { my ($old_unit, $new_unit) = @_; my $ret = 0; + # Keys to ignore in the [Unit] section + my %unit_section_ignores = map { $_ => 1 } qw( + X-Reload-Triggers + Description Documentation + OnFailure OnSuccess OnFailureJobMode + IgnoreOnIsolate StopWhenUnneeded + RefuseManualStart RefuseManualStop + AllowIsolate CollectMode + SourcePath + ); my $comp_array = sub { my ($a, $b) = @_; @@ -233,11 +260,23 @@ sub compare_units { }; # Comparison hash for the sections - my %section_cmp = map { $_ => 1 } keys %{$new_unit}; + my %section_cmp = map { $_ => 1 } keys(%{$new_unit}); # Iterate over the sections - foreach my $section_name (keys %{$old_unit}) { + foreach my $section_name (keys(%{$old_unit})) { # Missing section in the new unit? - if (not exists $section_cmp{$section_name}) { + if (not exists($section_cmp{$section_name})) { + # If the [Unit] section was removed, make sure that only keys + # were in it that are ignored + if ($section_name eq 'Unit') { + foreach my $ini_key (keys(%{$old_unit->{'Unit'}})) { + if (not defined($unit_section_ignores{$ini_key})) { + return 1; + } + } + next; # check the next section + } else { + return 1; + } if ($section_name eq 'Unit' and %{$old_unit->{'Unit'}} == 1 and defined(%{$old_unit->{'Unit'}}{'X-Reload-Triggers'})) { # If a new [Unit] section was removed that only contained X-Reload-Triggers, # do nothing. @@ -248,15 +287,15 @@ sub compare_units { } delete $section_cmp{$section_name}; # Comparison hash for the section contents - my %ini_cmp = map { $_ => 1 } keys %{$new_unit->{$section_name}}; + my %ini_cmp = map { $_ => 1 } keys(%{$new_unit->{$section_name}}); # Iterate over the keys of the section - foreach my $ini_key (keys %{$old_unit->{$section_name}}) { + foreach my $ini_key (keys(%{$old_unit->{$section_name}})) { delete $ini_cmp{$ini_key}; my @old_value = @{$old_unit->{$section_name}{$ini_key}}; # If the key is missing in the new unit, they are different... if (not $new_unit->{$section_name}{$ini_key}) { - # ... unless the key that is now missing was the reload trigger - if ($section_name eq 'Unit' and $ini_key eq 'X-Reload-Triggers') { + # ... unless the key that is now missing is one of the ignored keys + if ($section_name eq 'Unit' and defined($unit_section_ignores{$ini_key})) { next; } return 1; @@ -264,19 +303,30 @@ sub compare_units { my @new_value = @{$new_unit->{$section_name}{$ini_key}}; # If the contents are different, the units are different if (not $comp_array->(\@old_value, \@new_value)) { - # Check if only the reload triggers changed - if ($section_name eq 'Unit' and $ini_key eq 'X-Reload-Triggers') { - $ret = 2; - } else { - return 1; + # Check if only the reload triggers changed or one of the ignored keys + if ($section_name eq 'Unit') { + if ($ini_key eq 'X-Reload-Triggers') { + $ret = 2; + next; + } elsif (defined($unit_section_ignores{$ini_key})) { + next; + } } + return 1; } } # A key was introduced that was missing in the old unit if (%ini_cmp) { - if ($section_name eq 'Unit' and %ini_cmp == 1 and defined($ini_cmp{'X-Reload-Triggers'})) { - # If the newly introduced key was the reload triggers, reload the unit - $ret = 2; + if ($section_name eq 'Unit') { + foreach my $ini_key (keys(%ini_cmp)) { + if ($ini_key eq 'X-Reload-Triggers') { + $ret = 2; + } elsif (defined($unit_section_ignores{$ini_key})) { + next; + } else { + return 1; + } + } } else { return 1; } @@ -284,10 +334,14 @@ sub compare_units { } # A section was introduced that was missing in the old unit if (%section_cmp) { - if (%section_cmp == 1 and defined($section_cmp{'Unit'}) and %{$new_unit->{'Unit'}} == 1 and defined(%{$new_unit->{'Unit'}}{'X-Reload-Triggers'})) { - # If a new [Unit] section was introduced that only contains X-Reload-Triggers, - # reload instead of restarting - $ret = 2; + if (%section_cmp == 1 and defined($section_cmp{'Unit'})) { + foreach my $ini_key (keys(%{$new_unit->{'Unit'}})) { + if (not defined($unit_section_ignores{$ini_key})) { + return 1; + } elsif ($ini_key eq 'X-Reload-Triggers') { + $ret = 2; + } + } } else { return 1; } @@ -307,6 +361,7 @@ sub handleModifiedUnit { # seem to get applied on daemon-reload. } elsif ($unit =~ /\.mount$/) { # Reload the changed mount unit to force a remount. + # FIXME: only reload when Options= changed, restart otherwise $unitsToReload->{$unit} = 1; recordUnit($reloadListFile, $unit); } elsif ($unit =~ /\.socket$/) { @@ -339,21 +394,27 @@ sub handleModifiedUnit { # If this unit is socket-activated, then stop the # socket unit(s) as well, and restart the # socket(s) instead of the service. - my $socketActivated = 0; + my $socket_activated = 0; if ($unit =~ /\.service$/) { my @sockets = split(/ /, join(" ", @{$unitInfo{Service}{Sockets} // []})); - if (scalar @sockets == 0) { + if (scalar(@sockets) == 0) { @sockets = ("$baseName.socket"); } foreach my $socket (@sockets) { - if (defined $activePrev->{$socket}) { + if (defined($activePrev->{$socket})) { + # We can now be sure this is a socket-activate unit + $unitsToStop->{$socket} = 1; # Only restart sockets that actually # exist in new configuration: if (-e "$out/etc/systemd/system/$socket") { $unitsToStart->{$socket} = 1; - recordUnit($startListFile, $socket); - $socketActivated = 1; + if ($unitsToStart eq $unitsToRestart) { + recordUnit($restartListFile, $socket); + } else { + recordUnit($startListFile, $socket); + } + $socket_activated = 1; } # Remove from units to reload so we don't restart and reload if ($unitsToReload->{$unit}) { @@ -368,9 +429,13 @@ sub handleModifiedUnit { # that this unit needs to be started below. # We write this to a file to ensure that the # service gets restarted if we're interrupted. - if (!$socketActivated) { + if (!$socket_activated) { $unitsToStart->{$unit} = 1; - recordUnit($startListFile, $unit); + if ($unitsToStart eq $unitsToRestart) { + recordUnit($restartListFile, $unit); + } else { + recordUnit($startListFile, $unit); + } } $unitsToStop->{$unit} = 1; @@ -398,8 +463,8 @@ $unitsToRestart{$_} = 1 foreach $unitsToReload{$_} = 1 foreach split('\n', read_file($reloadListFile, err_mode => 'quiet') // ""); -my $activePrev = getActiveUnits; -while (my ($unit, $state) = each %{$activePrev}) { +my $activePrev = getActiveUnits(); +while (my ($unit, $state) = each(%{$activePrev})) { my $baseUnit = $unit; my $prevUnitFile = "/etc/systemd/system/$baseUnit"; @@ -459,9 +524,9 @@ while (my ($unit, $state) = each %{$activePrev}) { my %old_unit_info = parse_unit($prevUnitFile); my %new_unit_info = parse_unit($newUnitFile); my $diff = compare_units(\%old_unit_info, \%new_unit_info); - if ($diff eq 1) { + if ($diff == 1) { handleModifiedUnit($unit, $baseName, $newUnitFile, \%new_unit_info, $activePrev, \%unitsToStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, \%unitsToSkip); - } elsif ($diff eq 2 and not $unitsToRestart{$unit}) { + } elsif ($diff == 2 and not $unitsToRestart{$unit}) { $unitsToReload{$unit} = 1; recordUnit($reloadListFile, $unit); } @@ -472,11 +537,11 @@ while (my ($unit, $state) = each %{$activePrev}) { sub pathToUnitName { my ($path) = @_; # Use current version of systemctl binary before daemon is reexeced. - open my $cmd, "-|", "$curSystemd/systemd-escape", "--suffix=mount", "-p", $path + open(my $cmd, "-|", "$curSystemd/systemd-escape", "--suffix=mount", "-p", $path) or die "Unable to escape $path!\n"; - my $escaped = join "", <$cmd>; - chomp $escaped; - close $cmd or die; + my $escaped = join("", <$cmd>); + chomp($escaped); + close($cmd) or die('Unable to close systemd-escape pipe'); return $escaped; } @@ -485,13 +550,13 @@ sub pathToUnitName { # automatically by starting local-fs.target. FIXME: might be nicer if # we generated units for all mounts; then we could unify this with the # unit checking code above. -my ($prevFss, $prevSwaps) = parseFstab "/etc/fstab"; -my ($newFss, $newSwaps) = parseFstab "$out/etc/fstab"; -foreach my $mountPoint (keys %$prevFss) { +my ($prevFss, $prevSwaps) = parseFstab("/etc/fstab"); +my ($newFss, $newSwaps) = parseFstab("$out/etc/fstab"); +foreach my $mountPoint (keys(%$prevFss)) { my $prev = $prevFss->{$mountPoint}; my $new = $newFss->{$mountPoint}; my $unit = pathToUnitName($mountPoint); - if (!defined $new) { + if (!defined($new)) { # Filesystem entry disappeared, so unmount it. $unitsToStop{$unit} = 1; } elsif ($prev->{fsType} ne $new->{fsType} || $prev->{device} ne $new->{device}) { @@ -507,10 +572,10 @@ foreach my $mountPoint (keys %$prevFss) { } # Also handles swap devices. -foreach my $device (keys %$prevSwaps) { +foreach my $device (keys(%$prevSwaps)) { my $prev = $prevSwaps->{$device}; my $new = $newSwaps->{$device}; - if (!defined $new) { + if (!defined($new)) { # Swap entry disappeared, so turn it off. Can't use # "systemctl stop" here because systemd has lots of alias # units that prevent a stop from actually calling @@ -541,8 +606,8 @@ if ($prevSystemdSystemConfig ne $newSystemdSystemConfig) { sub filterUnits { my ($units) = @_; my @res; - foreach my $unit (sort(keys %{$units})) { - push @res, $unit if !defined $unitsToFilter{$unit}; + foreach my $unit (sort(keys(%{$units}))) { + push(@res, $unit) if !defined($unitsToFilter{$unit}); } return @res; } @@ -553,9 +618,9 @@ my @unitsToStopFiltered = filterUnits(\%unitsToStop); # Show dry-run actions. if ($action eq "dry-activate") { print STDERR "would stop the following units: ", join(", ", @unitsToStopFiltered), "\n" - if scalar @unitsToStopFiltered > 0; - print STDERR "would NOT stop the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n" - if scalar(keys %unitsToSkip) > 0; + if scalar(@unitsToStopFiltered) > 0; + print STDERR "would NOT stop the following changed units: ", join(", ", sort(keys(%unitsToSkip))), "\n" + if scalar(keys(%unitsToSkip)) > 0; print STDERR "would activate the configuration...\n"; system("$out/dry-activate", "$out"); @@ -576,7 +641,7 @@ if ($action eq "dry-activate") { $baseName =~ s/\.[a-z]*$//; # Start units if they were not active previously - if (not defined $activePrev->{$unit}) { + if (not defined($activePrev->{$unit})) { $unitsToStart{$unit} = 1; next; } @@ -596,28 +661,28 @@ if ($action eq "dry-activate") { unlink($dryReloadByActivationFile); print STDERR "would restart systemd\n" if $restartSystemd; - print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n" - if scalar(keys %unitsToReload) > 0; - print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n" - if scalar(keys %unitsToRestart) > 0; + print STDERR "would reload the following units: ", join(", ", sort(keys(%unitsToReload))), "\n" + if scalar(keys(%unitsToReload)) > 0; + print STDERR "would restart the following units: ", join(", ", sort(keys(%unitsToRestart))), "\n" + if scalar(keys(%unitsToRestart)) > 0; my @unitsToStartFiltered = filterUnits(\%unitsToStart); print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n" - if scalar @unitsToStartFiltered; + if scalar(@unitsToStartFiltered); exit 0; } syslog(LOG_NOTICE, "switching to system configuration $out"); -if (scalar (keys %unitsToStop) > 0) { +if (scalar(keys(%unitsToStop)) > 0) { print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n" - if scalar @unitsToStopFiltered; + if scalar(@unitsToStopFiltered); # Use current version of systemctl binary before daemon is reexeced. - system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop)); + system("$curSystemd/systemctl", "stop", "--", sort(keys(%unitsToStop))); } -print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n" - if scalar(keys %unitsToSkip) > 0; +print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys(%unitsToSkip))), "\n" + if scalar(keys(%unitsToSkip)) > 0; # Activate the new configuration (i.e., update /etc, make accounts, # and so on). @@ -641,7 +706,7 @@ foreach (split('\n', read_file($restartByActivationFile, err_mode => 'quiet') // $baseName =~ s/\.[a-z]*$//; # Start units if they were not active previously - if (not defined $activePrev->{$unit}) { + if (not defined($activePrev->{$unit})) { $unitsToStart{$unit} = 1; recordUnit($startListFile, $unit); next; @@ -678,7 +743,7 @@ system("@systemd@/bin/systemctl", "reset-failed"); system("@systemd@/bin/systemctl", "daemon-reload") == 0 or $res = 3; # Reload user units -open my $listActiveUsers, '-|', '@systemd@/bin/loginctl', 'list-users', '--no-legend'; +open(my $listActiveUsers, '-|', '@systemd@/bin/loginctl', 'list-users', '--no-legend'); while (my $f = <$listActiveUsers>) { next unless $f =~ /^\s*(?<uid>\d+)\s+(?<user>\S+)/; my ($uid, $name) = ($+{uid}, $+{user}); @@ -690,25 +755,43 @@ while (my $f = <$listActiveUsers>) { "@systemd@/bin/systemctl --user start nixos-activation.service"); } -close $listActiveUsers; +close($listActiveUsers); # Set the new tmpfiles print STDERR "setting up tmpfiles\n"; system("@systemd@/bin/systemd-tmpfiles", "--create", "--remove", "--exclude-prefix=/dev") == 0 or $res = 3; +# Before reloading we need to ensure that the units are still active. They may have been +# deactivated because one of their requirements got stopped. If they are inactive +# but should have been reloaded, the user probably expects them to be started. +if (scalar(keys(%unitsToReload)) > 0) { + for my $unit (keys(%unitsToReload)) { + if (!unit_is_active($unit)) { + # Figure out if we need to start the unit + my %unit_info = parse_unit("$out/etc/systemd/system/$unit"); + if (!(parseSystemdBool(\%unit_info, 'Unit', 'RefuseManualStart', 0) || parseSystemdBool(\%unit_info, 'Unit', 'X-OnlyManualStart', 0))) { + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $unit); + } + # Don't reload the unit, reloading would fail + delete %unitsToReload{$unit}; + unrecord_unit($reloadListFile, $unit); + } + } +} # Reload units that need it. This includes remounting changed mount # units. -if (scalar(keys %unitsToReload) > 0) { - print STDERR "reloading the following units: ", join(", ", sort(keys %unitsToReload)), "\n"; - system("@systemd@/bin/systemctl", "reload", "--", sort(keys %unitsToReload)) == 0 or $res = 4; +if (scalar(keys(%unitsToReload)) > 0) { + print STDERR "reloading the following units: ", join(", ", sort(keys(%unitsToReload))), "\n"; + system("@systemd@/bin/systemctl", "reload", "--", sort(keys(%unitsToReload))) == 0 or $res = 4; unlink($reloadListFile); } # Restart changed services (those that have to be restarted rather # than stopped and started). -if (scalar(keys %unitsToRestart) > 0) { - print STDERR "restarting the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"; - system("@systemd@/bin/systemctl", "restart", "--", sort(keys %unitsToRestart)) == 0 or $res = 4; +if (scalar(keys(%unitsToRestart)) > 0) { + print STDERR "restarting the following units: ", join(", ", sort(keys(%unitsToRestart))), "\n"; + system("@systemd@/bin/systemctl", "restart", "--", sort(keys(%unitsToRestart))) == 0 or $res = 4; unlink($restartListFile); } @@ -720,17 +803,17 @@ if (scalar(keys %unitsToRestart) > 0) { # systemd. my @unitsToStartFiltered = filterUnits(\%unitsToStart); print STDERR "starting the following units: ", join(", ", @unitsToStartFiltered), "\n" - if scalar @unitsToStartFiltered; -system("@systemd@/bin/systemctl", "start", "--", sort(keys %unitsToStart)) == 0 or $res = 4; + if scalar(@unitsToStartFiltered); +system("@systemd@/bin/systemctl", "start", "--", sort(keys(%unitsToStart))) == 0 or $res = 4; unlink($startListFile); # Print failed and new units. my (@failed, @new); -my $activeNew = getActiveUnits; -while (my ($unit, $state) = each %{$activeNew}) { +my $activeNew = getActiveUnits(); +while (my ($unit, $state) = each(%{$activeNew})) { if ($state->{state} eq "failed") { - push @failed, $unit; + push(@failed, $unit); next; } @@ -740,7 +823,7 @@ while (my ($unit, $state) = each %{$activeNew}) { chomp($main_status); if ($main_status ne "0") { - push @failed, $unit; + push(@failed, $unit); next; } } @@ -748,19 +831,19 @@ while (my ($unit, $state) = each %{$activeNew}) { # Ignore scopes since they are not managed by this script but rather # created and managed by third-party services via the systemd dbus API. # This only lists units that are not failed (including ones that are in auto-restart but have not failed previously) - if ($state->{state} ne "failed" && !defined $activePrev->{$unit} && $unit !~ /\.scope$/msx) { - push @new, $unit; + if ($state->{state} ne "failed" && !defined($activePrev->{$unit}) && $unit !~ /\.scope$/msx) { + push(@new, $unit); } } -if (scalar @new > 0) { +if (scalar(@new) > 0) { print STDERR "the following new units were started: ", join(", ", sort(@new)), "\n" } -if (scalar @failed > 0) { - my @failed_sorted = sort @failed; +if (scalar(@failed) > 0) { + my @failed_sorted = sort(@failed); print STDERR "warning: the following units failed: ", join(", ", @failed_sorted), "\n\n"; - system "@systemd@/bin/systemctl status --no-pager --full '" . join("' '", @failed_sorted) . "' >&2"; + system("@systemd@/bin/systemctl status --no-pager --full '" . join("' '", @failed_sorted) . "' >&2"); $res = 4; } @@ -770,4 +853,4 @@ if ($res == 0) { syslog(LOG_ERR, "switching to system configuration $out failed (status $res)"); } -exit $res; +exit($res); diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py index adc893063098..fa879437fd81 100644 --- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py @@ -15,9 +15,12 @@ import re import datetime import glob import os.path -from typing import Tuple, List, Optional +from typing import NamedTuple, List, Optional -SystemIdentifier = Tuple[Optional[str], int, Optional[str]] +class SystemIdentifier(NamedTuple): + profile: Optional[str] + generation: int + specialisation: Optional[str] def copy_if_not_exists(source: str, dest: str) -> None: @@ -151,7 +154,14 @@ def get_generations(profile: Optional[str] = None) -> List[SystemIdentifier]: gen_lines.pop() configurationLimit = @configurationLimit@ - configurations: List[SystemIdentifier] = [ (profile, int(line.split()[0]), None) for line in gen_lines ] + configurations = [ + SystemIdentifier( + profile=profile, + generation=int(line.split()[0]), + specialisation=None + ) + for line in gen_lines + ] return configurations[-configurationLimit:] @@ -160,7 +170,7 @@ def get_specialisations(profile: Optional[str], generation: int, _: Optional[str system_dir(profile, generation, None), "specialisation") if not os.path.exists(specialisations_dir): return [] - return [(profile, generation, spec) for spec in os.listdir(specialisations_dir)] + return [SystemIdentifier(profile, generation, spec) for spec in os.listdir(specialisations_dir)] def remove_old_entries(gens: List[SystemIdentifier]) -> None: @@ -271,7 +281,8 @@ def main() -> None: if os.readlink(system_dir(*gen)) == args.default_config: write_loader_conf(*gen) except OSError as e: - print("ignoring generation '{}' in the list of boot entries because of the following error:\n{}".format(*gen, e), file=sys.stderr) + profile = f"profile '{gen.profile}'" if gen.profile else "default profile" + print("ignoring {} in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr) for root, _, files in os.walk('@efiSysMountPoint@/efi/nixos/.extra-files', topdown=False): relative_root = root.removeprefix("@efiSysMountPoint@/efi/nixos/.extra-files").removeprefix("/") diff --git a/nixpkgs/nixos/modules/system/boot/modprobe.nix b/nixpkgs/nixos/modules/system/boot/modprobe.nix index 7426d148891f..27f78835adb2 100644 --- a/nixpkgs/nixos/modules/system/boot/modprobe.nix +++ b/nixpkgs/nixos/modules/system/boot/modprobe.nix @@ -72,6 +72,8 @@ with lib; ''; environment.etc."modprobe.d/debian.conf".source = pkgs.kmod-debian-aliases; + environment.etc."modprobe.d/systemd.conf".source = "${pkgs.systemd}/lib/modprobe.d/systemd.conf"; + environment.systemPackages = [ pkgs.kmod ]; system.activationScripts.modprobe = stringAfter ["specialfs"] diff --git a/nixpkgs/nixos/modules/system/boot/systemd.nix b/nixpkgs/nixos/modules/system/boot/systemd.nix index 04c310f07c59..2607e57195ca 100644 --- a/nixpkgs/nixos/modules/system/boot/systemd.nix +++ b/nixpkgs/nixos/modules/system/boot/systemd.nix @@ -1219,6 +1219,25 @@ in boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.is64bit (lib.mkDefault 4194304); boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0"; + + services.logrotate.paths = { + "/var/log/btmp" = mapAttrs (_: mkDefault) { + frequency = "monthly"; + keep = 1; + extraConfig = '' + create 0660 root ${config.users.groups.utmp.name} + minsize 1M + ''; + }; + "/var/log/wtmp" = mapAttrs (_: mkDefault) { + frequency = "monthly"; + keep = 1; + extraConfig = '' + create 0664 root ${config.users.groups.utmp.name} + minsize 1M + ''; + }; + }; }; # FIXME: Remove these eventually. diff --git a/nixpkgs/nixos/modules/virtualisation/amazon-image.nix b/nixpkgs/nixos/modules/virtualisation/amazon-image.nix index bd7077ff7ea1..9a56b6950155 100644 --- a/nixpkgs/nixos/modules/virtualisation/amazon-image.nix +++ b/nixpkgs/nixos/modules/virtualisation/amazon-image.nix @@ -37,8 +37,13 @@ in { assertion = cfg.efi -> cfg.hvm; message = "EC2 instances using EFI must be HVM instances."; } + { assertion = versionOlder config.boot.kernelPackages.kernel.version "5.15"; + message = "ENA driver fails to build with kernel >= 5.15"; + } ]; + boot.kernelPackages = pkgs.linuxKernel.packages.linux_5_10; + boot.growPartition = cfg.hvm; fileSystems."/" = mkIf (!cfg.zfs.enable) { diff --git a/nixpkgs/nixos/modules/virtualisation/oci-containers.nix b/nixpkgs/nixos/modules/virtualisation/oci-containers.nix index 5af9baff8bc1..f40481727830 100644 --- a/nixpkgs/nixos/modules/virtualisation/oci-containers.nix +++ b/nixpkgs/nixos/modules/virtualisation/oci-containers.nix @@ -22,11 +22,13 @@ let type = with types; nullOr package; default = null; description = '' - Path to an image file to load instead of pulling from a registry. - If defined, do not pull from registry. + Path to an image file to load before running the image. This can + be used to bypass pulling the image from the registry. - You still need to set the <literal>image</literal> attribute, as it - will be used as the image name for docker to start a container. + The <literal>image</literal> attribute must match the name and + tag of the image contained in this file, as they will be used to + run the container with that image. If they do not match, the + image will be pulled from the registry as usual. ''; example = literalExpression "pkgs.dockerTools.buildImage {...};"; }; diff --git a/nixpkgs/nixos/modules/virtualisation/openstack-metadata-fetcher.nix b/nixpkgs/nixos/modules/virtualisation/openstack-metadata-fetcher.nix index 133cd4c0e9f9..25104bb47667 100644 --- a/nixpkgs/nixos/modules/virtualisation/openstack-metadata-fetcher.nix +++ b/nixpkgs/nixos/modules/virtualisation/openstack-metadata-fetcher.nix @@ -15,7 +15,8 @@ } wget_imds -O "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path - (umask 077 && wget_imds -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data) + # When no user-data is provided, the OpenStack metadata server doesn't expose the user-data route. + (umask 077 && wget_imds -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data || rm -f "$metaDir/user-data") wget_imds -O "$metaDir/hostname" http://169.254.169.254/1.0/meta-data/hostname wget_imds -O "$metaDir/public-keys-0-openssh-key" http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key '' diff --git a/nixpkgs/nixos/modules/virtualisation/proxmox-lxc.nix b/nixpkgs/nixos/modules/virtualisation/proxmox-lxc.nix new file mode 100644 index 000000000000..3913b474afbe --- /dev/null +++ b/nixpkgs/nixos/modules/virtualisation/proxmox-lxc.nix @@ -0,0 +1,64 @@ +{ config, pkgs, lib, ... }: + +with lib; + +{ + options.proxmoxLXC = { + privileged = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable privileged mounts + ''; + }; + manageNetwork = mkOption { + type = types.bool; + default = false; + description = '' + Whether to manage network interfaces through nix options + When false, systemd-networkd is enabled to accept network + configuration from proxmox. + ''; + }; + }; + + config = + let + cfg = config.proxmoxLXC; + in + { + system.build.tarball = pkgs.callPackage ../../lib/make-system-tarball.nix { + storeContents = [{ + object = config.system.build.toplevel; + symlink = "none"; + }]; + + contents = [{ + source = config.system.build.toplevel + "/init"; + target = "/sbin/init"; + }]; + + extraCommands = "mkdir -p root etc/systemd/network"; + }; + + boot = { + isContainer = true; + loader.initScript.enable = true; + }; + + networking = mkIf (!cfg.manageNetwork) { + useDHCP = false; + useHostResolvConf = false; + useNetworkd = true; + }; + + services.openssh = { + enable = mkDefault true; + startWhenNeeded = mkDefault true; + }; + + systemd.mounts = mkIf (!cfg.privileged) + [{ where = "/sys/kernel/debug"; enable = false; }]; + + }; +} |