From 90162e8113546e3d16f1b8dead39f3ba7fee6c43 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Wed, 20 Aug 2025 11:34:52 +0200 Subject: [PATCH] nixos/service/portable: Provide an entrypoint function ... and tidy up in various small ways. This should help a bit to make more clear the separation between the portable parts and the systemd system service parts. --- nixos/doc/manual/default.nix | 12 ++++- nixos/modules/system/service/portable/lib.nix | 46 ++++++++++++++++++- .../system/service/portable/service.nix | 9 +++- .../system/service/systemd/service.nix | 4 +- .../modules/system/service/systemd/system.nix | 41 ++++++----------- 5 files changed, 81 insertions(+), 31 deletions(-) diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index 33a2e250f0a3..b552986f526b 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -25,6 +25,7 @@ let escapeShellArg concatMapStringsSep sourceFilesBySuffices + modules ; common = import ./common.nix; @@ -129,7 +130,16 @@ let ''; portableServiceOptions = buildPackages.nixosOptionsDoc { - inherit (evalModules { modules = [ ../../modules/system/service/portable/service.nix ]; }) options; + inherit + (evalModules { + modules = [ + (modules.importApply ../../modules/system/service/portable/service.nix { + pkgs = throw "nixos docs / portableServiceOptions: Do not reference pkgs in docs"; + }) + ]; + }) + options + ; inherit revision warningsAreErrors; transformOptions = opt: diff --git a/nixos/modules/system/service/portable/lib.nix b/nixos/modules/system/service/portable/lib.nix index 0529f81f8561..88db80f91494 100644 --- a/nixos/modules/system/service/portable/lib.nix +++ b/nixos/modules/system/service/portable/lib.nix @@ -1,6 +1,11 @@ { lib, ... }: let - inherit (lib) concatLists mapAttrsToList showOption; + inherit (lib) + concatLists + mapAttrsToList + showOption + types + ; in rec { flattenMapServicesConfigToList = @@ -30,4 +35,43 @@ rec { assertion = ass.assertion; }) config.assertions ); + + /** + This is the entrypoint for the portable part of modular services. + + It provides the various options that are consumed by service manager implementations. + + # Inputs + + `serviceManagerPkgs`: A Nixpkgs instance which will be used for built-in logic such as converting `configData..text` to a store path. + + `extraRootModules`: Modules to be loaded into the "root" service submodule, but not into its sub-`services`. That's the modules' own responsibility. + + `extraRootSpecialArgs`: Fixed module arguments that are provided in a similar manner to `extraRootModules`. + + # Output + + An attribute set. + + `serviceSubmodule`: a Module System option type which is a `submodule` with the portable modules and this function's inputs loaded into it. + */ + configure = + { + serviceManagerPkgs, + extraRootModules ? [ ], + extraRootSpecialArgs ? { }, + }: + let + modules = [ + (lib.modules.importApply ./service.nix { pkgs = serviceManagerPkgs; }) + ]; + serviceSubmodule = types.submoduleWith { + class = "service"; + modules = modules ++ extraRootModules; + specialArgs = extraRootSpecialArgs; + }; + in + { + inherit serviceSubmodule; + }; } diff --git a/nixos/modules/system/service/portable/service.nix b/nixos/modules/system/service/portable/service.nix index 9b9bce4082f2..3295a6e3bb44 100644 --- a/nixos/modules/system/service/portable/service.nix +++ b/nixos/modules/system/service/portable/service.nix @@ -1,3 +1,9 @@ +# Non-module arguments +# These are separate from the module arguments to avoid implicit dependencies. +# This makes service modules self-contains, allowing mixing of Nixpkgs versions. +{ pkgs }: + +# The module { lib, ... @@ -11,13 +17,14 @@ in _class = "service"; imports = [ ../../../misc/assertions.nix + (lib.modules.importApply ./config-data.nix { inherit pkgs; }) ]; options = { services = mkOption { type = types.attrsOf ( types.submoduleWith { modules = [ - ./service.nix + (lib.modules.importApply ./service.nix { inherit pkgs; }) ]; } ); diff --git a/nixos/modules/system/service/systemd/service.nix b/nixos/modules/system/service/systemd/service.nix index 9ba9bb7bf3f2..30c2335b81e3 100644 --- a/nixos/modules/system/service/systemd/service.nix +++ b/nixos/modules/system/service/systemd/service.nix @@ -52,8 +52,8 @@ let in { + _class = "service"; imports = [ - ../portable/service.nix (lib.mkAliasOptionModule [ "systemd" "service" ] [ "systemd" "services" "" ]) (lib.mkAliasOptionModule [ "systemd" "socket" ] [ "systemd" "sockets" "" ]) ]; @@ -101,6 +101,8 @@ in }; } ); + # Rendered by the portable docs instead. + visible = false; }; }; config = { diff --git a/nixos/modules/system/service/systemd/system.nix b/nixos/modules/system/service/systemd/system.nix index 978c59222e9c..3405072089e1 100644 --- a/nixos/modules/system/service/systemd/system.nix +++ b/nixos/modules/system/service/systemd/system.nix @@ -59,41 +59,28 @@ let // concatMapAttrs ( subServiceName: subService: makeUnits unitType (dash prefix subServiceName) subService ) service.services; + + modularServiceConfiguration = portable-lib.configure { + serviceManagerPkgs = pkgs; + extraRootModules = [ + ./service.nix + ./config-data-path.nix + ]; + extraRootSpecialArgs = { + systemdPackage = config.systemd.package; + }; + }; in { + _class = "nixos"; + # First half of the magic: mix systemd logic into the otherwise abstract services options = { system.services = mkOption { description = '' A collection of NixOS [modular services](https://nixos.org/manual/nixos/unstable/#modular-services) that are configured as systemd services. ''; - type = types.attrsOf ( - types.submoduleWith { - class = "service"; - modules = [ - ./service.nix - ./config-data-path.nix - (lib.modules.importApply ../portable/config-data.nix { inherit pkgs; }) - - { - # Extend portable services option - options.services = lib.mkOption { - type = types.attrsOf ( - types.submoduleWith { - modules = [ - (lib.modules.importApply ../portable/config-data.nix { inherit pkgs; }) - ]; - } - ); - }; - } - ]; - specialArgs = { - # perhaps: features."systemd" = { }; - systemdPackage = config.systemd.package; - }; - } - ); + type = types.attrsOf modularServiceConfiguration.serviceSubmodule; default = { }; visible = "shallow"; };