diff options
Diffstat (limited to 'nixos/modules')
48 files changed, 1405 insertions, 424 deletions
diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix index 4727e5b85ef2..a50a03ce52d4 100644 --- a/nixos/modules/config/no-x-libs.nix +++ b/nixos/modules/config/no-x-libs.nix @@ -37,6 +37,7 @@ with lib; ghostscript = super.ghostscript.override { cupsSupport = false; x11Support = false; }; gjs = super.gjs.overrideAttrs { doCheck = false; installTests = false; }; # avoid test dependency on gtk3 gobject-introspection = super.gobject-introspection.override { x11Support = false; }; + gpg-tui = super.gpg-tui.override { x11Support = false; }; gpsd = super.gpsd.override { guiSupport = false; }; graphviz = super.graphviz-nox; gst_all_1 = super.gst_all_1 // { diff --git a/nixos/modules/image/repart-image.nix b/nixos/modules/image/repart-image.nix index a12b4fb14fb1..7ac47ee32ff4 100644 --- a/nixos/modules/image/repart-image.nix +++ b/nixos/modules/image/repart-image.nix @@ -32,6 +32,7 @@ , split , seed , definitionsDirectory +, sectorSize }: let @@ -94,6 +95,7 @@ runCommand imageFileBasename --definitions="$amendedRepartDefinitions" \ --split="${lib.boolToString split}" \ --json=pretty \ + ${lib.optionalString (sectorSize != null) "--sector-size=${toString sectorSize}"} \ ${imageFileBasename}.raw \ | tee repart-output.json diff --git a/nixos/modules/image/repart.nix b/nixos/modules/image/repart.nix index ed584d9bf997..6a933f0d83cc 100644 --- a/nixos/modules/image/repart.nix +++ b/nixos/modules/image/repart.nix @@ -135,6 +135,16 @@ in ''; }; + sectorSize = lib.mkOption { + type = with lib.types; nullOr int; + default = 512; + example = lib.literalExpression "4096"; + description = lib.mdDoc '' + The sector size of the disk image produced by systemd-repart. This + value must be a power of 2 between 512 and 4096. + ''; + }; + package = lib.mkPackageOption pkgs "systemd-repart" { # We use buildPackages so that repart images are built with the build # platform's systemd, allowing for cross-compiled systems to work. @@ -232,7 +242,7 @@ in in pkgs.callPackage ./repart-image.nix { systemd = cfg.package; - inherit (cfg) imageFileBasename compression split seed; + inherit (cfg) imageFileBasename compression split seed sectorSize; inherit fileSystems definitionsDirectory partitions; }; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 0839422ac2e9..37f822721f48 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -215,6 +215,7 @@ ./programs/minipro.nix ./programs/miriway.nix ./programs/mosh.nix + ./programs/mouse-actions.nix ./programs/msmtp.nix ./programs/mtr.nix ./programs/nano.nix @@ -534,6 +535,7 @@ ./services/hardware/fancontrol.nix ./services/hardware/freefall.nix ./services/hardware/fwupd.nix + ./services/hardware/handheld-daemon.nix ./services/hardware/hddfancontrol.nix ./services/hardware/illum.nix ./services/hardware/interception-tools.nix @@ -1061,6 +1063,7 @@ ./services/networking/openvpn.nix ./services/networking/ostinato.nix ./services/networking/owamp.nix + ./services/networking/pyload.nix ./services/networking/pdns-recursor.nix ./services/networking/pdnsd.nix ./services/networking/peroxide.nix @@ -1236,6 +1239,7 @@ ./services/system/saslauthd.nix ./services/system/self-deploy.nix ./services/system/systembus-notify.nix + ./services/system/systemd-lock-handler.nix ./services/system/uptimed.nix ./services/system/zram-generator.nix ./services/torrent/deluge.nix @@ -1340,6 +1344,7 @@ ./services/web-apps/plantuml-server.nix ./services/web-apps/plausible.nix ./services/web-apps/powerdns-admin.nix + ./services/web-apps/pretalx.nix ./services/web-apps/prosody-filer.nix ./services/web-apps/restya-board.nix ./services/web-apps/rimgo.nix diff --git a/nixos/modules/profiles/hardened.nix b/nixos/modules/profiles/hardened.nix index 74dc2cb1b9aa..b85a2ac7e69d 100644 --- a/nixos/modules/profiles/hardened.nix +++ b/nixos/modules/profiles/hardened.nix @@ -39,14 +39,17 @@ with lib; security.apparmor.killUnconfinedConfinables = mkDefault true; boot.kernelParams = [ - # Slab/slub sanity checks, redzoning, and poisoning - "slub_debug=FZP" + # Don't merge slabs + "slab_nomerge" - # Overwrite free'd memory + # Overwrite free'd pages "page_poison=1" # Enable page allocator randomization "page_alloc.shuffle=1" + + # Disable debugfs + "debugfs=off" ]; boot.blacklistedKernelModules = [ diff --git a/nixos/modules/programs/mouse-actions.nix b/nixos/modules/programs/mouse-actions.nix new file mode 100644 index 000000000000..fdf39d56d383 --- /dev/null +++ b/nixos/modules/programs/mouse-actions.nix @@ -0,0 +1,15 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.programs.mouse-actions; +in + { + options.programs.mouse-actions = { + enable = lib.mkEnableOption '' + mouse-actions udev rules. This is a prerequisite for using mouse-actions without being root. + ''; + }; + config = lib.mkIf cfg.enable { + services.udev.packages = [ pkgs.mouse-actions ]; + }; + } diff --git a/nixos/modules/programs/nautilus-open-any-terminal.nix b/nixos/modules/programs/nautilus-open-any-terminal.nix new file mode 100644 index 000000000000..d205fb3ec916 --- /dev/null +++ b/nixos/modules/programs/nautilus-open-any-terminal.nix @@ -0,0 +1,36 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.programs.nautilus-open-any-terminal; +in +{ + options.programs.nautilus-open-any-terminal = { + enable = lib.mkEnableOption (lib.mdDoc "nautilus-open-any-terminal"); + + terminal = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + description = lib.mdDoc '' + The terminal emulator to add to context-entry of nautilus. Supported terminal + emulators are listed in https://github.com/Stunkymonkey/nautilus-open-any-terminal#supported-terminal-emulators. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + gnome.nautilus-python + nautilus-open-any-terminal + ]; + programs.dconf = lib.optionalAttrs (cfg.terminal != null) { + enable = true; + profiles.user.databases = [{ + settings."com/github/stunkymonkey/nautilus-open-any-terminal".terminal = cfg.terminal; + lockAll = true; + }]; + }; + }; + meta = { + maintainers = with lib.maintainers; [ stunkymonkey linsui ]; + }; +} diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 111be7057afc..ffbb558549f6 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -867,9 +867,6 @@ let { name = "gnupg"; enable = cfg.gnupg.enable; control = "optional"; modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; settings = { no-autostart = cfg.gnupg.noAutostart; }; } - { name = "cgfs"; enable = config.virtualisation.lxc.lxcfs.enable; control = "optional"; modulePath = "${pkgs.lxc}/lib/security/pam_cgfs.so"; args = [ - "-c" "all" - ]; } ]; }; }; diff --git a/nixos/modules/security/wrappers/wrapper.c b/nixos/modules/security/wrappers/wrapper.c index 3277e7ef6f79..3e126875c687 100644 --- a/nixos/modules/security/wrappers/wrapper.c +++ b/nixos/modules/security/wrappers/wrapper.c @@ -172,6 +172,13 @@ static int make_caps_ambient(const char *self_path) { int main(int argc, char **argv) { ASSERT(argc >= 1); + // argv[0] goes into a lot of places, to a far greater degree than other elements + // of argv. glibc has had buffer overflows relating to argv[0], eg CVE-2023-6246. + // Since we expect the wrappers to be invoked from either $PATH or /run/wrappers/bin, + // there should be no reason to pass any particularly large values here, so we can + // be strict for strictness' sake. + ASSERT(strlen(argv[0]) < 512); + int debug = getenv(wrapper_debug) != NULL; // Drop insecure environment variables explicitly diff --git a/nixos/modules/services/audio/navidrome.nix b/nixos/modules/services/audio/navidrome.nix index e44fc822e4ad..912edb03aa4c 100644 --- a/nixos/modules/services/audio/navidrome.nix +++ b/nixos/modules/services/audio/navidrome.nix @@ -53,6 +53,7 @@ in { RuntimeDirectory = "navidrome"; RootDirectory = "/run/navidrome"; ReadWritePaths = ""; + BindPaths = lib.optional (cfg.settings ? DataFolder) cfg.settings.DataFolder; BindReadOnlyPaths = [ # navidrome uses online services to download additional album metadata / covers "${config.environment.etc."ssl/certs/ca-certificates.crt".source}:/etc/ssl/certs/ca-certificates.crt" diff --git a/nixos/modules/services/hardware/acpid.nix b/nixos/modules/services/hardware/acpid.nix index 6021aad09f45..821f4ef205fc 100644 --- a/nixos/modules/services/hardware/acpid.nix +++ b/nixos/modules/services/hardware/acpid.nix @@ -135,7 +135,6 @@ in wantedBy = [ "multi-user.target" ]; serviceConfig = { - PrivateNetwork = true; ExecStart = escapeShellArgs ([ "${pkgs.acpid}/bin/acpid" "--foreground" diff --git a/nixos/modules/services/hardware/handheld-daemon.nix b/nixos/modules/services/hardware/handheld-daemon.nix new file mode 100644 index 000000000000..e8a7a39f441d --- /dev/null +++ b/nixos/modules/services/hardware/handheld-daemon.nix @@ -0,0 +1,44 @@ +{ config +, lib +, pkgs +, ... +}: +with lib; let + cfg = config.services.handheld-daemon; +in +{ + options.services.handheld-daemon = { + enable = mkEnableOption "Enable Handheld Daemon"; + package = mkPackageOption pkgs "handheld-daemon" { }; + + user = mkOption { + type = types.str; + description = lib.mdDoc '' + The user to run Handheld Daemon with. + ''; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + services.udev.packages = [ cfg.package ]; + systemd.packages = [ cfg.package ]; + + systemd.services.handheld-daemon = { + description = "Handheld Daemon"; + + wantedBy = [ "multi-user.target" ]; + + restartIfChanged = true; + + serviceConfig = { + ExecStart = "${ lib.getExe cfg.package } --user ${ cfg.user }"; + Nice = "-12"; + Restart = "on-failure"; + RestartSec = "10"; + }; + }; + }; + + meta.maintainers = [ maintainers.appsforartists ]; +} diff --git a/nixos/modules/services/hardware/ratbagd.nix b/nixos/modules/services/hardware/ratbagd.nix index c939d5e40a24..5567bcbafd16 100644 --- a/nixos/modules/services/hardware/ratbagd.nix +++ b/nixos/modules/services/hardware/ratbagd.nix @@ -11,6 +11,8 @@ in options = { services.ratbagd = { enable = mkEnableOption (lib.mdDoc "ratbagd for configuring gaming mice"); + + package = mkPackageOption pkgs "libratbag" { }; }; }; @@ -18,10 +20,10 @@ in config = mkIf cfg.enable { # Give users access to the "ratbagctl" tool - environment.systemPackages = [ pkgs.libratbag ]; + environment.systemPackages = [ cfg.package ]; - services.dbus.packages = [ pkgs.libratbag ]; + services.dbus.packages = [ cfg.package ]; - systemd.packages = [ pkgs.libratbag ]; + systemd.packages = [ cfg.package ]; }; } diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index 8d298de6945b..71baa2bb1852 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -1,8 +1,8 @@ -{ options, config, lib, pkgs, ... }: +{ config, lib, pkgs, ... }: let - inherit (lib) any attrValues concatMapStringsSep concatStrings - concatStringsSep flatten imap1 isList literalExpression mapAttrsToList + inherit (lib) attrValues concatMapStringsSep concatStrings + concatStringsSep flatten imap1 literalExpression mapAttrsToList mkEnableOption mkIf mkOption mkRemovedOptionModule optional optionalAttrs optionalString singleton types mkRenamedOptionModule nameValuePair mapAttrs' listToAttrs filter; @@ -14,7 +14,7 @@ let baseDir = "/run/dovecot2"; stateDir = "/var/lib/dovecot"; - sieveScriptSettings = mapAttrs' (to: from: nameValuePair "sieve_${to}" "${stateDir}/sieve/${from}") cfg.sieve.scripts; + sieveScriptSettings = mapAttrs' (to: _: nameValuePair "sieve_${to}" "${stateDir}/sieve/${to}") cfg.sieve.scripts; imapSieveMailboxSettings = listToAttrs (flatten (imap1 (idx: el: singleton { name = "imapsieve_mailbox${toString idx}_name"; diff --git a/nixos/modules/services/misc/moonraker.nix b/nixos/modules/services/misc/moonraker.nix index 4e419aafa990..f043cc83bf05 100644 --- a/nixos/modules/services/misc/moonraker.nix +++ b/nixos/modules/services/misc/moonraker.nix @@ -103,17 +103,18 @@ in { config = mkIf cfg.enable { warnings = [] - ++ optional (cfg.settings.update_manager.enable_system_updates or false) - ''Enabling update_manager is not supported on NixOS and will lead to non-removable warnings in some clients.'' - ++ optional (cfg.configDir != null) - '' - services.moonraker.configDir has been deprecated upstream and will be removed. - - Action: ${ - if cfg.configDir == unifiedConfigDir then "Simply remove services.moonraker.configDir from your config." - else "Move files from `${cfg.configDir}` to `${unifiedConfigDir}` then remove services.moonraker.configDir from your config." - } - ''; + ++ (optional (head (cfg.settings.update_manager.enable_system_updates or [false])) '' + Enabling system updates is not supported on NixOS and will lead to non-removable warnings in some clients. + '') + ++ (optional (cfg.configDir != null) '' + services.moonraker.configDir has been deprecated upstream and will be removed. + + Action: ${ + if cfg.configDir == unifiedConfigDir + then "Simply remove services.moonraker.configDir from your config." + else "Move files from `${cfg.configDir}` to `${unifiedConfigDir}` then remove services.moonraker.configDir from your config." + } + ''); assertions = [ { diff --git a/nixos/modules/services/misc/packagekit.nix b/nixos/modules/services/misc/packagekit.nix index 5a0d314d25cd..f4191a4453ca 100644 --- a/nixos/modules/services/misc/packagekit.nix +++ b/nixos/modules/services/misc/packagekit.nix @@ -13,7 +13,7 @@ let (iniFmt.generate "PackageKit.conf" (recursiveUpdate { Daemon = { - DefaultBackend = "nix"; + DefaultBackend = "test_nop"; KeepCache = false; }; } @@ -35,7 +35,7 @@ let in { imports = [ - (mkRemovedOptionModule [ "services" "packagekit" "backend" ] "Always set to Nix.") + (mkRemovedOptionModule [ "services" "packagekit" "backend" ] "Always set to test_nop, Nix backend is broken see #177946.") ]; options.services.packagekit = { diff --git a/nixos/modules/services/misc/paperless.nix b/nixos/modules/services/misc/paperless.nix index ca34a327dbdf..1256d8315c8b 100644 --- a/nixos/modules/services/misc/paperless.nix +++ b/nixos/modules/services/misc/paperless.nix @@ -6,7 +6,6 @@ let pkg = cfg.package; defaultUser = "paperless"; - nltkDir = "/var/cache/paperless/nltk"; defaultFont = "${pkgs.liberation_ttf}/share/fonts/truetype/LiberationSerif-Regular.ttf"; # Don't start a redis instance if the user sets a custom redis connection @@ -17,13 +16,17 @@ let PAPERLESS_DATA_DIR = cfg.dataDir; PAPERLESS_MEDIA_ROOT = cfg.mediaDir; PAPERLESS_CONSUMPTION_DIR = cfg.consumptionDir; - PAPERLESS_NLTK_DIR = nltkDir; PAPERLESS_THUMBNAIL_FONT_NAME = defaultFont; GUNICORN_CMD_ARGS = "--bind=${cfg.address}:${toString cfg.port}"; } // optionalAttrs (config.time.timeZone != null) { PAPERLESS_TIME_ZONE = config.time.timeZone; } // optionalAttrs enableRedis { PAPERLESS_REDIS = "unix://${redisServer.unixSocket}"; + } // optionalAttrs (cfg.settings.PAPERLESS_ENABLE_NLTK or true) { + PAPERLESS_NLTK_DIR = pkgs.symlinkJoin { + name = "paperless_ngx_nltk_data"; + paths = pkg.nltkData; + }; } // (lib.mapAttrs (_: s: if (lib.isAttrs s || lib.isList s) then builtins.toJSON s else if lib.isBool s then lib.boolToString s @@ -141,12 +144,12 @@ in `''${dataDir}/paperless-manage createsuperuser`. The default superuser name is `admin`. To change it, set - option {option}`extraConfig.PAPERLESS_ADMIN_USER`. + option {option}`settings.PAPERLESS_ADMIN_USER`. WARNING: When changing the superuser name after the initial setup, the old superuser will continue to exist. To disable login for the web interface, set the following: - `extraConfig.PAPERLESS_AUTO_LOGIN_USERNAME = "admin";`. + `settings.PAPERLESS_AUTO_LOGIN_USERNAME = "admin";`. WARNING: Only use this on a trusted system without internet access to Paperless. ''; }; @@ -292,23 +295,6 @@ in }; }; - # Download NLTK corpus data - systemd.services.paperless-download-nltk-data = { - wantedBy = [ "paperless-scheduler.service" ]; - before = [ "paperless-scheduler.service" ]; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - serviceConfig = defaultServiceConfig // { - User = cfg.user; - Type = "oneshot"; - # Enable internet access - PrivateNetwork = false; - ExecStart = let pythonWithNltk = pkg.python.withPackages (ps: [ ps.nltk ]); in '' - ${pythonWithNltk}/bin/python -m nltk.downloader -d '${nltkDir}' punkt snowball_data stopwords - ''; - }; - }; - systemd.services.paperless-consumer = { description = "Paperless document consumer"; # Bind to `paperless-scheduler` so that the consumer never runs diff --git a/nixos/modules/services/misc/portunus.nix b/nixos/modules/services/misc/portunus.nix index 47af24f024cd..ebb3bc8f0851 100644 --- a/nixos/modules/services/misc/portunus.nix +++ b/nixos/modules/services/misc/portunus.nix @@ -37,6 +37,15 @@ in ''; }; + seedSettings = lib.mkOption { + type = with lib.types; nullOr (attrsOf (listOf (attrsOf anything))); + default = null; + description = lib.mdDoc '' + Seed settings for users and groups. + See upstream for format <https://github.com/majewsky/portunus#seeding-users-and-groups-from-static-configuration> + ''; + }; + stateDir = mkOption { type = types.path; default = "/var/lib/portunus"; @@ -172,49 +181,53 @@ in "127.0.0.1" = [ cfg.domain ]; }; - services.dex = mkIf cfg.dex.enable { - enable = true; - settings = { - issuer = "https://${cfg.domain}/dex"; - web.http = "127.0.0.1:${toString cfg.dex.port}"; - storage = { - type = "sqlite3"; - config.file = "/var/lib/dex/dex.db"; - }; - enablePasswordDB = false; - connectors = [{ - type = "ldap"; - id = "ldap"; - name = "LDAP"; - config = { - host = "${cfg.domain}:636"; - bindDN = "uid=${cfg.ldap.searchUserName},ou=users,${cfg.ldap.suffix}"; - bindPW = "$DEX_SEARCH_USER_PASSWORD"; - userSearch = { - baseDN = "ou=users,${cfg.ldap.suffix}"; - filter = "(objectclass=person)"; - username = "uid"; - idAttr = "uid"; - emailAttr = "mail"; - nameAttr = "cn"; - preferredUsernameAttr = "uid"; - }; - groupSearch = { - baseDN = "ou=groups,${cfg.ldap.suffix}"; - filter = "(objectclass=groupOfNames)"; - nameAttr = "cn"; - userMatchers = [{ userAttr = "DN"; groupAttr = "member"; }]; - }; + services = { + dex = mkIf cfg.dex.enable { + enable = true; + settings = { + issuer = "https://${cfg.domain}/dex"; + web.http = "127.0.0.1:${toString cfg.dex.port}"; + storage = { + type = "sqlite3"; + config.file = "/var/lib/dex/dex.db"; }; - }]; - - staticClients = forEach cfg.dex.oidcClients (client: { - inherit (client) id; - redirectURIs = [ client.callbackURL ]; - name = "OIDC for ${client.id}"; - secretEnv = "DEX_CLIENT_${client.id}"; - }); + enablePasswordDB = false; + connectors = [{ + type = "ldap"; + id = "ldap"; + name = "LDAP"; + config = { + host = "${cfg.domain}:636"; + bindDN = "uid=${cfg.ldap.searchUserName},ou=users,${cfg.ldap.suffix}"; + bindPW = "$DEX_SEARCH_USER_PASSWORD"; + userSearch = { + baseDN = "ou=users,${cfg.ldap.suffix}"; + filter = "(objectclass=person)"; + username = "uid"; + idAttr = "uid"; + emailAttr = "mail"; + nameAttr = "cn"; + preferredUsernameAttr = "uid"; + }; + groupSearch = { + baseDN = "ou=groups,${cfg.ldap.suffix}"; + filter = "(objectclass=groupOfNames)"; + nameAttr = "cn"; + userMatchers = [{ userAttr = "DN"; groupAttr = "member"; }]; + }; + }; + }]; + + staticClients = forEach cfg.dex.oidcClients (client: { + inherit (client) id; + redirectURIs = [ client.callbackURL ]; + name = "OIDC for ${client.id}"; + secretEnv = "DEX_CLIENT_${client.id}"; + }); + }; }; + + portunus.seedPath = lib.mkIf (cfg.seedSettings != null) (pkgs.writeText "seed.json" (builtins.toJSON cfg.seedSettings)); }; systemd.services = { diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index 35db8a7376b1..6be6ba7edf72 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -60,7 +60,6 @@ let "node" "nut" "openldap" - "openvpn" "pgbouncer" "php-fpm" "pihole" @@ -71,6 +70,7 @@ let "pve" "py-air-control" "redis" + "restic" "rspamd" "rtl_433" "sabnzbd" diff --git a/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix b/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix deleted file mode 100644 index 5b54dad99805..000000000000 --- a/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.exporters.openvpn; -in { - port = 9176; - extraOpts = { - statusPaths = mkOption { - type = types.listOf types.str; - description = lib.mdDoc '' - Paths to OpenVPN status files. Please configure the OpenVPN option - `status` accordingly. - ''; - }; - telemetryPath = mkOption { - type = types.str; - default = "/metrics"; - description = lib.mdDoc '' - Path under which to expose metrics. - ''; - }; - }; - - serviceOpts = { - serviceConfig = { - PrivateDevices = true; - ProtectKernelModules = true; - NoNewPrivileges = true; - ExecStart = '' - ${pkgs.prometheus-openvpn-exporter}/bin/openvpn_exporter \ - -openvpn.status_paths "${concatStringsSep "," cfg.statusPaths}" \ - -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ - -web.telemetry-path ${cfg.telemetryPath} - ''; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/restic.nix b/nixos/modules/services/monitoring/prometheus/exporters/restic.nix new file mode 100644 index 000000000000..5b32c93a666d --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/restic.nix @@ -0,0 +1,131 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.restic; +in +{ + port = 9753; + extraOpts = { + repository = mkOption { + type = types.str; + description = lib.mdDoc '' + URI pointing to the repository to monitor. + ''; + example = "sftp:backup@192.168.1.100:/backups/example"; + }; + + passwordFile = mkOption { + type = types.path; + description = lib.mdDoc '' + File containing the password to the repository. + ''; + example = "/etc/nixos/restic-password"; + }; + + environmentFile = mkOption { + type = with types; nullOr path; + default = null; + description = lib.mdDoc '' + File containing the credentials to access the repository, in the + format of an EnvironmentFile as described by systemd.exec(5) + ''; + }; + + refreshInterval = mkOption { + type = types.ints.unsigned; + default = 60; + description = lib.mdDoc '' + Refresh interval for the metrics in seconds. + Computing the metrics is an expensive task, keep this value as high as possible. + ''; + }; + + rcloneOptions = mkOption { + type = with types; attrsOf (oneOf [ str bool ]); + default = { }; + description = lib.mdDoc '' + Options to pass to rclone to control its behavior. + See <https://rclone.org/docs/#options> for + available options. When specifying option names, strip the + leading `--`. To set a flag such as + `--drive-use-trash`, which does not take a value, + set the value to the Boolean `true`. + ''; + }; + + rcloneConfig = mkOption { + type = with types; attrsOf (oneOf [ str bool ]); + default = { }; + description = lib.mdDoc '' + Configuration for the rclone remote being used for backup. + See the remote's specific options under rclone's docs at + <https://rclone.org/docs/>. When specifying + option names, use the "config" name specified in the docs. + For example, to set `--b2-hard-delete` for a B2 + remote, use `hard_delete = true` in the + attribute set. + + ::: {.warning} + Secrets set in here will be world-readable in the Nix + store! Consider using the {option}`rcloneConfigFile` + option instead to specify secret values separately. Note that + options set here will override those set in the config file. + ::: + ''; + }; + + rcloneConfigFile = mkOption { + type = with types; nullOr path; + default = null; + description = lib.mdDoc '' + Path to the file containing rclone configuration. This file + must contain configuration for the remote specified in this backup + set and also must be readable by root. + + ::: {.caution} + Options set in `rcloneConfig` will override those set in this + file. + ::: + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-restic-exporter}/bin/restic-exporter.py \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; + }; + environment = + let + rcloneRemoteName = builtins.elemAt (splitString ":" cfg.repository) 1; + rcloneAttrToOpt = v: "RCLONE_" + toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v); + rcloneAttrToConf = v: "RCLONE_CONFIG_" + toUpper (rcloneRemoteName + "_" + v); + toRcloneVal = v: if lib.isBool v then lib.boolToString v else v; + in + { + RESTIC_REPO_URL = cfg.repository; + RESTIC_REPO_PASSWORD_FILE = cfg.passwordFile; + LISTEN_ADDRESS = cfg.listenAddress; + LISTEN_PORT = toString cfg.port; + REFRESH_INTERVAL = toString cfg.refreshInterval; + } + // (mapAttrs' + (name: value: + nameValuePair (rcloneAttrToOpt name) (toRcloneVal value) + ) + cfg.rcloneOptions) + // optionalAttrs (cfg.rcloneConfigFile != null) { + RCLONE_CONFIG = cfg.rcloneConfigFile; + } + // (mapAttrs' + (name: value: + nameValuePair (rcloneAttrToConf name) (toRcloneVal value) + ) + cfg.rcloneConfig); + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix b/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix index 840ce493ee81..452cb154bcf6 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix @@ -3,6 +3,7 @@ with lib; let + logPrefix = "services.prometheus.exporters.snmp"; cfg = config.services.prometheus.exporters.snmp; # This ensures that we can deal with string paths, path types and diff --git a/nixos/modules/services/monitoring/zabbix-proxy.nix b/nixos/modules/services/monitoring/zabbix-proxy.nix index 503e81b48a58..fea5704af6f6 100644 --- a/nixos/modules/services/monitoring/zabbix-proxy.nix +++ b/nixos/modules/services/monitoring/zabbix-proxy.nix @@ -299,10 +299,7 @@ in fi '' + optionalString (cfg.database.passwordFile != null) '' # create a copy of the supplied password file in a format zabbix can consume - touch ${passwordFile} - chmod 0600 ${passwordFile} - echo -n "DBPassword = " > ${passwordFile} - cat ${cfg.database.passwordFile} >> ${passwordFile} + install -m 0600 <(echo "DBPassword = $(cat ${cfg.database.passwordFile})") ${passwordFile} ''; serviceConfig = { diff --git a/nixos/modules/services/monitoring/zabbix-server.nix b/nixos/modules/services/monitoring/zabbix-server.nix index 0607188d2131..f2fb5fbe7ac6 100644 --- a/nixos/modules/services/monitoring/zabbix-server.nix +++ b/nixos/modules/services/monitoring/zabbix-server.nix @@ -292,10 +292,7 @@ in fi '' + optionalString (cfg.database.passwordFile != null) '' # create a copy of the supplied password file in a format zabbix can consume - touch ${passwordFile} - chmod 0600 ${passwordFile} - echo -n "DBPassword = " > ${passwordFile} - cat ${cfg.database.passwordFile} >> ${passwordFile} + install -m 0600 <(echo "DBPassword = $(cat ${cfg.database.passwordFile})") ${passwordFile} ''; serviceConfig = { diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix index 0c7363e564dc..307414abf170 100644 --- a/nixos/modules/services/networking/kresd.nix +++ b/nixos/modules/services/networking/kresd.nix @@ -11,7 +11,7 @@ let mkListen = kind: addr: let al_v4 = builtins.match "([0-9.]+):([0-9]+)($)" addr; al_v6 = builtins.match "\\[(.+)]:([0-9]+)(%.*|$)" addr; - al_portOnly = builtins.match "([0-9]+)" addr; + al_portOnly = builtins.match "(^)([0-9]+)" addr; al = findFirst (a: a != null) (throw "services.kresd.*: incorrect address specification '${addr}'") [ al_v4 al_v6 al_portOnly ]; diff --git a/nixos/modules/services/networking/pyload.nix b/nixos/modules/services/networking/pyload.nix new file mode 100644 index 000000000000..f2b85499d4dd --- /dev/null +++ b/nixos/modules/services/networking/pyload.nix @@ -0,0 +1,147 @@ +{ config, lib, pkgs, utils, ... }: +let + cfg = config.services.pyload; + + stateDir = "/var/lib/pyload"; +in +{ + meta.maintainers = with lib.maintainers; [ ambroisie ]; + + options = with lib; { + services.pyload = { + enable = mkEnableOption "pyLoad download manager"; + + package = mkPackageOption pkgs "pyLoad" { default = [ "pyload-ng" ]; }; + + listenAddress = mkOption { + type = types.str; + default = "localhost"; + example = "0.0.0.0"; + description = "Address to listen on for the web UI."; + }; + + port = mkOption { + type = types.port; + default = 8000; + example = 9876; + description = "Port to listen on for the web UI."; + }; + + downloadDirectory = mkOption { + type = types.path; + default = "${stateDir}/downloads"; + example = "/mnt/downloads"; + description = "Directory to store downloads."; + }; + + credentialsFile = mkOption { + type = with types; nullOr path; + default = null; + example = "/run/secrets/pyload-credentials.env"; + description = '' + File containing {env}`PYLOAD_DEFAULT_USERNAME` and + {env}`PYLOAD_DEFAULT_PASSWORD` in the format of an `EnvironmentFile=`, + as described by {manpage}`systemd.exec(5)`. + + If not given, they default to the username/password combo of + pyload/pyload. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.tmpfiles.settings.pyload = { + ${cfg.downloadDirectory}.d = { }; + }; + + systemd.services.pyload = { + description = "pyLoad download manager"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + # NOTE: unlike what the documentation says, it looks like `HOME` is not + # defined with this service definition... + # Since pyload tries to do the equivalent of `cd ~`, it needs to be able + # to resolve $HOME, which fails when `RootDirectory` is set. + # FIXME: check if `SetLoginEnvironment` fixes this issue in version 255 + environment = { + HOME = stateDir; + PYLOAD__WEBUI__HOST = cfg.listenAddress; + PYLOAD__WEBUI__PORT = builtins.toString cfg.port; + }; + + serviceConfig = { + ExecStart = utils.escapeSystemdExecArgs [ + (lib.getExe cfg.package) + "--userdir" + "${stateDir}/config" + "--storagedir" + cfg.downloadDirectory + ]; + + User = "pyload"; + Group = "pyload"; + DynamicUser = true; + + EnvironmentFile = lib.optional (cfg.credentialsFile != null) cfg.credentialsFile; + + StateDirectory = "pyload"; + WorkingDirectory = stateDir; + RuntimeDirectory = "pyload"; + RuntimeDirectoryMode = "0700"; + RootDirectory = "/run/pyload"; + BindReadOnlyPaths = [ + builtins.storeDir # Needed to run the python interpreter + ]; + BindPaths = [ + cfg.downloadDirectory + ]; + + # Hardening options + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@resources" "~@privileged" ]; + UMask = "0002"; + CapabilityBoundingSet = [ + "~CAP_BLOCK_SUSPEND" + "~CAP_BPF" + "~CAP_CHOWN" + "~CAP_IPC_LOCK" + "~CAP_KILL" + "~CAP_LEASE" + "~CAP_LINUX_IMMUTABLE" + "~CAP_NET_ADMIN" + "~CAP_SYS_ADMIN" + "~CAP_SYS_BOOT" + "~CAP_SYS_CHROOT" + "~CAP_SYS_NICE" + "~CAP_SYS_PACCT" + "~CAP_SYS_PTRACE" + "~CAP_SYS_RESOURCE" + "~CAP_SYS_TTY_CONFIG" + ]; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/seafile.nix b/nixos/modules/services/networking/seafile.nix index 9caabc60c78f..b2d12234900a 100644 --- a/nixos/modules/services/networking/seafile.nix +++ b/nixos/modules/services/networking/seafile.nix @@ -32,7 +32,8 @@ let dataDir = "${seafRoot}/data"; seahubDir = "${seafRoot}/seahub"; -in { +in +{ ###### Interface @@ -147,146 +148,151 @@ in { description = "Seafile components"; }; - systemd.services = let - securityOptions = { - ProtectHome = true; - PrivateUsers = true; - PrivateDevices = true; - ProtectClock = true; - ProtectHostname = true; - ProtectProc = "invisible"; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectKernelLogs = true; - ProtectControlGroups = true; - RestrictNamespaces = true; - LockPersonality = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - MemoryDenyWriteExecute = true; - SystemCallArchitectures = "native"; - RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" ]; - }; - in { - seaf-server = { - description = "Seafile server"; - partOf = [ "seafile.target" ]; - after = [ "network.target" ]; - wantedBy = [ "seafile.target" ]; - restartTriggers = [ ccnetConf seafileConf ]; - path = [ pkgs.sqlite ]; - serviceConfig = securityOptions // { - User = "seafile"; - Group = "seafile"; - DynamicUser = true; - StateDirectory = "seafile"; - RuntimeDirectory = "seafile"; - LogsDirectory = "seafile"; - ConfigurationDirectory = "seafile"; - ExecStart = '' - ${cfg.seafilePackage}/bin/seaf-server \ - --foreground \ - -F /etc/seafile \ - -c ${ccnetDir} \ - -d ${dataDir} \ - -l /var/log/seafile/server.log \ - -P /run/seafile/server.pid \ - -p /run/seafile - ''; + systemd.services = + let + securityOptions = { + ProtectHome = true; + PrivateUsers = true; + PrivateDevices = true; + ProtectClock = true; + ProtectHostname = true; + ProtectProc = "invisible"; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictNamespaces = true; + LockPersonality = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + MemoryDenyWriteExecute = true; + SystemCallArchitectures = "native"; + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" ]; }; - preStart = '' - if [ ! -f "${seafRoot}/server-setup" ]; then - mkdir -p ${dataDir}/library-template - mkdir -p ${ccnetDir}/{GroupMgr,misc,OrgMgr,PeerMgr} - sqlite3 ${ccnetDir}/GroupMgr/groupmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/groupmgr.sql" - sqlite3 ${ccnetDir}/misc/config.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/config.sql" - sqlite3 ${ccnetDir}/OrgMgr/orgmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/org.sql" - sqlite3 ${ccnetDir}/PeerMgr/usermgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/user.sql" - sqlite3 ${dataDir}/seafile.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/seafile.sql" - echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup - fi - # checking for upgrades and handling them - # WARNING: needs to be extended to actually handle major version migrations - installedMajor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f1) - installedMinor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f2) - pkgMajor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f1) - pkgMinor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f2) - - if [[ $installedMajor == $pkgMajor && $installedMinor == $pkgMinor ]]; then - : - elif [[ $installedMajor == 8 && $installedMinor == 0 && $pkgMajor == 9 && $pkgMinor == 0 ]]; then - # Upgrade from 8.0 to 9.0 - sqlite3 ${dataDir}/seafile.db ".read ${pkgs.seahub}/scripts/upgrade/sql/9.0.0/sqlite3/seafile.sql" - echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup - else - echo "Unsupported upgrade" >&2 - exit 1 - fi - ''; - }; + in + { + seaf-server = { + description = "Seafile server"; + partOf = [ "seafile.target" ]; + after = [ "network.target" ]; + wantedBy = [ "seafile.target" ]; + restartTriggers = [ ccnetConf seafileConf ]; + path = [ pkgs.sqlite ]; + serviceConfig = securityOptions // { + User = "seafile"; + Group = "seafile"; + DynamicUser = true; + StateDirectory = "seafile"; + RuntimeDirectory = "seafile"; + LogsDirectory = "seafile"; + ConfigurationDirectory = "seafile"; + ExecStart = '' + ${cfg.seafilePackage}/bin/seaf-server \ + --foreground \ + -F /etc/seafile \ + -c ${ccnetDir} \ + -d ${dataDir} \ + -l /var/log/seafile/server.log \ + -P /run/seafile/server.pid \ + -p /run/seafile + ''; + }; + preStart = '' + if [ ! -f "${seafRoot}/server-setup" ]; then + mkdir -p ${dataDir}/library-template + mkdir -p ${ccnetDir}/{GroupMgr,misc,OrgMgr,PeerMgr} + sqlite3 ${ccnetDir}/GroupMgr/groupmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/groupmgr.sql" + sqlite3 ${ccnetDir}/misc/config.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/config.sql" + sqlite3 ${ccnetDir}/OrgMgr/orgmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/org.sql" + sqlite3 ${ccnetDir}/PeerMgr/usermgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/user.sql" + sqlite3 ${dataDir}/seafile.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/seafile.sql" + echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup + fi + # checking for upgrades and handling them + installedMajor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f1) + installedMinor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f2) + pkgMajor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f1) + pkgMinor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f2) - seahub = { - description = "Seafile Server Web Frontend"; - wantedBy = [ "seafile.target" ]; - partOf = [ "seafile.target" ]; - after = [ "network.target" "seaf-server.service" ]; - requires = [ "seaf-server.service" ]; - restartTriggers = [ seahubSettings ]; - environment = { - PYTHONPATH = "${pkgs.seahub.pythonPath}:${pkgs.seahub}/thirdpart:${pkgs.seahub}"; - DJANGO_SETTINGS_MODULE = "seahub.settings"; - CCNET_CONF_DIR = ccnetDir; - SEAFILE_CONF_DIR = dataDir; - SEAFILE_CENTRAL_CONF_DIR = "/etc/seafile"; - SEAFILE_RPC_PIPE_PATH = "/run/seafile"; - SEAHUB_LOG_DIR = "/var/log/seafile"; + if [[ $installedMajor == $pkgMajor && $installedMinor == $pkgMinor ]]; then + : + elif [[ $installedMajor == 8 && $installedMinor == 0 && $pkgMajor == 9 && $pkgMinor == 0 ]]; then + # Upgrade from 8.0 to 9.0 + sqlite3 ${dataDir}/seafile.db ".read ${pkgs.seahub}/scripts/upgrade/sql/9.0.0/sqlite3/seafile.sql" + echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup + elif [[ $installedMajor == 9 && $installedMinor == 0 && $pkgMajor == 10 && $pkgMinor == 0 ]]; then + # Upgrade from 9.0 to 10.0 + sqlite3 ${dataDir}/seafile.db ".read ${pkgs.seahub}/scripts/upgrade/sql/10.0.0/sqlite3/seafile.sql" + echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup + else + echo "Unsupported upgrade" >&2 + exit 1 + fi + ''; }; - serviceConfig = securityOptions // { - User = "seafile"; - Group = "seafile"; - DynamicUser = true; - RuntimeDirectory = "seahub"; - StateDirectory = "seafile"; - LogsDirectory = "seafile"; - ConfigurationDirectory = "seafile"; - ExecStart = '' - ${pkgs.seahub.python.pkgs.gunicorn}/bin/gunicorn seahub.wsgi:application \ - --name seahub \ - --workers ${toString cfg.workers} \ - --log-level=info \ - --preload \ - --timeout=1200 \ - --limit-request-line=8190 \ - --bind unix:/run/seahub/gunicorn.sock + + seahub = { + description = "Seafile Server Web Frontend"; + wantedBy = [ "seafile.target" ]; + partOf = [ "seafile.target" ]; + after = [ "network.target" "seaf-server.service" ]; + requires = [ "seaf-server.service" ]; + restartTriggers = [ seahubSettings ]; + environment = { + PYTHONPATH = "${pkgs.seahub.pythonPath}:${pkgs.seahub}/thirdpart:${pkgs.seahub}"; + DJANGO_SETTINGS_MODULE = "seahub.settings"; + CCNET_CONF_DIR = ccnetDir; + SEAFILE_CONF_DIR = dataDir; + SEAFILE_CENTRAL_CONF_DIR = "/etc/seafile"; + SEAFILE_RPC_PIPE_PATH = "/run/seafile"; + SEAHUB_LOG_DIR = "/var/log/seafile"; + }; + serviceConfig = securityOptions // { + User = "seafile"; + Group = "seafile"; + DynamicUser = true; + RuntimeDirectory = "seahub"; + StateDirectory = "seafile"; + LogsDirectory = "seafile"; + ConfigurationDirectory = "seafile"; + ExecStart = '' + ${pkgs.seahub.python.pkgs.gunicorn}/bin/gunicorn seahub.wsgi:application \ + --name seahub \ + --workers ${toString cfg.workers} \ + --log-level=info \ + --preload \ + --timeout=1200 \ + --limit-request-line=8190 \ + --bind unix:/run/seahub/gunicorn.sock + ''; + }; + preStart = '' + mkdir -p ${seahubDir}/media + # Link all media except avatars + for m in `find ${pkgs.seahub}/media/ -maxdepth 1 -not -name "avatars"`; do + ln -sf $m ${seahubDir}/media/ + done + if [ ! -e "${seafRoot}/.seahubSecret" ]; then + ${pkgs.seahub.python}/bin/python ${pkgs.seahub}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret + chmod 400 ${seafRoot}/.seahubSecret + fi + if [ ! -f "${seafRoot}/seahub-setup" ]; then + # avatars directory should be writable + install -D -t ${seahubDir}/media/avatars/ ${pkgs.seahub}/media/avatars/default.png + install -D -t ${seahubDir}/media/avatars/groups ${pkgs.seahub}/media/avatars/groups/default.png + # init database + ${pkgs.seahub}/manage.py migrate + # create admin account + ${pkgs.expect}/bin/expect -c 'spawn ${pkgs.seahub}/manage.py createsuperuser --email=${cfg.adminEmail}; expect "Password: "; send "${cfg.initialAdminPassword}\r"; expect "Password (again): "; send "${cfg.initialAdminPassword}\r"; expect "Superuser created successfully."' + echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup" + fi + if [ $(cat "${seafRoot}/seahub-setup" | cut -d"-" -f1) != "${pkgs.seahub.version}" ]; then + # update database + ${pkgs.seahub}/manage.py migrate + echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup" + fi ''; }; - preStart = '' - mkdir -p ${seahubDir}/media - # Link all media except avatars - for m in `find ${pkgs.seahub}/media/ -maxdepth 1 -not -name "avatars"`; do - ln -sf $m ${seahubDir}/media/ - done - if [ ! -e "${seafRoot}/.seahubSecret" ]; then - ${pkgs.seahub.python}/bin/python ${pkgs.seahub}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret - chmod 400 ${seafRoot}/.seahubSecret - fi - if [ ! -f "${seafRoot}/seahub-setup" ]; then - # avatars directory should be writable - install -D -t ${seahubDir}/media/avatars/ ${pkgs.seahub}/media/avatars/default.png - install -D -t ${seahubDir}/media/avatars/groups ${pkgs.seahub}/media/avatars/groups/default.png - # init database - ${pkgs.seahub}/manage.py migrate - # create admin account - ${pkgs.expect}/bin/expect -c 'spawn ${pkgs.seahub}/manage.py createsuperuser --email=${cfg.adminEmail}; expect "Password: "; send "${cfg.initialAdminPassword}\r"; expect "Password (again): "; send "${cfg.initialAdminPassword}\r"; expect "Superuser created successfully."' - echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup" - fi - if [ $(cat "${seafRoot}/seahub-setup" | cut -d"-" -f1) != "${pkgs.seahub.version}" ]; then - # update database - ${pkgs.seahub}/manage.py migrate - echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup" - fi - ''; }; - }; }; } diff --git a/nixos/modules/services/networking/strongswan-swanctl/module.nix b/nixos/modules/services/networking/strongswan-swanctl/module.nix index a98850923955..c1f0aeb64e96 100644 --- a/nixos/modules/services/networking/strongswan-swanctl/module.nix +++ b/nixos/modules/services/networking/strongswan-swanctl/module.nix @@ -5,6 +5,9 @@ with (import ./param-lib.nix lib); let cfg = config.services.strongswan-swanctl; + configFile = pkgs.writeText "swanctl.conf" + ( (paramsToConf cfg.swanctl swanctlParams) + + (concatMapStrings (i: "\ninclude ${i}") cfg.includes)); swanctlParams = import ./swanctl-params.nix lib; in { options.services.strongswan-swanctl = { @@ -21,6 +24,13 @@ in { }; swanctl = paramsToOptions swanctlParams; + includes = mkOption { + type = types.listOf types.path; + default = []; + description = '' + Extra configuration files to include in the swanctl configuration. This can be used to provide secret values from outside the nix store. + ''; + }; }; config = mkIf cfg.enable { @@ -31,8 +41,7 @@ in { } ]; - environment.etc."swanctl/swanctl.conf".text = - paramsToConf cfg.swanctl swanctlParams; + environment.etc."swanctl/swanctl.conf".source = configFile; # The swanctl command complains when the following directories don't exist: # See: https://wiki.strongswan.org/projects/strongswan/wiki/Swanctldirectory diff --git a/nixos/modules/services/security/bitwarden-directory-connector-cli.nix b/nixos/modules/services/security/bitwarden-directory-connector-cli.nix index 18c02e22fd7e..a55758322a75 100644 --- a/nixos/modules/services/security/bitwarden-directory-connector-cli.nix +++ b/nixos/modules/services/security/bitwarden-directory-connector-cli.nix @@ -277,42 +277,42 @@ in { BITWARDENCLI_CONNECTOR_PLAINTEXT_SECRETS = "true"; }; + preStart = '' + set -eo pipefail + + # create the config file + ${lib.getExe cfg.package} data-file + touch /tmp/data.json.tmp + chmod 600 /tmp/data.json{,.tmp} + + ${lib.getExe cfg.package} config server ${cfg.domain} + + # now login to set credentials + export BW_CLIENTID="$(< ${escapeShellArg cfg.secrets.bitwarden.client_path_id})" + export BW_CLIENTSECRET="$(< ${escapeShellArg cfg.secrets.bitwarden.client_path_secret})" + ${lib.getExe cfg.package} login + + jq '.authenticatedAccounts[0] as $account + | .[$account].directoryConfigurations.ldap |= $ldap_data + | .[$account].directorySettings.organizationId |= $orgID + | .[$account].directorySettings.sync |= $sync_data' \ + --argjson ldap_data ${escapeShellArg cfg.ldap.finalJSON} \ + --arg orgID "''${BW_CLIENTID//organization.}" \ + --argjson sync_data ${escapeShellArg cfg.sync.finalJSON} \ + /tmp/data.json \ + > /tmp/data.json.tmp + + mv -f /tmp/data.json.tmp /tmp/data.json + + # final config + ${lib.getExe cfg.package} config directory 0 + ${lib.getExe cfg.package} config ldap.password --secretfile ${cfg.secrets.ldap} + ''; + serviceConfig = { Type = "oneshot"; User = "${cfg.user}"; PrivateTmp = true; - preStart = '' - set -eo pipefail - - # create the config file - ${lib.getExe cfg.package} data-file - touch /tmp/data.json.tmp - chmod 600 /tmp/data.json{,.tmp} - - ${lib.getExe cfg.package} config server ${cfg.domain} - - # now login to set credentials - export BW_CLIENTID="$(< ${escapeShellArg cfg.secrets.bitwarden.client_path_id})" - export BW_CLIENTSECRET="$(< ${escapeShellArg cfg.secrets.bitwarden.client_path_secret})" - ${lib.getExe cfg.package} login - - jq '.authenticatedAccounts[0] as $account - | .[$account].directoryConfigurations.ldap |= $ldap_data - | .[$account].directorySettings.organizationId |= $orgID - | .[$account].directorySettings.sync |= $sync_data' \ - --argjson ldap_data ${escapeShellArg cfg.ldap.finalJSON} \ - --arg orgID "''${BW_CLIENTID//organization.}" \ - --argjson sync_data ${escapeShellArg cfg.sync.finalJSON} \ - /tmp/data.json \ - > /tmp/data.json.tmp - - mv -f /tmp/data.json.tmp /tmp/data.json - - # final config - ${lib.getExe cfg.package} config directory 0 - ${lib.getExe cfg.package} config ldap.password --secretfile ${cfg.secrets.ldap} - ''; - ExecStart = "${lib.getExe cfg.package} sync"; }; }; diff --git a/nixos/modules/services/system/systemd-lock-handler.md b/nixos/modules/services/system/systemd-lock-handler.md new file mode 100644 index 000000000000..ac9ee00ae4bc --- /dev/null +++ b/nixos/modules/services/system/systemd-lock-handler.md @@ -0,0 +1,47 @@ +# systemd-lock-handler {#module-services-systemd-lock-handler} + +The `systemd-lock-handler` module provides a service that bridges +D-Bus events from `logind` to user-level systemd targets: + + - `lock.target` started by `loginctl lock-session`, + - `unlock.target` started by `loginctl unlock-session` and + - `sleep.target` started by `systemctl suspend`. + +You can create a user service that starts with any of these targets. + +For example, to create a service for `swaylock`: + +```nix +{ + services.systemd-lock-handler.enable = true; + + systemd.user.services.swaylock = { + description = "Screen locker for Wayland"; + documentation = ["man:swaylock(1)"]; + + # If swaylock exits cleanly, unlock the session: + onSuccess = ["unlock.target"]; + + # When lock.target is stopped, stops this too: + partOf = ["lock.target"]; + + # Delay lock.target until this service is ready: + before = ["lock.target"]; + wantedBy = ["lock.target"]; + + serviceConfig = { + # systemd will consider this service started when swaylock forks... + Type = "forking"; + + # ... and swaylock will fork only after it has locked the screen. + ExecStart = "${lib.getExe pkgs.swaylock} -f"; + + # If swaylock crashes, always restart it immediately: + Restart = "on-failure"; + RestartSec = 0; + }; + }; +} +``` + +See [upstream documentation](https://sr.ht/~whynothugo/systemd-lock-handler) for more information. diff --git a/nixos/modules/services/system/systemd-lock-handler.nix b/nixos/modules/services/system/systemd-lock-handler.nix new file mode 100644 index 000000000000..1ecb13b75bb3 --- /dev/null +++ b/nixos/modules/services/system/systemd-lock-handler.nix @@ -0,0 +1,27 @@ +{ config +, pkgs +, lib +, ... +}: +let + cfg = config.services.systemd-lock-handler; + inherit (lib) mkIf mkEnableOption mkPackageOption; +in +{ + options.services.systemd-lock-handler = { + enable = mkEnableOption (lib.mdDoc "systemd-lock-handler"); + package = mkPackageOption pkgs "systemd-lock-handler" { }; + }; + + config = mkIf cfg.enable { + systemd.packages = [ cfg.package ]; + + # https://github.com/NixOS/nixpkgs/issues/81138 + systemd.user.services.systemd-lock-handler.wantedBy = [ "default.target" ]; + }; + + meta = { + maintainers = with lib.maintainers; [ liff ]; + doc = ./systemd-lock-handler.md; + }; +} diff --git a/nixos/modules/services/web-apps/lemmy.nix b/nixos/modules/services/web-apps/lemmy.nix index bde9051a7033..968dcac93fab 100644 --- a/nixos/modules/services/web-apps/lemmy.nix +++ b/nixos/modules/services/web-apps/lemmy.nix @@ -204,7 +204,6 @@ in }; "/" = { # mixed frontend and backend requests, based on the request headers - proxyPass = "$proxpass"; recommendedProxySettings = true; extraConfig = '' set $proxpass "${ui}"; @@ -220,6 +219,8 @@ in # Cuts off the trailing slash on URLs to make them valid rewrite ^(.+)/+$ $1 permanent; + + proxy_pass $proxpass; ''; }; }; diff --git a/nixos/modules/services/web-apps/mastodon.nix b/nixos/modules/services/web-apps/mastodon.nix index 538e728fcc72..8d09d1b97828 100644 --- a/nixos/modules/services/web-apps/mastodon.nix +++ b/nixos/modules/services/web-apps/mastodon.nix @@ -133,6 +133,7 @@ let RestartSec = 20; EnvironmentFile = [ "/var/lib/mastodon/.secrets_env" ] ++ cfg.extraEnvFiles; WorkingDirectory = cfg.package; + LimitNOFILE = "1024000"; # System Call Filtering SystemCallFilter = [ ("~" + lib.concatStringsSep " " systemCallsList) "@chown" "pipe" "pipe2" ]; } // cfgService; diff --git a/nixos/modules/services/web-apps/nextcloud-notify_push.nix b/nixos/modules/services/web-apps/nextcloud-notify_push.nix index 759daa0c50dc..7b90e0bbaa9b 100644 --- a/nixos/modules/services/web-apps/nextcloud-notify_push.nix +++ b/nixos/modules/services/web-apps/nextcloud-notify_push.nix @@ -116,7 +116,7 @@ in } (lib.mkIf cfg.bendDomainToLocalhost { - nextcloud.extraOptions.trusted_proxies = [ "127.0.0.1" "::1" ]; + nextcloud.settings.trusted_proxies = [ "127.0.0.1" "::1" ]; }) ]; }; diff --git a/nixos/modules/services/web-apps/nextcloud.md b/nixos/modules/services/web-apps/nextcloud.md index ce8f96a6a389..5db83d7e4463 100644 --- a/nixos/modules/services/web-apps/nextcloud.md +++ b/nixos/modules/services/web-apps/nextcloud.md @@ -51,7 +51,7 @@ to ensure that changes can be applied by changing the module's options. In case the application serves multiple domains (those are checked with [`$_SERVER['HTTP_HOST']`](https://www.php.net/manual/en/reserved.variables.server.php)) it's needed to add them to -[`services.nextcloud.extraOptions.trusted_domains`](#opt-services.nextcloud.extraOptions.trusted_domains). +[`services.nextcloud.settings.trusted_domains`](#opt-services.nextcloud.settings.trusted_domains). Auto updates for Nextcloud apps can be enabled using [`services.nextcloud.autoUpdateApps`](#opt-services.nextcloud.autoUpdateApps.enable). diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index 0b19265942c0..8669f84b1cbb 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -183,8 +183,8 @@ let ]; $CONFIG = array_replace_recursive($CONFIG, nix_decode_json_file( - "${jsonFormat.generate "nextcloud-extraOptions.json" cfg.extraOptions}", - "impossible: this should never happen (decoding generated extraOptions file %s failed)" + "${jsonFormat.generate "nextcloud-settings.json" cfg.settings}", + "impossible: this should never happen (decoding generated settings file %s failed)" )); ${optionalString (cfg.secretFile != null) '' @@ -205,21 +205,22 @@ in { Add port to services.nextcloud.config.dbhost instead. '') (mkRenamedOptionModule - [ "services" "nextcloud" "logLevel" ] [ "services" "nextcloud" "extraOptions" "loglevel" ]) + [ "services" "nextcloud" "logLevel" ] [ "services" "nextcloud" "settings" "loglevel" ]) (mkRenamedOptionModule - [ "services" "nextcloud" "logType" ] [ "services" "nextcloud" "extraOptions" "log_type" ]) + [ "services" "nextcloud" "logType" ] [ "services" "nextcloud" "settings" "log_type" ]) (mkRenamedOptionModule - [ "services" "nextcloud" "config" "defaultPhoneRegion" ] [ "services" "nextcloud" "extraOptions" "default_phone_region" ]) + [ "services" "nextcloud" "config" "defaultPhoneRegion" ] [ "services" "nextcloud" "settings" "default_phone_region" ]) (mkRenamedOptionModule - [ "services" "nextcloud" "config" "overwriteProtocol" ] [ "services" "nextcloud" "extraOptions" "overwriteprotocol" ]) + [ "services" "nextcloud" "config" "overwriteProtocol" ] [ "services" "nextcloud" "settings" "overwriteprotocol" ]) (mkRenamedOptionModule - [ "services" "nextcloud" "skeletonDirectory" ] [ "services" "nextcloud" "extraOptions" "skeletondirectory" ]) + [ "services" "nextcloud" "skeletonDirectory" ] [ "services" "nextcloud" "settings" "skeletondirectory" ]) (mkRenamedOptionModule - [ "services" "nextcloud" "globalProfiles" ] [ "services" "nextcloud" "extraOptions" "profile.enabled" ]) + [ "services" "nextcloud" "globalProfiles" ] [ "services" "nextcloud" "settings" "profile.enabled" ]) (mkRenamedOptionModule - [ "services" "nextcloud" "config" "extraTrustedDomains" ] [ "services" "nextcloud" "extraOptions" "trusted_domains" ]) + [ "services" "nextcloud" "config" "extraTrustedDomains" ] [ "services" "nextcloud" "settings" "trusted_domains" ]) (mkRenamedOptionModule - [ "services" "nextcloud" "config" "trustedProxies" ] [ "services" "nextcloud" "extraOptions" "trusted_proxies" ]) + [ "services" "nextcloud" "config" "trustedProxies" ] [ "services" "nextcloud" "settings" "trusted_proxies" ]) + (mkRenamedOptionModule ["services" "nextcloud" "extraOptions" ] [ "services" "nextcloud" "settings" ]) ]; options.services.nextcloud = { @@ -648,7 +649,7 @@ in { ''; }; - extraOptions = mkOption { + settings = mkOption { type = types.submodule { freeformType = jsonFormat.type; options = { @@ -770,7 +771,7 @@ in { default = null; description = lib.mdDoc '' Secret options which will be appended to Nextcloud's config.php file (written as JSON, in the same - form as the [](#opt-services.nextcloud.extraOptions) option), for example + form as the [](#opt-services.nextcloud.settings) option), for example `{"redis":{"password":"secret"}}`. ''; }; @@ -930,7 +931,7 @@ in { (i: v: '' ${occ}/bin/nextcloud-occ config:system:set trusted_domains \ ${toString i} --value="${toString v}" - '') ([ cfg.hostName ] ++ cfg.extraOptions.trusted_domains)); + '') ([ cfg.hostName ] ++ cfg.settings.trusted_domains)); in { wantedBy = [ "multi-user.target" ]; @@ -1056,7 +1057,7 @@ in { services.nextcloud = { caching.redis = lib.mkIf cfg.configureRedis true; - extraOptions = mkMerge [({ + settings = mkMerge [({ datadirectory = lib.mkDefault "${datadir}/data"; trusted_domains = [ cfg.hostName ]; }) (lib.mkIf cfg.configureRedis { diff --git a/nixos/modules/services/web-apps/photoprism.nix b/nixos/modules/services/web-apps/photoprism.nix index e25b03484424..1716840e84e5 100644 --- a/nixos/modules/services/web-apps/photoprism.nix +++ b/nixos/modules/services/web-apps/photoprism.nix @@ -18,6 +18,9 @@ let in pkgs.writeShellScript "manage" '' ${setupEnv} + eval "$(${config.systemd.package}/bin/systemctl show -pUID,MainPID photoprism.service | ${pkgs.gnused}/bin/sed "s/UID/ServiceUID/")" + exec ${pkgs.util-linux}/bin/nsenter \ + -t $MainPID -m -S $ServiceUID -G $ServiceUID --wdns=${cfg.storagePath} \ exec ${cfg.package}/bin/photoprism "$@" ''; in diff --git a/nixos/modules/services/web-apps/pretalx.nix b/nixos/modules/services/web-apps/pretalx.nix new file mode 100644 index 000000000000..ff6218112d2f --- /dev/null +++ b/nixos/modules/services/web-apps/pretalx.nix @@ -0,0 +1,415 @@ +{ config +, lib +, pkgs +, utils +, ... +}: + +let + cfg = config.services.pretalx; + format = pkgs.formats.ini { }; + + configFile = format.generate "pretalx.cfg" cfg.settings; + + extras = cfg.package.optional-dependencies.redis + ++ lib.optionals (cfg.settings.database.backend == "mysql") cfg.package.optional-dependencies.mysql + ++ lib.optionals (cfg.settings.database.backend == "postgresql") cfg.package.optional-dependencies.postgres; + + pythonEnv = cfg.package.python.buildEnv.override { + extraLibs = [ (cfg.package.python.pkgs.toPythonModule cfg.package) ] + ++ (with cfg.package.python.pkgs; [ gunicorn ] + ++ lib.optional cfg.celery.enable celery) ++ extras; + }; +in + +{ + meta = with lib; { + maintainers = teams.c3d2.members; + }; + + options.services.pretalx = { + enable = lib.mkEnableOption (lib.mdDoc "pretalx"); + + package = lib.mkPackageOptionMD pkgs "pretalx" {}; + + group = lib.mkOption { + type = lib.types.str; + default = "pretalx"; + description = "Group under which pretalx should run."; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "pretalx"; + description = "User under which pretalx should run."; + }; + + gunicorn.extraArgs = lib.mkOption { + type = with lib.types; listOf str; + default = [ + "--name=pretalx" + ]; + example = [ + "--name=pretalx" + "--workers=4" + "--max-requests=1200" + "--max-requests-jitter=50" + "--log-level=info" + ]; + description = lib.mdDoc '' + Extra arguments to pass to gunicorn. + See <https://docs.pretalx.org/administrator/installation.html#step-6-starting-pretalx-as-a-service> for details. + ''; + apply = lib.escapeShellArgs; + }; + + celery = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + example = false; + description = lib.mdDoc '' + Whether to set up celery as an asynchronous task runner. + ''; + }; + + extraArgs = lib.mkOption { + type = with lib.types; listOf str; + default = [ ]; + description = lib.mdDoc '' + Extra arguments to pass to celery. + + See <https://docs.celeryq.dev/en/stable/reference/cli.html#celery-worker> for more info. + ''; + apply = utils.escapeSystemdExecArgs; + }; + }; + + nginx = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + example = false; + description = lib.mdDoc '' + Whether to set up an nginx virtual host. + ''; + }; + + domain = lib.mkOption { + type = lib.types.str; + example = "talks.example.com"; + description = lib.mdDoc '' + The domain name under which to set up the virtual host. + ''; + }; + }; + + database.createLocally = lib.mkOption { + type = lib.types.bool; + default = true; + example = false; + description = lib.mdDoc '' + Whether to automatically set up the database on the local DBMS instance. + + Currently only supported for PostgreSQL. Not required for sqlite. + ''; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = format.type; + options = { + database = { + backend = lib.mkOption { + type = lib.types.enum [ + "postgresql" + ]; + default = "postgresql"; + description = lib.mdDoc '' + Database backend to use. + + Currently only PostgreSQL gets tested, and as such we don't support any other DBMS. + ''; + readOnly = true; # only postgres supported right now + }; + + host = lib.mkOption { + type = with lib.types; nullOr types.path; + default = if cfg.settings.database.backend == "postgresql" then "/run/postgresql" + else if cfg.settings.database.backend == "mysql" then "/run/mysqld/mysqld.sock" + else null; + defaultText = lib.literalExpression '' + if config.services.pretalx.settings..database.backend == "postgresql" then "/run/postgresql" + else if config.services.pretalx.settings.database.backend == "mysql" then "/run/mysqld/mysqld.sock" + else null + ''; + description = lib.mdDoc '' + Database host or socket path. + ''; + }; + + name = lib.mkOption { + type = lib.types.str; + default = "pretalx"; + description = lib.mdDoc '' + Database name. + ''; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "pretalx"; + description = lib.mdDoc '' + Database username. + ''; + }; + }; + + filesystem = { + data = lib.mkOption { + type = lib.types.path; + default = "/var/lib/pretalx"; + description = lib.mdDoc '' + Base path for all other storage paths. + ''; + }; + logs = lib.mkOption { + type = lib.types.path; + default = "/var/log/pretalx"; + description = lib.mdDoc '' + Path to the log directory, that pretalx logs message to. + ''; + }; + static = lib.mkOption { + type = lib.types.path; + default = "${cfg.package.static}/"; + defaultText = lib.literalExpression "\${config.services.pretalx.package}.static}/"; + readOnly = true; + description = lib.mdDoc '' + Path to the directory that contains static files. + ''; + }; + }; + + celery = { + backend = lib.mkOption { + type = with lib.types; nullOr str; + default = lib.optionalString cfg.celery.enable "redis+socket://${config.services.redis.servers.pretalx.unixSocket}?virtual_host=1"; + defaultText = lib.literalExpression '' + optionalString config.services.pretalx.celery.enable "redis+socket://''${config.services.redis.servers.pretalx.unixSocket}?virtual_host=1" + ''; + description = lib.mdDoc '' + URI to the celery backend used for the asynchronous job queue. + ''; + }; + + broker = lib.mkOption { + type = with lib.types; nullOr str; + default = lib.optionalString cfg.celery.enable "redis+socket://${config.services.redis.servers.pretalx.unixSocket}?virtual_host=2"; + defaultText = lib.literalExpression '' + optionalString config.services.pretalx.celery.enable "redis+socket://''${config.services.redis.servers.pretalx.unixSocket}?virtual_host=2" + ''; + description = lib.mdDoc '' + URI to the celery broker used for the asynchronous job queue. + ''; + }; + }; + + redis = { + location = lib.mkOption { + type = with lib.types; nullOr str; + default = "unix://${config.services.redis.servers.pretalx.unixSocket}?db=0"; + defaultText = lib.literalExpression '' + "unix://''${config.services.redis.servers.pretalx.unixSocket}?db=0" + ''; + description = lib.mdDoc '' + URI to the redis server, used to speed up locking, caching and session storage. + ''; + }; + + session = lib.mkOption { + type = lib.types.bool; + default = true; + example = false; + description = lib.mdDoc '' + Whether to use redis as the session storage. + ''; + }; + }; + + site = { + url = lib.mkOption { + type = lib.types.str; + default = "https://${cfg.nginx.domain}"; + defaultText = lib.literalExpression "https://\${config.services.pretalx.nginx.domain}"; + example = "https://talks.example.com"; + description = lib.mdDoc '' + The base URI below which your pretalx instance will be reachable. + ''; + }; + }; + }; + }; + default = { }; + description = lib.mdDoc '' + pretalx configuration as a Nix attribute set. All settings can also be passed + from the environment. + + See <https://docs.pretalx.org/administrator/configure.html> for possible options. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + # https://docs.pretalx.org/administrator/installation.html + + environment.systemPackages = [ + (pkgs.writeScriptBin "pretalx-manage" '' + cd ${cfg.settings.filesystem.data} + sudo=exec + if [[ "$USER" != ${cfg.user} ]]; then + sudo='exec /run/wrappers/bin/sudo -u ${cfg.user} --preserve-env=PRETALX_CONFIG_FILE' + fi + export PRETALX_CONFIG_FILE=${configFile} + $sudo ${lib.getExe' pythonEnv "pretalx-manage"} "$@" + '') + ]; + + services = { + nginx = lib.mkIf cfg.nginx.enable { + enable = true; + recommendedGzipSettings = lib.mkDefault true; + recommendedOptimisation = lib.mkDefault true; + recommendedProxySettings = lib.mkDefault true; + recommendedTlsSettings = lib.mkDefault true; + upstreams.pretalx.servers."unix:/run/pretalx/pretalx.sock" = { }; + virtualHosts.${cfg.nginx.domain} = { + # https://docs.pretalx.org/administrator/installation.html#step-7-ssl + extraConfig = '' + more_set_headers Referrer-Policy same-origin; + more_set_headers X-Content-Type-Options nosniff; + ''; + locations = { + "/".proxyPass = "http://pretalx"; + "/media/" = { + alias = "${cfg.settings.filesystem.data}/data/media/"; + extraConfig = '' + access_log off; + more_set_headers Content-Disposition 'attachment; filename="$1"'; + expires 7d; + ''; + }; + "/static/" = { + alias = cfg.settings.filesystem.static; + extraConfig = '' + access_log off; + more_set_headers Cache-Control "public"; + expires 365d; + ''; + }; + }; + }; + }; + + postgresql = lib.mkIf (cfg.database.createLocally && cfg.settings.database.backend == "postgresql") { + enable = true; + ensureUsers = [ { + name = cfg.settings.database.user; + ensureDBOwnership = true; + } ]; + ensureDatabases = [ cfg.settings.database.name ]; + }; + + redis.servers.pretalx.enable = true; + }; + + systemd.services = let + commonUnitConfig = { + environment.PRETALX_CONFIG_FILE = configFile; + serviceConfig = { + User = "pretalx"; + Group = "pretalx"; + StateDirectory = [ "pretalx" "pretalx/media" ]; + LogsDirectory = "pretalx"; + WorkingDirectory = cfg.settings.filesystem.data; + SupplementaryGroups = [ "redis-pretalx" ]; + }; + }; + in { + pretalx-web = lib.recursiveUpdate commonUnitConfig { + description = "pretalx web service"; + after = [ + "network.target" + "redis-pretalx.service" + ] ++ lib.optionals (cfg.settings.database.backend == "postgresql") [ + "postgresql.service" + ] ++ lib.optionals (cfg.settings.database.backend == "mysql") [ + "mysql.service" + ]; + wantedBy = [ "multi-user.target" ]; + preStart = '' + versionFile="${cfg.settings.filesystem.data}/.version" + version=$(cat "$versionFile" 2>/dev/null || echo 0) + + if [[ $version != ${cfg.package.version} ]]; then + ${lib.getExe' pythonEnv "pretalx-manage"} migrate + + echo "${cfg.package.version}" > "$versionFile" + fi + ''; + serviceConfig = { + ExecStart = "${lib.getExe' pythonEnv "gunicorn"} --bind unix:/run/pretalx/pretalx.sock ${cfg.gunicorn.extraArgs} pretalx.wsgi"; + RuntimeDirectory = "pretalx"; + }; + }; + + pretalx-periodic = lib.recursiveUpdate commonUnitConfig { + description = "pretalx periodic task runner"; + # every 15 minutes + startAt = [ "*:3,18,33,48" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${lib.getExe' pythonEnv "pretalx-manage"} runperiodic"; + }; + }; + + pretalx-clear-sessions = lib.recursiveUpdate commonUnitConfig { + description = "pretalx session pruning"; + startAt = [ "monthly" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${lib.getExe' pythonEnv "pretalx-manage"} clearsessions"; + }; + }; + + pretalx-worker = lib.mkIf cfg.celery.enable (lib.recursiveUpdate commonUnitConfig { + description = "pretalx asynchronous job runner"; + after = [ + "network.target" + "redis-pretalx.service" + ] ++ lib.optionals (cfg.settings.database.backend == "postgresql") [ + "postgresql.service" + ] ++ lib.optionals (cfg.settings.database.backend == "mysql") [ + "mysql.service" + ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig.ExecStart = "${lib.getExe' pythonEnv "celery"} -A pretalx.celery_app worker ${cfg.celery.extraArgs}"; + }); + }; + + systemd.sockets.pretalx-web.socketConfig = { + ListenStream = "/run/pretalx/pretalx.sock"; + SocketUser = "nginx"; + }; + + users = { + groups."${cfg.group}" = {}; + users."${cfg.user}" = { + isSystemUser = true; + createHome = true; + home = cfg.settings.filesystem.data; + inherit (cfg) group; + }; + }; + }; +} diff --git a/nixos/modules/services/web-apps/youtrack.md b/nixos/modules/services/web-apps/youtrack.md new file mode 100644 index 000000000000..f33f482ff970 --- /dev/null +++ b/nixos/modules/services/web-apps/youtrack.md @@ -0,0 +1,30 @@ +# YouTrack {#module-services-youtrack} + +YouTrack is a browser-based bug tracker, issue tracking system and project management software. + +## Installation {#module-services-youtrack-installation} + +YouTrack exposes a web GUI installer on first login. +You need a token to access it. +You can find this token in the log of the `youtrack` service. The log line looks like +``` +* JetBrains YouTrack 2023.3 Configuration Wizard will be available on [http://127.0.0.1:8090/?wizard_token=somelongtoken] after start +``` + +## Upgrade from 2022.3 to 2023.x {#module-services-youtrack-upgrade-2022_3-2023_1} + +Starting with YouTrack 2023.1, JetBrains no longer distributes it as as JAR. +The new distribution with the JetBrains Launcher as a ZIP changed the basic data structure and also some configuration parameters. +Check out https://www.jetbrains.com/help/youtrack/server/YouTrack-Java-Start-Parameters.html for more information on the new configuration options. +When upgrading to YouTrack 2023.1 or higher, a migration script will move the old state directory to `/var/lib/youtrack/2022_3` as a backup. +A one-time manual update is required: + +1. Before you update take a backup of your YouTrack instance! +2. Migrate the options you set in `services.youtrack.extraParams` and `services.youtrack.jvmOpts` to `services.youtrack.generalParameters` and `services.youtrack.environmentalParameters` (see the examples and [the YouTrack docs](https://www.jetbrains.com/help/youtrack/server/2023.3/YouTrack-Java-Start-Parameters.html)) +2. To start the upgrade set `services.youtrack.package = pkgs.youtrack` +3. YouTrack then starts in upgrade mode, meaning you need to obtain the wizard token as above +4. Select you want to **Upgrade** YouTrack +5. As source you select `/var/lib/youtrack/2022_3/teamsysdata/` (adopt if you have a different state path) +6. Change the data directory location to `/var/lib/youtrack/data/`. The other paths should already be right. + +If you migrate a larger YouTrack instance, it might be useful to set `-Dexodus.entityStore.refactoring.forceAll=true` in `services.youtrack.generalParameters` for the first startup of YouTrack 2023.x. diff --git a/nixos/modules/services/web-apps/youtrack.nix b/nixos/modules/services/web-apps/youtrack.nix index 79e1d12e0abb..abb4292113b6 100644 --- a/nixos/modules/services/web-apps/youtrack.nix +++ b/nixos/modules/services/web-apps/youtrack.nix @@ -1,130 +1,224 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.youtrack; - - extraAttr = concatStringsSep " " (mapAttrsToList (k: v: "-D${k}=${v}") (stdParams // cfg.extraParams)); - mergeAttrList = lib.foldl' lib.mergeAttrs {}; - - stdParams = mergeAttrList [ - (optionalAttrs (cfg.baseUrl != null) { - "jetbrains.youtrack.baseUrl" = cfg.baseUrl; - }) - { - "java.aws.headless" = "true"; - "jetbrains.youtrack.disableBrowser" = "true"; - } - ]; in { - options.services.youtrack = { + imports = [ + (lib.mkRenamedOptionModule [ "services" "youtrack" "baseUrl" ] [ "services" "youtrack" "environmentalParameters" "base-url" ]) + (lib.mkRenamedOptionModule [ "services" "youtrack" "port" ] [ "services" "youtrack" "environmentalParameters" "listen-port" ]) + (lib.mkRemovedOptionModule [ "services" "youtrack" "maxMemory" ] "Please instead use `services.youtrack.generalParameters`.") + (lib.mkRemovedOptionModule [ "services" "youtrack" "maxMetaspaceSize" ] "Please instead use `services.youtrack.generalParameters`.") + ]; - enable = mkEnableOption (lib.mdDoc "YouTrack service"); + options.services.youtrack = { + enable = lib.mkEnableOption (lib.mdDoc "YouTrack service"); - address = mkOption { + address = lib.mkOption { description = lib.mdDoc '' The interface youtrack will listen on. ''; default = "127.0.0.1"; - type = types.str; + type = lib.types.str; }; - baseUrl = mkOption { - description = lib.mdDoc '' - Base URL for youtrack. Will be auto-detected and stored in database. - ''; - type = types.nullOr types.str; - default = null; - }; - - extraParams = mkOption { + extraParams = lib.mkOption { default = {}; description = lib.mdDoc '' - Extra parameters to pass to youtrack. See + Extra parameters to pass to youtrack. + Use to configure YouTrack 2022.x, deprecated with YouTrack 2023.x. Use `services.youtrack.generalParameters`. https://www.jetbrains.com/help/youtrack/standalone/YouTrack-Java-Start-Parameters.html for more information. ''; - example = literalExpression '' + example = lib.literalExpression '' { "jetbrains.youtrack.overrideRootPassword" = "tortuga"; } ''; - type = types.attrsOf types.str; + type = lib.types.attrsOf lib.types.str; + visible = false; }; - package = mkPackageOption pkgs "youtrack" { }; - - port = mkOption { + package = lib.mkOption { description = lib.mdDoc '' - The port youtrack will listen on. + Package to use. ''; - default = 8080; - type = types.port; + type = lib.types.package; + default = null; + relatedPackages = [ "youtrack_2022_3" "youtrack" ]; }; - statePath = mkOption { + + statePath = lib.mkOption { description = lib.mdDoc '' - Where to keep the youtrack database. + Path were the YouTrack state is stored. + To this path the base version (e.g. 2023_1) of the used package will be appended. ''; - type = types.path; + type = lib.types.path; default = "/var/lib/youtrack"; }; - virtualHost = mkOption { + virtualHost = lib.mkOption { description = lib.mdDoc '' Name of the nginx virtual host to use and setup. If null, do not setup anything. ''; default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; }; - jvmOpts = mkOption { + jvmOpts = lib.mkOption { description = lib.mdDoc '' Extra options to pass to the JVM. + Only has a use with YouTrack 2022.x, deprecated with YouTrack 2023.x. Use `serivces.youtrack.generalParameters`. See https://www.jetbrains.com/help/youtrack/standalone/Configure-JVM-Options.html for more information. ''; - type = types.separatedString " "; - example = "-XX:MetaspaceSize=250m"; + type = lib.types.separatedString " "; + example = "--J-XX:MetaspaceSize=250m"; default = ""; + visible = false; }; - maxMemory = mkOption { + autoUpgrade = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc "Whether YouTrack should auto upgrade it without showing the upgrade dialog."; + }; + + generalParameters = lib.mkOption { + type = with lib.types; listOf str; description = lib.mdDoc '' - Maximum Java heap size + General configuration parameters and other JVM options. + Only has an effect for YouTrack 2023.x. + See https://www.jetbrains.com/help/youtrack/server/2023.3/youtrack-java-start-parameters.html#general-parameters + for more information. ''; - type = types.str; - default = "1g"; + example = lib.literalExpression '' + [ + "-Djetbrains.youtrack.admin.restore=true" + "-Xmx1024m" + ]; + ''; + default = []; }; - maxMetaspaceSize = mkOption { + environmentalParameters = lib.mkOption { + type = lib.types.submodule { + freeformType = with lib.types; attrsOf (oneOf [ int str port ]); + options = { + listen-address = lib.mkOption { + type = lib.types.str; + default = "0.0.0.0"; + description = lib.mdDoc "The interface YouTrack will listen on."; + }; + listen-port = lib.mkOption { + type = lib.types.port; + default = 8080; + description = lib.mdDoc "The port YouTrack will listen on."; + }; + }; + }; description = lib.mdDoc '' - Maximum java Metaspace memory. + Environmental configuration parameters, set imperatively. The values doesn't get removed, when removed in Nix. + Only has an effect for YouTrack 2023.x. + See https://www.jetbrains.com/help/youtrack/server/2023.3/youtrack-java-start-parameters.html#environmental-parameters + for more information. + ''; + example = lib.literalExpression '' + { + secure-mode = "tls"; + } ''; - type = types.str; - default = "350m"; + default = {}; }; }; - config = mkIf cfg.enable { - - systemd.services.youtrack = { - environment.HOME = cfg.statePath; - environment.YOUTRACK_JVM_OPTS = "${extraAttr}"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - path = with pkgs; [ unixtools.hostname ]; - serviceConfig = { - Type = "simple"; - User = "youtrack"; - Group = "youtrack"; - Restart = "on-failure"; - ExecStart = ''${cfg.package}/bin/youtrack --J-Xmx${cfg.maxMemory} --J-XX:MaxMetaspaceSize=${cfg.maxMetaspaceSize} ${cfg.jvmOpts} ${cfg.address}:${toString cfg.port}''; + config = lib.mkIf cfg.enable { + warnings = lib.optional (lib.versions.major cfg.package.version <= "2022") + "YouTrack 2022.x is deprecated. See https://nixos.org/manual/nixos/unstable/index.html#module-services-youtrack for details on how to upgrade." + ++ lib.optional (cfg.extraParams != "" && (lib.versions.major cfg.package.version >= "2023")) + "'services.youtrack.extraParams' is deprecated and has no effect on YouTrack 2023.x and newer. Please migrate to 'services.youtrack.generalParameters'" + ++ lib.optional (cfg.jvmOpts != "" && (lib.versions.major cfg.package.version >= "2023")) + "'services.youtrack.jvmOpts' is deprecated and has no effect on YouTrack 2023.x and newer. Please migrate to 'services.youtrack.generalParameters'"; + + # XXX: Drop all version feature switches at the point when we consider YT 2022.3 as outdated. + services.youtrack.package = lib.mkDefault ( + if lib.versionAtLeast config.system.stateVersion "24.11" then pkgs.youtrack + else pkgs.youtrack_2022_3 + ); + + services.youtrack.generalParameters = lib.optional (lib.versions.major cfg.package.version >= "2023") + "-Ddisable.configuration.wizard.on.upgrade=${lib.boolToString cfg.autoUpgrade}" + ++ (lib.mapAttrsToList (k: v: "-D${k}=${v}") cfg.extraParams); + + systemd.services.youtrack = let + service_jar = let + mergeAttrList = lib.foldl' lib.mergeAttrs {}; + stdParams = mergeAttrList [ + (lib.optionalAttrs (cfg.environmentalParameters ? base-url && cfg.environmentalParameters.base-url != null) { + "jetbrains.youtrack.baseUrl" = cfg.environmentalParameters.base-url; + }) + { + "java.aws.headless" = "true"; + "jetbrains.youtrack.disableBrowser" = "true"; + } + ]; + extraAttr = lib.concatStringsSep " " (lib.mapAttrsToList (k: v: "-D${k}=${v}") (stdParams // cfg.extraParams)); + in { + environment.HOME = cfg.statePath; + environment.YOUTRACK_JVM_OPTS = "${extraAttr}"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = with pkgs; [ unixtools.hostname ]; + serviceConfig = { + Type = "simple"; + User = "youtrack"; + Group = "youtrack"; + Restart = "on-failure"; + ExecStart = ''${cfg.package}/bin/youtrack ${cfg.jvmOpts} ${cfg.environmentalParameters.listen-address}:${toString cfg.environmentalParameters.listen-port}''; + }; }; - }; + service_zip = let + jvmoptions = pkgs.writeTextFile { + name = "youtrack.jvmoptions"; + text = (lib.concatStringsSep "\n" cfg.generalParameters); + }; + + package = cfg.package.override { + statePath = cfg.statePath; + }; + in { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = with pkgs; [ unixtools.hostname ]; + preStart = '' + # This detects old (i.e. <= 2022.3) installations that were not migrated yet + # and migrates them to the new state directory style + if [[ -d ${cfg.statePath}/teamsysdata ]] && [[ ! -d ${cfg.statePath}/2022_3 ]] + then + mkdir -p ${cfg.statePath}/2022_3 + mv ${cfg.statePath}/teamsysdata ${cfg.statePath}/2022_3 + mv ${cfg.statePath}/.youtrack ${cfg.statePath}/2022_3 + fi + mkdir -p ${cfg.statePath}/{backups,conf,data,logs,temp} + ${pkgs.coreutils}/bin/ln -fs ${jvmoptions} ${cfg.statePath}/conf/youtrack.jvmoptions + ${package}/bin/youtrack configure ${lib.concatStringsSep " " (lib.mapAttrsToList (name: value: "--${name}=${toString value}") cfg.environmentalParameters )} + ''; + serviceConfig = lib.mkMerge [ + { + Type = "simple"; + User = "youtrack"; + Group = "youtrack"; + Restart = "on-failure"; + ExecStart = "${package}/bin/youtrack run"; + } + (lib.mkIf (cfg.statePath == "/var/lib/youtrack") { + StateDirectory = "youtrack"; + }) + ]; + }; + in if (lib.versions.major cfg.package.version >= "2023") then service_zip else service_jar; users.users.youtrack = { description = "Youtrack service user"; @@ -136,7 +230,7 @@ in users.groups.youtrack = {}; - services.nginx = mkIf (cfg.virtualHost != null) { + services.nginx = lib.mkIf (cfg.virtualHost != null) { upstreams.youtrack.servers."${cfg.address}:${toString cfg.port}" = {}; virtualHosts.${cfg.virtualHost}.locations = { "/" = { @@ -166,9 +260,10 @@ in proxy_set_header X-Forwarded-Proto $scheme; ''; }; - }; }; - }; + + meta.doc = ./youtrack.md; + meta.maintainers = [ lib.maintainers.leona ]; } diff --git a/nixos/modules/services/web-servers/zope2.nix b/nixos/modules/services/web-servers/zope2.nix index a17fe6bc2082..29731b29eea4 100644 --- a/nixos/modules/services/web-servers/zope2.nix +++ b/nixos/modules/services/web-servers/zope2.nix @@ -147,7 +147,7 @@ in name = "zope2-${name}-env"; paths = [ pkgs.python27 - pkgs.python27Packages.recursivePthLoader + pkgs.python27Packages.recursive-pth-loader pkgs.python27Packages."plone.recipe.zope2instance" ] ++ attrValues pkgs.python27.modules ++ opts.packages; diff --git a/nixos/modules/services/x11/desktop-managers/budgie.nix b/nixos/modules/services/x11/desktop-managers/budgie.nix index de4b2c0e50f5..463c45675cee 100644 --- a/nixos/modules/services/x11/desktop-managers/budgie.nix +++ b/nixos/modules/services/x11/desktop-managers/budgie.nix @@ -118,9 +118,7 @@ in { (budgie.budgie-desktop-with-plugins.override { plugins = cfg.extraPlugins; }) budgie.budgie-desktop-view budgie.budgie-screensaver - - # Required by the Budgie Desktop session. - (gnome.gnome-session.override { gnomeShellSupport = false; }) + budgie.budgie-session # Required by Budgie Menu. gnome-menus diff --git a/nixos/modules/services/x11/desktop-managers/deepin.nix b/nixos/modules/services/x11/desktop-managers/deepin.nix index 7fdd50b1ed26..7d3acada6073 100644 --- a/nixos/modules/services/x11/desktop-managers/deepin.nix +++ b/nixos/modules/services/x11/desktop-managers/deepin.nix @@ -96,18 +96,10 @@ in "/share/dde-daemon" "/share/dsg" "/share/deepin-themes" + "/share/deepin" ]; environment.etc = { - "distribution.info".text = '' - [Distribution] - Name=NixOS - WebsiteName=www.nixos.org - Website=https://www.nixos.org - Logo=${pkgs.nixos-icons}/share/icons/hicolor/96x96/apps/nix-snowflake.png - LogoLight=${pkgs.nixos-icons}/share/icons/hicolor/32x32/apps/nix-snowflake.png - LogoTransparent=${pkgs.deepin.deepin-desktop-base}/share/pixmaps/distribution_logo_transparent.svg - ''; "deepin-installer.conf".text = '' system_info_vendor_name="Copyright (c) 2003-2023 NixOS contributors" ''; @@ -156,6 +148,7 @@ in deepin-sound-theme deepin-gtk-theme deepin-wallpapers + deepin-desktop-base startdde dde-dock diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index fc9de2500ba4..677465f55c47 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -185,6 +185,8 @@ in }; }; + qt.enable = true; + environment.systemPackages = with pkgs.plasma5Packages; let @@ -253,6 +255,9 @@ in plasma-integration polkit-kde-agent + qqc2-breeze-style + qqc2-desktop-style + plasma-desktop plasma-workspace plasma-workspace-wallpapers @@ -480,7 +485,7 @@ in pkgs.maliit-framework pkgs.maliit-keyboard ] - ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with libsForQt5.plasmaMobileGear;[ + ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with pkgs.plasma5Packages.plasmaMobileGear; [ # Additional software made for Plasma Mobile. alligator angelfish diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py index 055afe95df60..a9978d7adf80 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py @@ -18,7 +18,7 @@ from dataclasses import dataclass # These values will be replaced with actual values during the package build EFI_SYS_MOUNT_POINT = "@efiSysMountPoint@" TIMEOUT = "@timeout@" -EDITOR = bool("@editor@") +EDITOR = "@editor@" == "1" CONSOLE_MODE = "@consoleMode@" BOOTSPEC_TOOLS = "@bootspecTools@" DISTRO_NAME = "@distroName@" diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix index 3b140726c2d6..ea4553b8208f 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix @@ -22,11 +22,9 @@ let timeout = optionalString (config.boot.loader.timeout != null) config.boot.loader.timeout; - editor = if cfg.editor then "True" else "False"; - configurationLimit = if cfg.configurationLimit == null then 0 else cfg.configurationLimit; - inherit (cfg) consoleMode graceful; + inherit (cfg) consoleMode graceful editor; inherit (efi) efiSysMountPoint canTouchEfiVariables; @@ -54,17 +52,18 @@ let checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" { nativeBuildInputs = [ pkgs.mypy ]; } '' - install -m755 ${systemdBootBuilder} $out + mkdir -p $out/bin + install -m755 ${systemdBootBuilder} $out/bin/systemd-boot-builder mypy \ --no-implicit-optional \ --disallow-untyped-calls \ --disallow-untyped-defs \ - $out + $out/bin/systemd-boot-builder ''; finalSystemdBootBuilder = pkgs.writeScript "install-systemd-boot.sh" '' #!${pkgs.runtimeShell} - ${checkedSystemdBootBuilder} "$@" + ${checkedSystemdBootBuilder}/bin/systemd-boot-builder "$@" ${cfg.extraInstallCommands} ''; in { diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index f236a4c005ad..a7399bd55e77 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -2989,15 +2989,9 @@ let systemd.services.systemd-networkd = { wantedBy = [ "initrd.target" ]; - # These before and conflicts lines can be removed when this PR makes it into a release: - # https://github.com/systemd/systemd/pull/27791 - before = ["initrd-switch-root.target"]; - conflicts = ["initrd-switch-root.target"]; }; systemd.sockets.systemd-networkd = { wantedBy = [ "initrd.target" ]; - before = ["initrd-switch-root.target"]; - conflicts = ["initrd-switch-root.target"]; }; systemd.services.systemd-network-generator.wantedBy = [ "sysinit.target" ]; diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix index 26cc016869b3..9641921fc795 100644 --- a/nixos/modules/system/boot/systemd/initrd.nix +++ b/nixos/modules/system/boot/systemd/initrd.nix @@ -57,6 +57,7 @@ let "systemd-ask-password-console.service" "systemd-fsck@.service" "systemd-halt.service" + "systemd-hibernate-resume.service" "systemd-journald-audit.socket" "systemd-journald-dev-log.socket" "systemd-journald.service" |