diff --git a/nixos/lib/systemd-submodules.nix b/nixos/lib/systemd-submodules.nix new file mode 100644 index 000000000000000..99d0d232397a385 --- /dev/null +++ b/nixos/lib/systemd-submodules.nix @@ -0,0 +1,193 @@ +{ + config, + lib, + pkgs, + utils, +}: let + mountModule' = name: module: {config, ...} @ args: let + moduleInstance = module (args // {config = config.${name};}); + in { + options.${name} = moduleInstance.options; + config.${name} = moduleInstance.config; + }; + + mountModule = names: module: lib.foldr mountModule' module names; + + inherit (utils.systemdUtils.lib) generateUnits makeUnit unitConfig mountConfig automountConfig; + inherit (utils.systemdUtils.unitOptions) concreteUnitOptions mountOptions automountOptions; +in + with lib; rec { + mkUnitTypeModule = { + name, + extension, + subOptions, + extraConfigs ? [], + toUnit, + description, + }: {config, ...}: { + options = { + "${name}" = mkOption { + default = {}; + type = with types; attrsOf (submodule ([{options = subOptions;} unitConfig] ++ extraConfigs)); + description = description; + }; + }; + + config = { + units = + mapAttrs' (n: v: nameValuePair "${n}${extension}" (toUnit n v)) config.${name}; + }; + }; + + mkModules = { + title, + type, + upstreamUnits ? [], + upstreamWants ? [], + suppressedUnits ? [], + mount ? [], + }: + mapAttrs (name: module: mountModule mount module) { + units = {config, ...}: { + options = { + units = mkOption { + description = "Definition of ${title} units."; + default = {}; + type = with types; + attrsOf (submodule ( + { + name, + config, + ... + }: { + options = concreteUnitOptions; + config = { + unit = mkDefault (makeUnit name config); + }; + } + )); + }; + + unitsSource = mkOption { + internal = true; + visible = false; + type = types.path; + }; + + upstreamUnits = mkOption { + type = with types; listOf str; + default = upstreamUnits; + }; + + upstreamWants = mkOption { + type = with types; listOf str; + default = upstreamWants; + }; + }; + + config = { + unitsSource = let + enabledUpstreamUnits = filter (n: !elem n suppressedUnits) config.upstreamUnits; + enabledUnits = filterAttrs (n: v: !elem n suppressedUnits) config.units; + in + generateUnits type enabledUnits enabledUpstreamUnits config.upstreamWants; + }; + }; + + targets = mkUnitTypeModule { + name = "targets"; + extension = ".target"; + subOptions = utils.systemdUtils.unitOptions.targetOptions; + toUnit = utils.systemdUtils.lib.targetToUnit; + description = "Definition of ${title} target units."; + }; + + services = mkUnitTypeModule { + name = "services"; + extension = ".service"; + subOptions = utils.systemdUtils.unitOptions.serviceOptions; + extraConfigs = [utils.systemdUtils.lib.serviceConfig]; + toUnit = utils.systemdUtils.lib.serviceToUnit; + description = "Definition of ${title} service units."; + }; + + sockets = mkUnitTypeModule { + name = "sockets"; + extension = ".socket"; + subOptions = utils.systemdUtils.unitOptions.socketOptions; + toUnit = utils.systemdUtils.lib.socketToUnit; + description = "Definition of ${title} socket units."; + }; + + timers = mkUnitTypeModule { + name = "timers"; + extension = ".timer"; + subOptions = utils.systemdUtils.unitOptions.timerOptions; + toUnit = utils.systemdUtils.lib.timerToUnit; + description = "Definition of ${title} timer units."; + }; + + paths = mkUnitTypeModule { + name = "paths"; + extension = ".path"; + subOptions = utils.systemdUtils.unitOptions.pathOptions; + toUnit = utils.systemdUtils.lib.pathToUnit; + description = "Definition of ${title} path units."; + }; + + slices = mkUnitTypeModule { + name = "slices"; + extension = ".slice"; + subOptions = utils.systemdUtils.unitOptions.sliceOptions; + extraConfigs = [utils.systemdUtils.lib.sliceConfig]; + toUnit = utils.systemdUtils.lib.sliceToUnit; + description = "Definition of ${title} slice configurations."; + }; + + mounts = {config, ...}: { + options = { + mounts = mkOption { + default = []; + type = with types; listOf (submodule [{options = mountOptions;} unitConfig mountConfig]); + description = '' + Definition of ${title} mount units. + This is a list instead of an attrSet, because systemd mandates the names to be derived from + the 'where' attribute. + ''; + }; + }; + + config = { + units = listToAttrs (map + (v: let + n = escapeSystemdPath v.where; + in + nameValuePair "${n}.mount" (mountToUnit n v)) + config.mounts); + }; + }; + + automounts = {config, ...}: { + options = { + automounts = mkOption { + default = []; + type = with types; listOf (submodule [{options = automountOptions;} unitConfig automountConfig]); + description = '' + Definition of ${title} automount units. + This is a list instead of an attrSet, because systemd mandates the names to be derived from + the 'where' attribute. + ''; + }; + }; + + config = { + units = listToAttrs (map + (v: let + n = escapeSystemdPath v.where; + in + nameValuePair "${n}.automount" (automountToUnit n v)) + config.automounts); + }; + }; + }; + } diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 057474c607ac852..8c5dac9298eee9d 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, utils, ... }: -with utils; -with systemdUtils.unitOptions; with lib; let @@ -10,24 +8,6 @@ let systemd = cfg.package; - inherit (systemdUtils.lib) - makeUnit - generateUnits - makeJobScript - unitConfig - serviceConfig - mountConfig - automountConfig - commonUnitText - targetToUnit - serviceToUnit - socketToUnit - timerToUnit - pathToUnit - mountToUnit - automountToUnit - sliceToUnit; - upstreamSystemUnits = [ # Targets. "basic.target" @@ -182,18 +162,6 @@ in description = "The systemd package."; }; - systemd.units = mkOption { - description = "Definition of systemd units."; - default = {}; - type = with types; attrsOf (submodule ( - { name, config, ... }: - { options = concreteUnitOptions; - config = { - unit = mkDefault (makeUnit name config); - }; - })); - }; - systemd.packages = mkOption { default = []; type = types.listOf types.package; @@ -201,62 +169,6 @@ in description = "Packages providing systemd units and hooks."; }; - systemd.targets = mkOption { - default = {}; - type = with types; attrsOf (submodule [ { options = targetOptions; } unitConfig] ); - description = "Definition of systemd target units."; - }; - - systemd.services = mkOption { - default = {}; - type = with types; attrsOf (submodule [ { options = serviceOptions; } unitConfig serviceConfig ]); - description = "Definition of systemd service units."; - }; - - systemd.sockets = mkOption { - default = {}; - type = with types; attrsOf (submodule [ { options = socketOptions; } unitConfig ]); - description = "Definition of systemd socket units."; - }; - - systemd.timers = mkOption { - default = {}; - type = with types; attrsOf (submodule [ { options = timerOptions; } unitConfig ]); - description = "Definition of systemd timer units."; - }; - - systemd.paths = mkOption { - default = {}; - type = with types; attrsOf (submodule [ { options = pathOptions; } unitConfig ]); - description = "Definition of systemd path units."; - }; - - systemd.mounts = mkOption { - default = []; - type = with types; listOf (submodule [ { options = mountOptions; } unitConfig mountConfig ]); - description = '' - Definition of systemd mount units. - This is a list instead of an attrSet, because systemd mandates the names to be derived from - the 'where' attribute. - ''; - }; - - systemd.automounts = mkOption { - default = []; - type = with types; listOf (submodule [ { options = automountOptions; } unitConfig automountConfig ]); - description = '' - Definition of systemd automount units. - This is a list instead of an attrSet, because systemd mandates the names to be derived from - the 'where' attribute. - ''; - }; - - systemd.slices = mkOption { - default = {}; - type = with types; attrsOf (submodule [ { options = sliceOptions; } unitConfig] ); - description = "Definition of slice configurations."; - }; - systemd.generators = mkOption { type = types.attrsOf types.path; default = {}; @@ -467,11 +379,8 @@ in done ${concatStrings (mapAttrsToList (exec: target: "ln -s ${target} $out/${exec};\n") links)} ''; - - enabledUpstreamSystemUnits = filter (n: ! elem n cfg.suppressedSystemUnits) upstreamSystemUnits; - enabledUnits = filterAttrs (n: v: ! elem n cfg.suppressedSystemUnits) cfg.units; in ({ - "systemd/system".source = generateUnits "system" enabledUnits enabledUpstreamSystemUnits upstreamSystemWants; + "systemd/system".source = cfg.unitsSource; "systemd/system.conf".text = '' [Manager] @@ -528,20 +437,6 @@ in unitConfig.X-StopOnReconfiguration = true; }; - systemd.units = - mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths - // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services - // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.slices - // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets - // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets - // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.timers - // listToAttrs (map - (v: let n = escapeSystemdPath v.where; - in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts) - // listToAttrs (map - (v: let n = escapeSystemdPath v.where; - in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); - system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [ "DEVTMPFS" "CGROUPS" "INOTIFY_USER" "SIGNALFD" "TIMERFD" "EPOLL" "NET" "SYSFS" "PROC_FS" "FHANDLE" "CRYPTO_USER_API_HASH" "CRYPTO_HMAC" @@ -611,7 +506,24 @@ in # FIXME: Remove these eventually. imports = - [ (mkRenamedOptionModule [ "boot" "systemd" "sockets" ] [ "systemd" "sockets" ]) + (with (import ./../../../lib/systemd-submodules.nix { inherit config lib pkgs utils; }).mkModules { + title = "systemd"; + type = "system"; + upstreamUnits = upstreamSystemUnits; + upstreamWants = upstreamSystemWants; + mount = [ "systemd" ]; + }; [ + units + targets + services + sockets + timers + mounts + automounts + paths + slices + ]) ++ [ + (mkRenamedOptionModule [ "boot" "systemd" "sockets" ] [ "systemd" "sockets" ]) (mkRenamedOptionModule [ "boot" "systemd" "targets" ] [ "systemd" "targets" ]) (mkRenamedOptionModule [ "boot" "systemd" "services" ] [ "systemd" "services" ]) (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ])