1{ config, lib, pkgs, utils, ...}:
2
3with utils.systemdUtils.unitOptions;
4with utils.systemdUtils.lib;
5with lib;
6
7let
8 cfg = config.systemd.nspawn;
9
10 checkExec = checkUnitConfig "Exec" [
11 (assertOnlyFields [
12 "Boot" "ProcessTwo" "Parameters" "Environment" "User" "WorkingDirectory"
13 "PivotRoot" "Capability" "DropCapability" "NoNewPrivileges" "KillSignal"
14 "Personality" "MachineID" "PrivateUsers" "NotifyReady" "SystemCallFilter"
15 "LimitCPU" "LimitFSIZE" "LimitDATA" "LimitSTACK" "LimitCORE" "LimitRSS"
16 "LimitNOFILE" "LimitAS" "LimitNPROC" "LimitMEMLOCK" "LimitLOCKS"
17 "LimitSIGPENDING" "LimitMSGQUEUE" "LimitNICE" "LimitRTPRIO" "LimitRTTIME"
18 "OOMScoreAdjust" "CPUAffinity" "Hostname" "ResolvConf" "Timezone"
19 "LinkJournal" "Ephemeral" "AmbientCapability"
20 ])
21 (assertValueOneOf "Boot" boolValues)
22 (assertValueOneOf "ProcessTwo" boolValues)
23 (assertValueOneOf "NotifyReady" boolValues)
24 ];
25
26 checkFiles = checkUnitConfig "Files" [
27 (assertOnlyFields [
28 "ReadOnly" "Volatile" "Bind" "BindReadOnly" "TemporaryFileSystem"
29 "Overlay" "OverlayReadOnly" "PrivateUsersChown" "BindUser"
30 "Inaccessible" "PrivateUsersOwnership"
31 ])
32 (assertValueOneOf "ReadOnly" boolValues)
33 (assertValueOneOf "Volatile" (boolValues ++ [ "state" ]))
34 (assertValueOneOf "PrivateUsersChown" boolValues)
35 (assertValueOneOf "PrivateUsersOwnership" [ "off" "chown" "map" "auto" ])
36 ];
37
38 checkNetwork = checkUnitConfig "Network" [
39 (assertOnlyFields [
40 "Private" "VirtualEthernet" "VirtualEthernetExtra" "Interface" "MACVLAN"
41 "IPVLAN" "Bridge" "Zone" "Port"
42 ])
43 (assertValueOneOf "Private" boolValues)
44 (assertValueOneOf "VirtualEthernet" boolValues)
45 ];
46
47 instanceOptions = {
48 options =
49 (getAttrs [ "enable" ] sharedOptions)
50 // {
51 execConfig = mkOption {
52 default = {};
53 example = { Parameters = "/bin/sh"; };
54 type = types.addCheck (types.attrsOf unitOption) checkExec;
55 description = ''
56 Each attribute in this set specifies an option in the
57 `[Exec]` section of this unit. See
58 {manpage}`systemd.nspawn(5)` for details.
59 '';
60 };
61
62 filesConfig = mkOption {
63 default = {};
64 example = { Bind = [ "/home/alice" ]; };
65 type = types.addCheck (types.attrsOf unitOption) checkFiles;
66 description = ''
67 Each attribute in this set specifies an option in the
68 `[Files]` section of this unit. See
69 {manpage}`systemd.nspawn(5)` for details.
70 '';
71 };
72
73 networkConfig = mkOption {
74 default = {};
75 example = { Private = false; };
76 type = types.addCheck (types.attrsOf unitOption) checkNetwork;
77 description = ''
78 Each attribute in this set specifies an option in the
79 `[Network]` section of this unit. See
80 {manpage}`systemd.nspawn(5)` for details.
81 '';
82 };
83 };
84
85 };
86
87 instanceToUnit = name: def:
88 let base = {
89 text = ''
90 [Exec]
91 ${attrsToSection def.execConfig}
92
93 [Files]
94 ${attrsToSection def.filesConfig}
95
96 [Network]
97 ${attrsToSection def.networkConfig}
98 '';
99 } // def;
100 in base // { unit = makeUnit name base; };
101
102in {
103
104 options = {
105
106 systemd.nspawn = mkOption {
107 default = {};
108 type = with types; attrsOf (submodule instanceOptions);
109 description = "Definition of systemd-nspawn configurations.";
110 };
111
112 };
113
114 config =
115 let
116 units = mapAttrs' (n: v: let nspawnFile = "${n}.nspawn"; in nameValuePair nspawnFile (instanceToUnit nspawnFile v)) cfg;
117 in
118 mkMerge [
119 (mkIf (cfg != {}) {
120 environment.etc."systemd/nspawn".source = mkIf (cfg != {}) (generateUnits {
121 allowCollisions = false;
122 type = "nspawn";
123 inherit units;
124 upstreamUnits = [];
125 upstreamWants = [];
126 });
127 })
128 {
129 systemd.targets.multi-user.wants = [ "machines.target" ];
130 }
131 ];
132}