1{
2 lib,
3 config,
4 options,
5 pkgs,
6 ...
7}:
8
9let
10 inherit (lib)
11 concatMapAttrs
12 mkOption
13 types
14 concatLists
15 mapAttrsToList
16 ;
17
18 portable-lib = import ../portable/lib.nix { inherit lib; };
19
20 dash =
21 before: after:
22 if after == "" then
23 before
24 else if before == "" then
25 after
26 else
27 "${before}-${after}";
28
29 makeNixosEtcFiles =
30 prefix: service:
31 let
32 # Convert configData entries to environment.etc entries
33 serviceConfigData = lib.mapAttrs' (name: cfg: {
34 name =
35 # cfg.path is read only and prefixed with unique service name; see ./config-data-path.nix
36 assert lib.hasPrefix "/etc/system-services" cfg.path;
37 lib.removePrefix "/etc/" cfg.path;
38 value = {
39 inherit (cfg) enable source;
40 };
41 }) (service.configData or { });
42
43 # Recursively process sub-services
44 subServiceConfigData = concatMapAttrs (
45 subServiceName: subService: makeNixosEtcFiles (dash prefix subServiceName) subService
46 ) service.services;
47 in
48 serviceConfigData // subServiceConfigData;
49
50 makeUnits =
51 unitType: prefix: service:
52 concatMapAttrs (unitName: unitModule: {
53 "${dash prefix unitName}" =
54 { ... }:
55 {
56 imports = [ unitModule ];
57 };
58 }) service.systemd.${unitType}
59 // concatMapAttrs (
60 subServiceName: subService: makeUnits unitType (dash prefix subServiceName) subService
61 ) service.services;
62
63 modularServiceConfiguration = portable-lib.configure {
64 serviceManagerPkgs = pkgs;
65 extraRootModules = [
66 ./service.nix
67 ./config-data-path.nix
68 ];
69 extraRootSpecialArgs = {
70 systemdPackage = config.systemd.package;
71 };
72 };
73in
74{
75 _class = "nixos";
76
77 # First half of the magic: mix systemd logic into the otherwise abstract services
78 options = {
79 system.services = mkOption {
80 description = ''
81 A collection of NixOS [modular services](https://nixos.org/manual/nixos/unstable/#modular-services) that are configured as systemd services.
82 '';
83 type = types.attrsOf modularServiceConfiguration.serviceSubmodule;
84 default = { };
85 visible = "shallow";
86 };
87 };
88
89 # Second half of the magic: siphon units that were defined in isolation to the system
90 config = {
91
92 assertions = concatLists (
93 mapAttrsToList (
94 name: cfg: portable-lib.getAssertions (options.system.services.loc ++ [ name ]) cfg
95 ) config.system.services
96 );
97
98 warnings = concatLists (
99 mapAttrsToList (
100 name: cfg: portable-lib.getWarnings (options.system.services.loc ++ [ name ]) cfg
101 ) config.system.services
102 );
103
104 systemd.services = concatMapAttrs (
105 serviceName: topLevelService: makeUnits "services" serviceName topLevelService
106 ) config.system.services;
107
108 systemd.sockets = concatMapAttrs (
109 serviceName: topLevelService: makeUnits "sockets" serviceName topLevelService
110 ) config.system.services;
111
112 environment.etc = concatMapAttrs (
113 serviceName: topLevelService: makeNixosEtcFiles serviceName topLevelService
114 ) config.system.services;
115 };
116}