1{ config, lib , pkgs, ...}:
2
3with lib;
4with import ./systemd-unit-options.nix { inherit config lib; };
5with import ./systemd-lib.nix { inherit config lib pkgs; };
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"
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"
30 ])
31 (assertValueOneOf "ReadOnly" boolValues)
32 (assertValueOneOf "Volatile" (boolValues ++ [ "state" ]))
33 (assertValueOneOf "PrivateUsersChown" boolValues)
34 ];
35
36 checkNetwork = checkUnitConfig "Network" [
37 (assertOnlyFields [
38 "Private" "VirtualEthernet" "VirtualEthernetExtra" "Interface" "MACVLAN"
39 "IPVLAN" "Bridge" "Zone" "Port"
40 ])
41 (assertValueOneOf "Private" boolValues)
42 (assertValueOneOf "VirtualEthernet" boolValues)
43 ];
44
45 instanceOptions = {
46 options = sharedOptions // {
47 execConfig = mkOption {
48 default = {};
49 example = { Parameters = "/bin/sh"; };
50 type = types.addCheck (types.attrsOf unitOption) checkExec;
51 description = ''
52 Each attribute in this set specifies an option in the
53 <literal>[Exec]</literal> section of this unit. See
54 <citerefentry><refentrytitle>systemd.nspawn</refentrytitle>
55 <manvolnum>5</manvolnum></citerefentry> for details.
56 '';
57 };
58
59 filesConfig = mkOption {
60 default = {};
61 example = { Bind = [ "/home/alice" ]; };
62 type = types.addCheck (types.attrsOf unitOption) checkFiles;
63 description = ''
64 Each attribute in this set specifies an option in the
65 <literal>[Files]</literal> section of this unit. See
66 <citerefentry><refentrytitle>systemd.nspawn</refentrytitle>
67 <manvolnum>5</manvolnum></citerefentry> for details.
68 '';
69 };
70
71 networkConfig = mkOption {
72 default = {};
73 example = { Private = false; };
74 type = types.addCheck (types.attrsOf unitOption) checkNetwork;
75 description = ''
76 Each attribute in this set specifies an option in the
77 <literal>[Network]</literal> section of this unit. See
78 <citerefentry><refentrytitle>systemd.nspawn</refentrytitle>
79 <manvolnum>5</manvolnum></citerefentry> for details.
80 '';
81 };
82 };
83
84 };
85
86 instanceToUnit = name: def:
87 let base = {
88 text = ''
89 [Exec]
90 ${attrsToSection def.execConfig}
91
92 [Files]
93 ${attrsToSection def.filesConfig}
94
95 [Network]
96 ${attrsToSection def.networkConfig}
97 '';
98 } // def;
99 in base // { unit = makeUnit name base; };
100
101in {
102
103 options = {
104
105 systemd.nspawn = mkOption {
106 default = {};
107 type = with types; attrsOf (submodule instanceOptions);
108 description = "Definition of systemd-nspawn configurations.";
109 };
110
111 };
112
113 config =
114 let
115 units = mapAttrs' (n: v: let nspawnFile = "${n}.nspawn"; in nameValuePair nspawnFile (instanceToUnit nspawnFile v)) cfg;
116 in
117 mkMerge [
118 (mkIf (cfg != {}) {
119 environment.etc."systemd/nspawn".source = mkIf (cfg != {}) (generateUnits' false "nspawn" units [] []);
120 })
121 {
122 systemd.targets.multi-user.wants = [ "machines.target" ];
123
124 # Workaround for https://github.com/NixOS/nixpkgs/pull/67232#issuecomment-531315437 and https://github.com/systemd/systemd/issues/13622
125 # Once systemd fixes this upstream, we can re-enable -U
126 systemd.services."systemd-nspawn@".serviceConfig.ExecStart = [
127 "" # deliberately empty. signals systemd to override the ExecStart
128 # Only difference between upstream is that we do not pass the -U flag
129 "${config.systemd.package}/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth --settings=override --machine=%i"
130 ];
131 }
132 ];
133}