diff options
Diffstat (limited to 'nixos')
23 files changed, 818 insertions, 182 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index 760c58d5050e3..5c6bdf97d1203 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -20,7 +20,7 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2 - [Breaking Changes](#sec-release-23.11-nixos-breaking-changes) - [New Services](#sec-release-23.11-nixos-new-services) - [Other Notable Changes](#sec-release-23.11-nixos-notable-changes) -- [Nixpkgs Library Changes](#sec-release-23.11-nixpkgs-lib) +- [Nixpkgs Library](#sec-release-23.11-nixpkgs-lib) - [Breaking Changes](#sec-release-23.11-lib-breaking) - [Additions and Improvements](#sec-release-23.11-lib-additions-improvements) - [Deprecations](#sec-release-23.11-lib-deprecations) @@ -71,7 +71,9 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2 - `services.mastodon` doesn't support providing a TCP port to its `streaming` component anymore, as upstream implemented parallelization by running multiple instances instead of running multiple processes in one instance. - Please create a PR if you are interested in this feature. + Please create a PR if you are interested in this feature.\ + Due to this, the desired number of such instances + {option}`services.mastodon.streamingProcesses` now needs to be declared explicitly. - The `services.hostapd` module was rewritten to support `passwordFile` like options, WPA3-SAE, and management of multiple interfaces. This breaks @@ -1315,14 +1317,14 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2 ### Breaking Changes {#sec-release-23.11-lib-breaking} -- [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.foldl-prime) +- [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.foldl-prime) now always evaluates the initial accumulator argument first. If you depend on the lazier behavior, consider using - [`lib.lists.foldl`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.foldl) + [`lib.lists.foldl`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.foldl) or [`builtins.foldl'`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-foldl') instead. -- [`lib.attrsets.foldlAttrs`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.attrsets.foldlAttrs) +- [`lib.attrsets.foldlAttrs`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.attrsets.foldlAttrs) now always evaluates the initial accumulator argument first. - Now that the internal NixOS transition to Markdown documentation is complete, `lib.options.literalDocBook` has been removed after deprecation in 22.11. @@ -1330,7 +1332,7 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2 ### Additions and Improvements {#sec-release-23.11-lib-additions-improvements} -- [`lib.fileset`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-fileset): +- [`lib.fileset`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-fileset): A new sub-library to select local files to use for sources, designed to be easy and safe to use. @@ -1339,7 +1341,7 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2 post](https://www.tweag.io/blog/2023-11-28-file-sets/) or [the tutorial](https://nix.dev/tutorials/file-sets). -- [`lib.gvariant`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-gvariant): +- [`lib.gvariant`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-gvariant): A partial and basic implementation of GVariant formatted strings. See [GVariant Format Strings](https://docs.gtk.org/glib/gvariant-format-strings.html) for details. @@ -1349,58 +1351,58 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2 change in backwards incompatible ways without prior notice. ::: -- [`lib.asserts`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-asserts): +- [`lib.asserts`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-asserts): New function: - [`assertEachOneOf`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.asserts.assertEachOneOf). -- [`lib.attrsets`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-attrsets): + [`assertEachOneOf`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.asserts.assertEachOneOf). +- [`lib.attrsets`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-attrsets): New function: - [`attrsToList`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.attrsets.attrsToList). -- [`lib.customisation`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-customisation): + [`attrsToList`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.attrsets.attrsToList). +- [`lib.customisation`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-customisation): New function: - [`makeScopeWithSplicing'`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.customisation.makeScopeWithSplicing-prime). -- [`lib.fixedPoints`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-fixedPoints): + [`makeScopeWithSplicing'`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.customisation.makeScopeWithSplicing-prime). +- [`lib.fixedPoints`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-fixedPoints): Documentation improvements for - [`lib.fixedPoints.fix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.fixedPoints.fix). + [`lib.fixedPoints.fix`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.fixedPoints.fix). - `lib.generators`: New functions: - [`mkDconfKeyValue`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.generators.mkDconfKeyValue), - [`toDconfINI`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.generators.toDconfINI). + [`mkDconfKeyValue`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.generators.mkDconfKeyValue), + [`toDconfINI`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.generators.toDconfINI). `lib.generators.toKeyValue` now supports the `indent` attribute in its first argument. -- [`lib.lists`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-lists): +- [`lib.lists`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-lists): New functions: - [`findFirstIndex`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.findFirstIndex), - [`hasPrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.hasPrefix), - [`removePrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.removePrefix), - [`commonPrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.commonPrefix), - [`allUnique`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.allUnique). + [`findFirstIndex`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.findFirstIndex), + [`hasPrefix`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.hasPrefix), + [`removePrefix`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.removePrefix), + [`commonPrefix`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.commonPrefix), + [`allUnique`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.allUnique). Documentation improvements for - [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.foldl-prime). -- [`lib.meta`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-meta): + [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.foldl-prime). +- [`lib.meta`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-meta): Documentation of functions now gets rendered -- [`lib.path`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-path): +- [`lib.path`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-path): New functions: - [`hasPrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.hasPrefix), - [`removePrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.removePrefix), - [`splitRoot`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.splitRoot), - [`subpath.components`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.subpath.components). -- [`lib.strings`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-strings): + [`hasPrefix`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.path.hasPrefix), + [`removePrefix`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.path.removePrefix), + [`splitRoot`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.path.splitRoot), + [`subpath.components`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.path.subpath.components). +- [`lib.strings`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-strings): New functions: - [`replicate`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.replicate), - [`cmakeOptionType`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.cmakeOptionType), - [`cmakeBool`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.cmakeBool), - [`cmakeFeature`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.cmakeFeature). -- [`lib.trivial`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-trivial): + [`replicate`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.strings.replicate), + [`cmakeOptionType`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.strings.cmakeOptionType), + [`cmakeBool`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.strings.cmakeBool), + [`cmakeFeature`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.strings.cmakeFeature). +- [`lib.trivial`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-trivial): New function: - [`mirrorFunctionArgs`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.trivial.mirrorFunctionArgs). + [`mirrorFunctionArgs`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.trivial.mirrorFunctionArgs). - `lib.systems`: New function: - [`equals`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.systems.equals). -- [`lib.options`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-options): + [`equals`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.systems.equals). +- [`lib.options`](https://nixos.org/manual/nixpkgs/stable#sec-functions-library-options): Improved documentation for - [`mkPackageOption`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mkPackageOption). + [`mkPackageOption`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.options.mkPackageOption). - [`mkPackageOption`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mkPackageOption). + [`mkPackageOption`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.options.mkPackageOption). now also supports the `pkgsText` attribute. Module system: diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 9191a204a7a19..4210f5da58e11 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -27,6 +27,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. --> +- The `power.ups` module now generates `upsd.conf`, `upsd.users` and `upsmon.conf` automatically from a set of new configuration options. This breaks compatibility with existing `power.ups` setups where these files were created manually. Back up these files before upgrading NixOS. + - `mkosi` was updated to v19. Parts of the user interface have changed. Consult the [release notes](https://github.com/systemd/mkosi/releases/tag/v19) for a list of changes. diff --git a/nixos/maintainers/scripts/ec2/create-amis.sh b/nixos/maintainers/scripts/ec2/create-amis.sh index 0c1656efaf1ca..d182c5c2a4794 100755 --- a/nixos/maintainers/scripts/ec2/create-amis.sh +++ b/nixos/maintainers/scripts/ec2/create-amis.sh @@ -27,31 +27,37 @@ var ${bucket:=nixos-amis} var ${service_role_name:=vmimport} # Output of the command: -# > aws ec2 describe-regions --all-regions --query "Regions[].{Name:RegionName}" --output text | sort +# $ nix-shell -I nixpkgs=. -p awscli --run 'aws ec2 describe-regions --region us-east-1 --all-regions --query "Regions[].{Name:RegionName}" --output text | sort | sed -e s/^/\ \ /' var ${regions:= - af-south-1 - ap-east-1 - ap-northeast-1 - ap-northeast-2 - ap-northeast-3 - ap-south-1 - ap-southeast-1 - ap-southeast-2 - ap-southeast-3 - ca-central-1 - eu-central-1 - eu-north-1 - eu-south-1 - eu-west-1 - eu-west-2 - eu-west-3 - me-south-1 - sa-east-1 - us-east-1 - us-east-2 - us-west-1 - us-west-2 - } + af-south-1 + ap-east-1 + ap-northeast-1 + ap-northeast-2 + ap-northeast-3 + ap-south-1 + ap-south-2 + ap-southeast-1 + ap-southeast-2 + ap-southeast-3 + ap-southeast-4 + ca-central-1 + eu-central-1 + eu-central-2 + eu-north-1 + eu-south-1 + eu-south-2 + eu-west-1 + eu-west-2 + eu-west-3 + il-central-1 + me-central-1 + me-south-1 + sa-east-1 + us-east-1 + us-east-2 + us-west-1 + us-west-2 +} regions=($regions) diff --git a/nixos/modules/config/nix.nix b/nixos/modules/config/nix.nix index cee4f54db0cb5..2769d8b25ef6f 100644 --- a/nixos/modules/config/nix.nix +++ b/nixos/modules/config/nix.nix @@ -109,13 +109,17 @@ let if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then '' echo "Ignoring validation for cross-compilation" '' - else '' + else + let + showCommand = if isNixAtLeast "2.20pre" then "config show" else "show-config"; + in + '' echo "Validating generated nix.conf" ln -s $out ./nix.conf set -e set +o pipefail NIX_CONF_DIR=$PWD \ - ${cfg.package}/bin/nix show-config ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \ + ${cfg.package}/bin/nix ${showCommand} ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \ ${optionalString (isNixAtLeast "2.4pre") "--option experimental-features nix-command"} \ |& sed -e 's/^warning:/error:/' \ | (! grep '${if cfg.checkAllErrors then "^error:" else "^error: unknown setting"}') diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 18928a6bf21bb..5af7284ac71af 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -288,7 +288,7 @@ in telegraf = 256; gitlab-runner = 257; postgrey = 258; - hound = 259; + # hound = 259; # unused, removed 2023-11-21 leaps = 260; ipfs = 261; # stanchion = 262; # unused, removed 2020-10-14 @@ -599,7 +599,7 @@ in #telegraf = 256; # unused gitlab-runner = 257; postgrey = 258; - hound = 259; + # hound = 259; # unused, removed 2023-11-21 leaps = 260; ipfs = 261; # stanchion = 262; # unused, removed 2020-10-14 diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index fee7c35ed8f45..4a93cd1fd9c87 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1334,6 +1334,7 @@ ./services/web-apps/vikunja.nix ./services/web-apps/whitebophir.nix ./services/web-apps/wiki-js.nix + ./services/web-apps/windmill.nix ./services/web-apps/wordpress.nix ./services/web-apps/writefreely.nix ./services/web-apps/youtrack.nix diff --git a/nixos/modules/services/cluster/kubernetes/flannel.nix b/nixos/modules/services/cluster/kubernetes/flannel.nix index 11c5adc6a8859..dca8996df0831 100644 --- a/nixos/modules/services/cluster/kubernetes/flannel.nix +++ b/nixos/modules/services/cluster/kubernetes/flannel.nix @@ -13,6 +13,13 @@ in ###### interface options.services.kubernetes.flannel = { enable = mkEnableOption (lib.mdDoc "flannel networking"); + + openFirewallPorts = mkOption { + description = lib.mdDoc '' + Whether to open the Flannel UDP ports in the firewall on all interfaces.''; + type = types.bool; + default = true; + }; }; ###### implementation @@ -38,7 +45,7 @@ in }; networking = { - firewall.allowedUDPPorts = [ + firewall.allowedUDPPorts = mkIf cfg.openFirewallPorts [ 8285 # flannel udp 8472 # flannel vxlan ]; diff --git a/nixos/modules/services/development/zammad.nix b/nixos/modules/services/development/zammad.nix index 87aceddd6635c..c084d6541ad38 100644 --- a/nixos/modules/services/development/zammad.nix +++ b/nixos/modules/services/development/zammad.nix @@ -21,6 +21,7 @@ let NODE_ENV = "production"; RAILS_SERVE_STATIC_FILES = "true"; RAILS_LOG_TO_STDOUT = "true"; + REDIS_URL = "redis://${cfg.redis.host}:${toString cfg.redis.port}"; }; databaseConfig = settingsFormat.generate "database.yml" cfg.database.settings; in @@ -65,6 +66,36 @@ in description = lib.mdDoc "Websocket service port."; }; + redis = { + createLocally = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc "Whether to create a local redis automatically."; + }; + + name = mkOption { + type = types.str; + default = "zammad"; + description = lib.mdDoc '' + Name of the redis server. Only used if `createLocally` is set to true. + ''; + }; + + host = mkOption { + type = types.str; + default = "localhost"; + description = lib.mdDoc '' + Redis server address. + ''; + }; + + port = mkOption { + type = types.port; + default = 6379; + description = lib.mdDoc "Port of the redis server."; + }; + }; + database = { type = mkOption { type = types.enum [ "PostgreSQL" "MySQL" ]; @@ -206,6 +237,10 @@ in assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; message = "a password cannot be specified if services.zammad.database.createLocally is set to true"; } + { + assertion = cfg.redis.createLocally -> cfg.redis.host == "localhost"; + message = "the redis host must be localhost if services.zammad.redis.createLocally is set to true"; + } ]; services.mysql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "MySQL") { @@ -231,6 +266,13 @@ in ]; }; + services.redis = optionalAttrs cfg.redis.createLocally { + servers."${cfg.redis.name}" = { + enable = true; + port = cfg.redis.port; + }; + }; + systemd.services.zammad-web = { inherit environment; serviceConfig = serviceConfig // { @@ -240,6 +282,8 @@ in after = [ "network.target" "postgresql.service" + ] ++ optionals cfg.redis.createLocally [ + "redis-${cfg.redis.name}.service" ]; requires = [ "postgresql.service" @@ -303,16 +347,15 @@ in script = "./script/websocket-server.rb -b ${cfg.host} -p ${toString cfg.websocketPort} start"; }; - systemd.services.zammad-scheduler = { - inherit environment; - serviceConfig = serviceConfig // { Type = "forking"; }; + systemd.services.zammad-worker = { + inherit serviceConfig environment; after = [ "zammad-web.service" ]; requires = [ "zammad-web.service" ]; - description = "Zammad scheduler"; + description = "Zammad background worker"; wantedBy = [ "multi-user.target" ]; - script = "./script/scheduler.rb start"; + script = "./script/background-worker.rb start"; }; }; - meta.maintainers = with lib.maintainers; [ garbas taeer ]; + meta.maintainers = with lib.maintainers; [ taeer netali ]; } diff --git a/nixos/modules/services/home-automation/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix index 6aa0ae9eba47a..0a399e0774d10 100644 --- a/nixos/modules/services/home-automation/home-assistant.nix +++ b/nixos/modules/services/home-automation/home-assistant.nix @@ -11,14 +11,12 @@ let # options shown in settings. # We post-process the result to add support for YAML functions, like secrets or includes, see e.g. # https://www.home-assistant.io/docs/configuration/secrets/ - filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) cfg.config or {}; + filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) (lib.recursiveUpdate customLovelaceModulesResources (cfg.config or {})); configFile = pkgs.runCommandLocal "configuration.yaml" { } '' cp ${format.generate "configuration.yaml" filteredConfig} $out sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out ''; - lovelaceConfig = if (cfg.lovelaceConfig == null) then {} - else (lib.recursiveUpdate customLovelaceModulesResources cfg.lovelaceConfig); - lovelaceConfigFile = format.generate "ui-lovelace.yaml" lovelaceConfig; + lovelaceConfigFile = format.generate "ui-lovelace.yaml" cfg.lovelaceConfig; # Components advertised by the home-assistant package availableComponents = cfg.package.availableComponents; @@ -77,7 +75,7 @@ let # Create parts of the lovelace config that reference lovelave modules as resources customLovelaceModulesResources = { lovelace.resources = map (card: { - url = "/local/nixos-lovelace-modules/${card.entrypoint or card.pname}.js?${card.version}"; + url = "/local/nixos-lovelace-modules/${card.entrypoint or card.pname + ".js"}?${card.version}"; type = "module"; }) cfg.customLovelaceModules; }; diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix index 90ea56658b02d..e78cb4d01dc5b 100644 --- a/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixos/modules/services/monitoring/prometheus/default.nix @@ -41,12 +41,12 @@ let # This becomes the main config file for Prometheus promConfig = { global = filterValidPrometheus cfg.globalConfig; - rule_files = map (promtoolCheck "check rules" "rules") (cfg.ruleFiles ++ [ - (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules)) - ]); scrape_configs = filterValidPrometheus cfg.scrapeConfigs; remote_write = filterValidPrometheus cfg.remoteWrite; remote_read = filterValidPrometheus cfg.remoteRead; + rule_files = optionals (!(cfg.enableAgentMode)) (map (promtoolCheck "check rules" "rules") (cfg.ruleFiles ++ [ + (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules)) + ])); alerting = { inherit (cfg) alertmanagers; }; @@ -62,15 +62,20 @@ let promtoolCheck "check config ${lib.optionalString (cfg.checkConfig == "syntax-only") "--syntax-only"}" "prometheus.yml" yml; cmdlineArgs = cfg.extraFlags ++ [ - "--storage.tsdb.path=${workingDir}/data/" "--config.file=${ if cfg.enableReload then "/etc/prometheus/prometheus.yaml" else prometheusYml }" "--web.listen-address=${cfg.listenAddress}:${builtins.toString cfg.port}" - "--alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}" - ] ++ optional (cfg.webExternalUrl != null) "--web.external-url=${cfg.webExternalUrl}" + ] ++ ( + if (cfg.enableAgentMode) then [ + "--enable-feature=agent" + ] else [ + "--alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity }" + "--storage.tsdb.path=${workingDir}/data/" + ]) + ++ optional (cfg.webExternalUrl != null) "--web.external-url=${cfg.webExternalUrl}" ++ optional (cfg.retentionTime != null) "--storage.tsdb.retention.time=${cfg.retentionTime}" ++ optional (cfg.webConfigFile != null) "--web.config.file=${cfg.webConfigFile}"; @@ -1612,6 +1617,8 @@ in ''; }; + enableAgentMode = mkEnableOption (lib.mdDoc "agent mode"); + configText = mkOption { type = types.nullOr types.lines; default = null; diff --git a/nixos/modules/services/monitoring/ups.nix b/nixos/modules/services/monitoring/ups.nix index efef2d777acd8..c9dda8a8c0930 100644 --- a/nixos/modules/services/monitoring/ups.nix +++ b/nixos/modules/services/monitoring/ups.nix @@ -6,9 +6,83 @@ with lib; let cfg = config.power.ups; -in + defaultPort = 3493; + + nutFormat = { + + type = with lib.types; let + + singleAtom = nullOr (oneOf [ + bool + int + float + str + ]) // { + description = "atom (null, bool, int, float or string)"; + }; + + in attrsOf (oneOf [ + singleAtom + (listOf (nonEmptyListOf singleAtom)) + ]); + + generate = name: value: + let + normalizedValue = + lib.mapAttrs (key: val: + if lib.isList val + then forEach val (elem: if lib.isList elem then elem else [elem]) + else + if val == null + then [] + else [[val]] + ) value; + + mkValueString = concatMapStringsSep " " (v: + let str = generators.mkValueStringDefault {} v; + in + # Quote the value if it has spaces and isn't already quoted. + if (hasInfix " " str) && !(hasPrefix "\"" str && hasSuffix "\"" str) + then "\"${str}\"" + else str + ); + + in pkgs.writeText name (lib.generators.toKeyValue { + mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " "; + listsAsDuplicateKeys = true; + } normalizedValue); + + }; + + installSecrets = source: target: secrets: + pkgs.writeShellScript "installSecrets.sh" '' + install -m0600 -D ${source} "${target}" + ${concatLines (forEach secrets (name: '' + ${pkgs.replace-secret}/bin/replace-secret \ + '@${name}@' \ + "$CREDENTIALS_DIRECTORY/${name}" \ + "${target}" + ''))} + chmod u-w "${target}" + ''; + + upsmonConf = nutFormat.generate "upsmon.conf" cfg.upsmon.settings; + + upsdUsers = pkgs.writeText "upsd.users" (let + # This looks like INI, but it's not quite because the + # 'upsmon' option lacks a '='. See: man upsd.users + userConfig = name: user: concatStringsSep "\n " (concatLists [ + [ + "[${name}]" + "password = \"@upsdusers_password_${name}@\"" + ] + (optional (user.upsmon != null) "upsmon ${user.upsmon}") + (forEach user.actions (action: "actions = ${action}")) + (forEach user.instcmds (instcmd: "instcmds = ${instcmd}")) + ]); + in concatStringsSep "\n\n" (mapAttrsToList userConfig cfg.users)); + -let upsOptions = {name, config, ...}: { options = { @@ -95,6 +169,213 @@ let }; }; + listenOptions = { + options = { + address = mkOption { + type = types.str; + description = lib.mdDoc '' + Address of the interface for `upsd` to listen on. + See `man upsd.conf` for details. + ''; + }; + + port = mkOption { + type = types.port; + default = defaultPort; + description = lib.mdDoc '' + TCP port for `upsd` to listen on. + See `man upsd.conf` for details. + ''; + }; + }; + }; + + upsdOptions = { + options = { + enable = mkOption { + type = types.bool; + defaultText = literalMD "`true` if `mode` is one of `standalone`, `netserver`"; + description = mdDoc "Whether to enable `upsd`."; + }; + + listen = mkOption { + type = with types; listOf (submodule listenOptions); + default = []; + example = [ + { + address = "192.168.50.1"; + } + { + address = "::1"; + port = 5923; + } + ]; + description = lib.mdDoc '' + Address of the interface for `upsd` to listen on. + See `man upsd` for details`. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = lib.mdDoc '' + Additional lines to add to `upsd.conf`. + ''; + }; + }; + + config = { + enable = mkDefault (elem cfg.mode [ "standalone" "netserver" ]); + }; + }; + + + monitorOptions = { name, config, ... }: { + options = { + system = mkOption { + type = types.str; + default = name; + description = lib.mdDoc '' + Identifier of the UPS to monitor, in this form: `<upsname>[@<hostname>[:<port>]]` + See `upsmon.conf` for details. + ''; + }; + + powerValue = mkOption { + type = types.int; + default = 1; + description = lib.mdDoc '' + Number of power supplies that the UPS feeds on this system. + See `upsmon.conf` for details. + ''; + }; + + user = mkOption { + type = types.str; + description = lib.mdDoc '' + Username from `upsd.users` for accessing this UPS. + See `upsmon.conf` for details. + ''; + }; + + passwordFile = mkOption { + type = types.str; + defaultText = literalMD "power.ups.users.\${user}.passwordFile"; + description = lib.mdDoc '' + The full path to a file containing the password from + `upsd.users` for accessing this UPS. The password file + is read on service start. + See `upsmon.conf` for details. + ''; + }; + + type = mkOption { + type = types.str; + default = "master"; + description = lib.mdDoc '' + The relationship with `upsd`. + See `upsmon.conf` for details. + ''; + }; + }; + + config = { + passwordFile = mkDefault cfg.users.${config.user}.passwordFile; + }; + }; + + upsmonOptions = { + options = { + enable = mkOption { + type = types.bool; + defaultText = literalMD "`true` if `mode` is one of `standalone`, `netserver`, `netclient`"; + description = mdDoc "Whether to enable `upsmon`."; + }; + + monitor = mkOption { + type = with types; attrsOf (submodule monitorOptions); + default = {}; + description = lib.mdDoc '' + Set of UPS to monitor. See `man upsmon.conf` for details. + ''; + }; + + settings = mkOption { + type = nutFormat.type; + default = {}; + defaultText = literalMD '' + { + MINSUPPLIES = 1; + RUN_AS_USER = "root"; + NOTIFYCMD = "''${pkgs.nut}/bin/upssched"; + SHUTDOWNCMD = "''${pkgs.systemd}/bin/shutdown now"; + } + ''; + description = mdDoc "Additional settings to add to `upsmon.conf`."; + example = literalMD '' + { + MINSUPPLIES = 2; + NOTIFYFLAG = [ + [ "ONLINE" "SYSLOG+EXEC" ] + [ "ONBATT" "SYSLOG+EXEC" ] + ]; + } + ''; + }; + }; + + config = { + enable = mkDefault (elem cfg.mode [ "standalone" "netserver" "netclient" ]); + settings = { + RUN_AS_USER = "root"; # TODO: replace 'root' by another username. + MINSUPPLIES = mkDefault 1; + NOTIFYCMD = mkDefault "${pkgs.nut}/bin/upssched"; + SHUTDOWNCMD = mkDefault "${pkgs.systemd}/bin/shutdown now"; + MONITOR = flip mapAttrsToList cfg.upsmon.monitor (name: monitor: with monitor; [ system powerValue user "\"@upsmon_password_${name}@\"" type ]); + }; + }; + }; + + userOptions = { + options = { + passwordFile = mkOption { + type = types.str; + description = lib.mdDoc '' + The full path to a file that contains the user's (clear text) + password. The password file is read on service start. + ''; + }; + + actions = mkOption { + type = with types; listOf str; + default = []; + description = lib.mdDoc '' + Allow the user to do certain things with upsd. + See `man upsd.users` for details. + ''; + }; + + instcmds = mkOption { + type = with types; listOf str; + default = []; + description = lib.mdDoc '' + Let the user initiate specific instant commands. Use "ALL" to grant all commands automatically. For the full list of what your UPS supports, use "upscmd -l". + See `man upsd.users` for details. + ''; + }; + + upsmon = mkOption { + type = with types; nullOr str; + default = null; + description = lib.mdDoc '' + Add the necessary actions for a upsmon process to work. + See `man upsd.users` for details. + ''; + }; + }; + }; + in @@ -103,19 +384,14 @@ in # powerManagement.powerDownCommands power.ups = { - enable = mkOption { - default = false; - type = with types; bool; - description = lib.mdDoc '' - Enables support for Power Devices, such as Uninterruptible Power - Supplies, Power Distribution Units and Solar Controllers. - ''; - }; + enable = mkEnableOption (lib.mdDoc '' + Enables support for Power Devices, such as Uninterruptible Power + Supplies, Power Distribution Units and Solar Controllers. + ''); - # This option is not used yet. mode = mkOption { default = "standalone"; - type = types.str; + type = types.enum [ "none" "standalone" "netserver" "netclient" ]; description = lib.mdDoc '' The MODE determines which part of the NUT is to be started, and which configuration files must be modified. @@ -148,6 +424,13 @@ in ''; }; + openFirewall = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Open ports in the firewall for `upsd`. + ''; + }; maxStartDelay = mkOption { default = 45; @@ -161,6 +444,22 @@ in ''; }; + upsmon = mkOption { + default = {}; + description = lib.mdDoc '' + Options for the `upsmon.conf` configuration file. + ''; + type = types.submodule upsmonOptions; + }; + + upsd = mkOption { + default = {}; + description = lib.mdDoc '' + Options for the `upsd.conf` configuration file. + ''; + type = types.submodule upsdOptions; + }; + ups = mkOption { default = {}; # see nut/etc/ups.conf.sample @@ -172,46 +471,95 @@ in type = with types; attrsOf (submodule upsOptions); }; + users = mkOption { + default = {}; + description = lib.mdDoc '' + Users that can access upsd. See `man upsd.users`. + ''; + type = with types; attrsOf (submodule userOptions); + }; + }; }; config = mkIf cfg.enable { + assertions = [ + (let + totalPowerValue = foldl' add 0 (map (monitor: monitor.powerValue) (attrValues cfg.upsmon.monitor)); + minSupplies = cfg.upsmon.settings.MINSUPPLIES; + in mkIf cfg.upsmon.enable { + assertion = totalPowerValue >= minSupplies; + message = '' + `power.ups.upsmon`: Total configured power value (${toString totalPowerValue}) must be at least MINSUPPLIES (${toString minSupplies}). + ''; + }) + ]; + environment.systemPackages = [ pkgs.nut ]; - systemd.services.upsmon = { + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = + if cfg.upsd.listen == [] + then [ defaultPort ] + else unique (forEach cfg.upsd.listen (listen: listen.port)); + }; + + systemd.services.upsmon = let + secrets = mapAttrsToList (name: monitor: "upsmon_password_${name}") cfg.upsmon.monitor; + createUpsmonConf = installSecrets upsmonConf "/run/nut/upsmon.conf" secrets; + in { + enable = cfg.upsmon.enable; description = "Uninterruptible Power Supplies (Monitor)"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - serviceConfig.Type = "forking"; - script = "${pkgs.nut}/sbin/upsmon"; - environment.NUT_CONFPATH = "/etc/nut/"; - environment.NUT_STATEPATH = "/var/lib/nut/"; + serviceConfig = { + Type = "forking"; + ExecStartPre = "${createUpsmonConf}"; + ExecStart = "${pkgs.nut}/sbin/upsmon"; + ExecReload = "${pkgs.nut}/sbin/upsmon -c reload"; + LoadCredential = mapAttrsToList (name: monitor: "upsmon_password_${name}:${monitor.passwordFile}") cfg.upsmon.monitor; + }; + environment.NUT_CONFPATH = "/etc/nut"; + environment.NUT_STATEPATH = "/var/lib/nut"; }; - systemd.services.upsd = { + systemd.services.upsd = let + secrets = mapAttrsToList (name: user: "upsdusers_password_${name}") cfg.users; + createUpsdUsers = installSecrets upsdUsers "/run/nut/upsd.users" secrets; + in { + enable = cfg.upsd.enable; description = "Uninterruptible Power Supplies (Daemon)"; after = [ "network.target" "upsmon.service" ]; wantedBy = [ "multi-user.target" ]; - serviceConfig.Type = "forking"; - # TODO: replace 'root' by another username. - script = "${pkgs.nut}/sbin/upsd -u root"; - environment.NUT_CONFPATH = "/etc/nut/"; - environment.NUT_STATEPATH = "/var/lib/nut/"; + serviceConfig = { + Type = "forking"; + ExecStartPre = "${createUpsdUsers}"; + # TODO: replace 'root' by another username. + ExecStart = "${pkgs.nut}/sbin/upsd -u root"; + ExecReload = "${pkgs.nut}/sbin/upsd -c reload"; + LoadCredential = mapAttrsToList (name: user: "upsdusers_password_${name}:${user.passwordFile}") cfg.users; + }; + environment.NUT_CONFPATH = "/etc/nut"; + environment.NUT_STATEPATH = "/var/lib/nut"; + restartTriggers = [ + config.environment.etc."nut/upsd.conf".source + ]; }; systemd.services.upsdrv = { + enable = cfg.upsd.enable; description = "Uninterruptible Power Supplies (Register all UPS)"; after = [ "upsd.service" ]; wantedBy = [ "multi-user.target" ]; - # TODO: replace 'root' by another username. - script = "${pkgs.nut}/bin/upsdrvctl -u root start"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; + # TODO: replace 'root' by another username. + ExecStart = "${pkgs.nut}/bin/upsdrvctl -u root start"; }; - environment.NUT_CONFPATH = "/etc/nut/"; - environment.NUT_STATEPATH = "/var/lib/nut/"; + environment.NUT_CONFPATH = "/etc/nut"; + environment.NUT_STATEPATH = "/var/lib/nut"; }; environment.etc = { @@ -223,24 +571,23 @@ in '' maxstartdelay = ${toString cfg.maxStartDelay} - ${flip concatStringsSep (forEach (attrValues cfg.ups) (ups: ups.summary)) " - - "} + ${concatStringsSep "\n\n" (forEach (attrValues cfg.ups) (ups: ups.summary))} + ''; + "nut/upsd.conf".source = pkgs.writeText "upsd.conf" + '' + ${concatStringsSep "\n" (forEach cfg.upsd.listen (listen: "LISTEN ${listen.address} ${toString listen.port}"))} + ${cfg.upsd.extraConfig} ''; "nut/upssched.conf".source = cfg.schedulerRules; - # These file are containing private information and thus should not - # be stored inside the Nix store. - /* - "nut/upsd.conf".source = ""; - "nut/upsd.users".source = ""; - "nut/upsmon.conf".source = ""; - */ + "nut/upsd.users".source = "/run/nut/upsd.users"; + "nut/upsmon.conf".source = "/run/nut/upsmon.conf"; }; power.ups.schedulerRules = mkDefault "${pkgs.nut}/etc/upssched.conf.sample"; systemd.tmpfiles.rules = [ "d /var/state/ups -" + "d /var/lib/nut 700" ]; diff --git a/nixos/modules/services/networking/harmonia.nix b/nixos/modules/services/networking/harmonia.nix index beaa7d00b6ce8..d0f4a8a6e6333 100644 --- a/nixos/modules/services/networking/harmonia.nix +++ b/nixos/modules/services/networking/harmonia.nix @@ -29,6 +29,11 @@ in config = lib.mkIf cfg.enable { nix.settings.extra-allowed-users = [ "harmonia" ]; + users.users.harmonia = { + isSystemUser = true; + group = "harmonia"; + }; + users.groups.harmonia = { }; systemd.services.harmonia = { description = "harmonia binary cache service"; @@ -50,7 +55,6 @@ in ExecStart = lib.getExe cfg.package; User = "harmonia"; Group = "harmonia"; - DynamicUser = true; PrivateUsers = true; DeviceAllow = [ "" ]; UMask = "0066"; diff --git a/nixos/modules/services/search/hound.nix b/nixos/modules/services/search/hound.nix index 539a322b431f6..d238b26a226b5 100644 --- a/nixos/modules/services/search/hound.nix +++ b/nixos/modules/services/search/hound.nix @@ -3,6 +3,12 @@ with lib; let cfg = config.services.hound; in { + imports = [ + (lib.mkRemovedOptionModule [ "services" "hound" "extraGroups" ] "Use users.users.hound.extraGroups instead") + ]; + + meta.maintainers = with maintainers; [ SuperSandro2000 ]; + options = { services.hound = { enable = mkOption { @@ -13,6 +19,8 @@ in { ''; }; + package = mkPackageOptionMD pkgs "hound" { }; + user = mkOption { default = "hound"; type = types.str; @@ -29,27 +37,15 @@ in { ''; }; - extraGroups = mkOption { - type = types.listOf types.str; - default = [ ]; - example = [ "dialout" ]; - description = lib.mdDoc '' - List of extra groups that the "hound" user should be a part of. - ''; - }; - home = mkOption { default = "/var/lib/hound"; type = types.path; description = lib.mdDoc '' - The path to use as hound's $HOME. If the default user - "hound" is configured then this is the home of the "hound" - user. + The path to use as hound's $HOME. + If the default user "hound" is configured then this is the home of the "hound" user. ''; }; - package = mkPackageOption pkgs "hound" { }; - config = mkOption { type = types.str; description = lib.mdDoc '' @@ -57,63 +53,62 @@ in { should be an absolute path to a writable location on disk. ''; example = literalExpression '' - ''' - { - "max-concurrent-indexers" : 2, - "dbpath" : "''${services.hound.home}/data", - "repos" : { - "nixpkgs": { - "url" : "https://www.github.com/NixOS/nixpkgs.git" - } - } + { + "max-concurrent-indexers" : 2, + "repos" : { + "nixpkgs": { + "url" : "https://www.github.com/NixOS/nixpkgs.git" + } } - ''' + } ''; }; listen = mkOption { type = types.str; default = "0.0.0.0:6080"; - example = "127.0.0.1:6080 or just :6080"; + example = ":6080"; description = lib.mdDoc '' - Listen on this IP:port / :port + Listen on this [IP]:port ''; }; }; }; config = mkIf cfg.enable { - users.groups = optionalAttrs (cfg.group == "hound") { - hound.gid = config.ids.gids.hound; + users.groups = lib.mkIf (cfg.group == "hound") { + hound = { }; }; - users.users = optionalAttrs (cfg.user == "hound") { + users.users = lib.mkIf (cfg.user == "hound") { hound = { - description = "hound code search"; + description = "Hound code search"; createHome = true; - home = cfg.home; - group = cfg.group; - extraGroups = cfg.extraGroups; - uid = config.ids.uids.hound; + isSystemUser = true; + inherit (cfg) home group; }; }; - systemd.services.hound = { + systemd.services.hound = let + configFile = pkgs.writeTextFile { + name = "hound.json"; + text = cfg.config; + checkPhase = '' + # check if the supplied text is valid json + ${lib.getExe pkgs.jq} . $target > /dev/null + ''; + }; + in { description = "Hound Code Search"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - serviceConfig = { User = cfg.user; Group = cfg.group; WorkingDirectory = cfg.home; ExecStartPre = "${pkgs.git}/bin/git config --global --replace-all http.sslCAinfo /etc/ssl/certs/ca-certificates.crt"; - ExecStart = "${cfg.package}/bin/houndd" + - " -addr ${cfg.listen}" + - " -conf ${pkgs.writeText "hound.json" cfg.config}"; - + ExecStart = "${cfg.package}/bin/houndd -addr ${cfg.listen} -conf ${configFile}"; }; }; }; - } diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix index 72a195d3a04ed..d3164373ec01f 100644 --- a/nixos/modules/services/security/clamav.nix +++ b/nixos/modules/services/security/clamav.nix @@ -3,7 +3,6 @@ with lib; let clamavUser = "clamav"; stateDir = "/var/lib/clamav"; - runDir = "/run/clamav"; clamavGroup = clamavUser; cfg = config.services.clamav; pkg = pkgs.clamav; @@ -99,6 +98,29 @@ in ''; }; }; + + scanner = { + enable = mkEnableOption (lib.mdDoc "ClamAV scanner"); + + interval = mkOption { + type = types.str; + default = "*-*-* 04:00:00"; + description = lib.mdDoc '' + How often clamdscan is invoked. See systemd.time(7) for more + information about the format. + By default this runs using 10 cores at most, be sure to run it at a time of low traffic. + ''; + }; + + scanDirectories = mkOption { + type = with types; listOf str; + default = [ "/home" "/var/lib" "/tmp" "/etc" "/var/tmp" ]; + description = lib.mdDoc '' + List of directories to scan. + The default includes everything I could think of that is valid for nixos. Feel free to contribute a PR to add to the default if you see something missing. + ''; + }; + }; }; }; @@ -117,9 +139,8 @@ in services.clamav.daemon.settings = { DatabaseDirectory = stateDir; - LocalSocket = "${runDir}/clamd.ctl"; - PidFile = "${runDir}/clamd.pid"; - TemporaryDirectory = "/tmp"; + LocalSocket = "/run/clamav/clamd.ctl"; + PidFile = "/run/clamav/clamd.pid"; User = "clamav"; Foreground = true; }; @@ -182,7 +203,6 @@ in ExecStart = "${pkg}/bin/freshclam"; SuccessExitStatus = "1"; # if databases are up to date StateDirectory = "clamav"; - RuntimeDirectory = "clamav"; User = clamavUser; Group = clamavGroup; PrivateTmp = "yes"; @@ -204,7 +224,6 @@ in serviceConfig = { Type = "oneshot"; StateDirectory = "clamav"; - RuntimeDirectory = "clamav"; User = clamavUser; Group = clamavGroup; PrivateTmp = "yes"; @@ -230,12 +249,31 @@ in Type = "oneshot"; ExecStart = "${pkgs.fangfrisch}/bin/fangfrisch --conf ${fangfrischConfigFile} refresh"; StateDirectory = "clamav"; - RuntimeDirectory = "clamav"; User = clamavUser; Group = clamavGroup; PrivateTmp = "yes"; PrivateDevices = "yes"; }; }; + + systemd.timers.clamdscan = mkIf cfg.scanner.enable { + description = "Timer for ClamAV virus scanner"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = cfg.scanner.interval; + Unit = "clamdscan.service"; + }; + }; + + systemd.services.clamdscan = mkIf cfg.scanner.enable { + description = "ClamAV virus scanner"; + after = optionals cfg.updater.enable [ "clamav-freshclam.service" ]; + wants = optionals cfg.updater.enable [ "clamav-freshclam.service" ]; + + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkg}/bin/clamdscan --multiscan --fdpass --infected --allmatch ${lib.concatStringsSep " " cfg.scanner.scanDirectories}"; + }; + }; }; } diff --git a/nixos/modules/services/web-apps/mastodon.nix b/nixos/modules/services/web-apps/mastodon.nix index 8686506b1c282..7b00ce35eb1a7 100644 --- a/nixos/modules/services/web-apps/mastodon.nix +++ b/nixos/modules/services/web-apps/mastodon.nix @@ -229,7 +229,7 @@ in { streamingProcesses = lib.mkOption { description = lib.mdDoc '' Number of processes used by the mastodon-streaming service. - Recommended is the amount of your CPU cores minus one. + Please define this explicitly, recommended is the amount of your CPU cores minus one. ''; type = lib.types.ints.positive; example = 3; diff --git a/nixos/modules/services/web-apps/mattermost.nix b/nixos/modules/services/web-apps/mattermost.nix index f19465eeb59a5..5035594323749 100644 --- a/nixos/modules/services/web-apps/mattermost.nix +++ b/nixos/modules/services/web-apps/mattermost.nix @@ -102,7 +102,7 @@ in services.mattermost = { enable = mkEnableOption (lib.mdDoc "Mattermost chat server"); - package = mkPackageOption pkgs "mattermostl" { }; + package = mkPackageOption pkgs "mattermost" { }; statePath = mkOption { type = types.str; diff --git a/nixos/modules/services/web-apps/windmill.nix b/nixos/modules/services/web-apps/windmill.nix new file mode 100644 index 0000000000000..8e940dabdc1f8 --- /dev/null +++ b/nixos/modules/services/web-apps/windmill.nix @@ -0,0 +1,177 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.services.windmill; +in +{ + options.services.windmill = { + enable = lib.mkEnableOption (lib.mdDoc "windmill service"); + + serverPort = lib.mkOption { + type = lib.types.port; + default = 8001; + description = lib.mdDoc "Port the windmill server listens on."; + }; + + lspPort = lib.mkOption { + type = lib.types.port; + default = 3001; + description = lib.mdDoc "Port the windmill lsp listens on."; + }; + + database = { + name = lib.mkOption { + type = lib.types.str; + # the simplest database setup is to have the database named like the user. + default = "windmill"; + description = lib.mdDoc "Database name."; + }; + + user = lib.mkOption { + type = lib.types.str; + # the simplest database setup is to have the database user like the name. + default = "windmill"; + description = lib.mdDoc "Database user."; + }; + + urlPath = lib.mkOption { + type = lib.types.path; + description = lib.mdDoc '' + Path to the file containing the database url windmill should connect to. This is not deducted from database user and name as it might contain a secret + ''; + example = "config.age.secrets.DATABASE_URL_FILE.path"; + }; + createLocally = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc "Whether to create a local database automatically."; + }; + }; + + baseUrl = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc '' + The base url that windmill will be served on. + ''; + example = "https://windmill.example.com"; + }; + + logLevel = lib.mkOption { + type = lib.types.enum [ "error" "warn" "info" "debug" "trace" ]; + default = "info"; + description = lib.mdDoc "Log level"; + }; + }; + + config = lib.mkIf cfg.enable { + + services.postgresql = lib.optionalAttrs (cfg.database.createLocally) { + enable = lib.mkDefault true; + + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.database.user; + ensureDBOwnership = true; + } + ]; + + }; + + systemd.services = + let + serviceConfig = { + DynamicUser = true; + # using the same user to simplify db connection + User = cfg.database.user; + ExecStart = "${pkgs.windmill}/bin/windmill"; + + Restart = "always"; + LoadCredential = [ + "DATABASE_URL_FILE:${cfg.database.urlPath}" + ]; + }; + in + { + + # coming from https://github.com/windmill-labs/windmill/blob/main/init-db-as-superuser.sql + # modified to not grant priviledges on all tables + # create role windmill_user and windmill_admin only if they don't exist + postgresql.postStart = lib.mkIf cfg.database.createLocally (lib.mkAfter '' + $PSQL -tA <<"EOF" +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT FROM pg_catalog.pg_roles + WHERE rolname = 'windmill_user' + ) THEN + CREATE ROLE windmill_user; + GRANT ALL PRIVILEGES ON DATABASE ${cfg.database.name} TO windmill_user; + ELSE + RAISE NOTICE 'Role "windmill_user" already exists. Skipping.'; + END IF; + IF NOT EXISTS ( + SELECT FROM pg_catalog.pg_roles + WHERE rolname = 'windmill_admin' + ) THEN + CREATE ROLE windmill_admin WITH BYPASSRLS; + GRANT windmill_user TO windmill_admin; + ELSE + RAISE NOTICE 'Role "windmill_admin" already exists. Skipping.'; + END IF; + GRANT windmill_admin TO windmill; +END +$$; +EOF + ''); + + windmill-server = { + description = "Windmill server"; + after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = serviceConfig // { StateDirectory = "windmill";}; + + environment = { + DATABASE_URL_FILE = "%d/DATABASE_URL_FILE"; + PORT = builtins.toString cfg.serverPort; + WM_BASE_URL = cfg.baseUrl; + RUST_LOG = cfg.logLevel; + MODE = "server"; + }; + }; + + windmill-worker = { + description = "Windmill worker"; + after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = serviceConfig // { StateDirectory = "windmill-worker";}; + + environment = { + DATABASE_URL_FILE = "%d/DATABASE_URL_FILE"; + WM_BASE_URL = cfg.baseUrl; + RUST_LOG = cfg.logLevel; + MODE = "worker"; + WORKER_GROUP = "default"; + KEEP_JOB_DIR = "false"; + }; + }; + + windmill-worker-native = { + description = "Windmill worker native"; + after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = serviceConfig // { StateDirectory = "windmill-worker-native";}; + + environment = { + DATABASE_URL_FILE = "%d/DATABASE_URL_FILE"; + WM_BASE_URL = cfg.baseUrl; + RUST_LOG = cfg.logLevel; + MODE = "worker"; + WORKER_GROUP = "native"; + }; + }; + }; + }; +} diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index 9cc7c4381620f..027479b1ce094 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -338,6 +338,7 @@ in # Enable helpful DBus services. services.accounts-daemon.enable = true; + programs.dconf.enable = true; # when changing an account picture the accounts-daemon reads a temporary file containing the image which systemsettings5 may place under /tmp systemd.services.accounts-daemon.serviceConfig.PrivateTmp = false; services.power-profiles-daemon.enable = mkDefault true; diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 33261021480f1..3e10770812db6 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -1612,7 +1612,7 @@ let description = lib.mdDoc '' Each attribute in this set specifies an option in the `[WireGuardPeer]` section of the unit. See - {manpage}`systemd.network(5)` for details. + {manpage}`systemd.netdev(5)` for details. ''; }; }; diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index fd92a0014002c..784040f0ce9e3 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -17,7 +17,7 @@ let cfgZED = config.services.zfs.zed; selectModulePackage = package: config.boot.kernelPackages.${package.kernelModuleAttribute}; - clevisDatasets = map (e: e.device) (filter (e: (hasAttr e.device config.boot.initrd.clevis.devices) && e.fsType == "zfs" && (fsNeededForBoot e)) config.system.build.fileSystems); + clevisDatasets = map (e: e.device) (filter (e: e.device != null && (hasAttr e.device config.boot.initrd.clevis.devices) && e.fsType == "zfs" && (fsNeededForBoot e)) config.system.build.fileSystems); inInitrd = any (fs: fs == "zfs") config.boot.initrd.supportedFilesystems; @@ -157,7 +157,7 @@ let poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool. fi if poolImported "${pool}"; then - ${concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem} || true ") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets)} + ${optionalString config.boot.initrd.clevis.enable (concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem} || true ") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets))} ${optionalString keyLocations.hasKeys '' @@ -630,7 +630,7 @@ in poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool. fi - ${concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem}") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets)} + ${optionalString config.boot.initrd.clevis.enable (concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem}") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets))} ${if isBool cfgZfs.requestEncryptionCredentials then optionalString cfgZfs.requestEncryptionCredentials '' diff --git a/nixos/tests/harmonia.nix b/nixos/tests/harmonia.nix index 6cf9ad4d23358..a9beac82f8e12 100644 --- a/nixos/tests/harmonia.nix +++ b/nixos/tests/harmonia.nix @@ -13,6 +13,9 @@ networking.firewall.allowedTCPPorts = [ 5000 ]; system.extraDependencies = [ pkgs.emptyFile ]; + + # check that extra-allowed-users is effective for harmonia + nix.settings.allowed-users = []; }; client01 = { diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index e1588088ba198..9200723f35e7b 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -43,7 +43,7 @@ in { # test loading custom components customComponents = with pkgs.home-assistant-custom-components; [ - prometheus-sensor + prometheus_sensor ]; # test loading lovelace modules diff --git a/nixos/tests/zammad.nix b/nixos/tests/zammad.nix index 7a2d40e82b3ed..1b2f245946993 100644 --- a/nixos/tests/zammad.nix +++ b/nixos/tests/zammad.nix @@ -4,7 +4,7 @@ import ./make-test-python.nix ( { name = "zammad"; - meta.maintainers = with lib.maintainers; [ garbas taeer n0emis ]; + meta.maintainers = with lib.maintainers; [ taeer n0emis netali ]; nodes.machine = { config, ... }: { services.zammad.enable = true; @@ -44,9 +44,10 @@ import ./make-test-python.nix ( testScript = '' start_all() machine.wait_for_unit("postgresql.service") + machine.wait_for_unit("redis-zammad.service") machine.wait_for_unit("zammad-web.service") machine.wait_for_unit("zammad-websocket.service") - machine.wait_for_unit("zammad-scheduler.service") + machine.wait_for_unit("zammad-worker.service") # wait for zammad to fully come up machine.sleep(120) |