summary refs log tree commit diff
path: root/nixos/modules/system/boot/systemd-unit-options.nix
diff options
context:
space:
mode:
authorWilliam A. Kennington III <william@wkennington.com>2014-11-20 01:41:05 -0800
committerWilliam A. Kennington III <william@wkennington.com>2014-11-26 11:22:02 -0800
commit045132a9b096a22cb6f84210fcd5223b9a770d62 (patch)
tree002f2d259d05518483c9dcbbedf7e24065a0174a /nixos/modules/system/boot/systemd-unit-options.nix
parenta332c4eac5c958c04a3873559988e892caa8c6d2 (diff)
downloadnixpkgs-045132a9b096a22cb6f84210fcd5223b9a770d62.tar
nixpkgs-045132a9b096a22cb6f84210fcd5223b9a770d62.tar.gz
nixpkgs-045132a9b096a22cb6f84210fcd5223b9a770d62.tar.bz2
nixpkgs-045132a9b096a22cb6f84210fcd5223b9a770d62.tar.lz
nixpkgs-045132a9b096a22cb6f84210fcd5223b9a770d62.tar.xz
nixpkgs-045132a9b096a22cb6f84210fcd5223b9a770d62.tar.zst
nixpkgs-045132a9b096a22cb6f84210fcd5223b9a770d62.zip
systemd-network: Add assertions for user clarity
Diffstat (limited to 'nixos/modules/system/boot/systemd-unit-options.nix')
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix215
1 files changed, 192 insertions, 23 deletions
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
index 4aceaad9e9f..52ad71a66c7 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -4,15 +4,184 @@ with lib;
 
 let
 
-  checkService = v:
-    let assertValueOneOf = name: values: attr:
-          let val = attr.${name};
-          in optional (attr ? ${name} && !elem val values) "Systemd service field `${name}' cannot have value `${val}'.";
-        checkType = assertValueOneOf "Type" ["simple" "forking" "oneshot" "dbus" "notify" "idle"];
-        checkRestart = assertValueOneOf "Restart" ["no" "on-success" "on-failure" "on-abort" "always"];
-        errors = concatMap (c: c v) [checkType checkRestart];
-    in if errors == [] then true
-       else builtins.trace (concatStringsSep "\n" errors) false;
+  boolValues = [true false "yes" "no"];
+
+  assertValueOneOf = name: values: group: attr:
+    optional (attr ? ${name} && !elem attr.${name} values)
+      "Systemd ${group} field `${name}' cannot have value `${attr.${name}}'.";
+
+  assertHasField = name: group: attr:
+    optional (!(attr ? ${name}))
+      "Systemd ${group} field `${name}' must exist.";
+
+  assertOnlyFields = fields: group: attr:
+    let badFields = filter (name: ! elem name fields) (attrNames attr); in
+    optional (badFields != [ ])
+      "Systemd ${group} has extra fields [${concatStringsSep " " badFields}].";
+
+  assertRange = name: min: max: group: attr:
+    optional (attr ? ${name} && !(min <= attr.${name} && max >= attr.${name}))
+      "Systemd ${group} field `${name}' is outside the range [${toString min},${toString max}]";
+
+  digits = map toString (range 0 9);
+
+  isByteFormat = s:
+    let
+      l = reverseList (stringToCharacters s);
+      suffix = head l;
+      nums = tail l;
+    in elem suffix (["K" "M" "G" "T"] ++ digits)
+      && all (num: elem num digits) nums;
+
+  assertByteFormat = name: group: attr:
+    optional (attr ? ${name} && ! isByteFormat attr.${name})
+      "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT].";
+
+  hexChars = stringToCharacters "0123456789abcdefABCDEF";
+
+  isMacAddress = s: stringLength s == 17
+    && flip all (splitString ":" s) (bytes:
+      all (byte: elem byte hexChars) (stringToCharacters bytes)
+    );
+
+  assertMacAddress = name: group: attr:
+    optional (attr ? ${name} && ! isMacAddress attr.${name})
+      "Systemd ${group} field `${name}' must be a valid mac address.";
+
+  checkUnitConfig = group: checks: v:
+    let errors = concatMap (c: c group v) checks; in
+    if errors == [] then true
+      else builtins.trace (concatStringsSep "\n" errors) false;
+
+  checkService = checkUnitConfig "Service" [
+    (assertValueOneOf "Type" [
+      "simple" "forking" "oneshot" "dbus" "notify" "idle"
+    ])
+    (assertValueOneOf "Restart" [
+      "no" "on-success" "on-failure" "on-abort" "always"
+    ])
+  ];
+
+  checkLink = checkUnitConfig "Link" [
+    (assertOnlyFields [
+      "Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "Name"
+      "MTUBytes" "BitsPerSecond" "Duplex" "WakeOnLan"
+    ])
+    (assertValueOneOf "MACAddressPolicy" ["persistent" "random"])
+    (assertMacAddress "MACAddress")
+    (assertValueOneOf "NamePolicy" [
+      "kernel" "database" "onboard" "slot" "path" "mac"
+    ])
+    (assertByteFormat "MTUBytes")
+    (assertByteFormat "BitsPerSecond")
+    (assertValueOneOf "Duplex" ["half" "full"])
+    (assertValueOneOf "WakeOnLan" ["phy" "magic" "off"])
+  ];
+
+  checkNetdev = checkUnitConfig "Netdev" [
+    (assertOnlyFields [
+      "Description" "Name" "Kind" "MTUBytes" "MACAddress"
+    ])
+    (assertHasField "Name")
+    (assertHasField "Kind")
+    (assertValueOneOf "Kind" [
+      "bridge" "bond" "vlan" "macvlan" "vxlan" "ipip"
+      "gre" "sit" "vti" "veth" "tun" "tap" "dummy"
+    ])
+    (assertByteFormat "MTUBytes")
+    (assertMacAddress "MACAddress")
+  ];
+
+  checkVlan = checkUnitConfig "VLAN" [
+    (assertOnlyFields ["Id"])
+    (assertRange "Id" 0 4094)
+  ];
+
+  checkMacvlan = checkUnitConfig "MACVLAN" [
+    (assertOnlyFields ["Mode"])
+    (assertValueOneOf "Mode" ["private" "vepa" "bridge" "passthru"])
+  ];
+
+  checkVxlan = checkUnitConfig "VXLAN" [
+    (assertOnlyFields ["Id" "Group" "TOS" "TTL" "MacLearning"])
+    (assertRange "TTL" 0 255)
+    (assertValueOneOf "MacLearning" boolValues)
+  ];
+
+  checkTunnel = checkUnitConfig "Tunnel" [
+    (assertOnlyFields ["Local" "Remote" "TOS" "TTL" "DiscoverPathMTU"])
+    (assertRange "TTL" 0 255)
+    (assertValueOneOf "DiscoverPathMTU" boolValues)
+  ];
+
+  checkPeer = checkUnitConfig "Peer" [
+    (assertOnlyFields ["Name" "MACAddress"])
+    (assertMacAddress "MACAddress")
+  ];
+
+  tunTapChecks = [
+    (assertOnlyFields ["OneQueue" "MultiQueue" "PacketInfo" "User" "Group"])
+    (assertValueOneOf "OneQueue" boolValues)
+    (assertValueOneOf "MultiQueue" boolValues)
+    (assertValueOneOf "PacketInfo" boolValues)
+  ];
+
+  checkTun = checkUnitConfig "Tun" tunTapChecks;
+
+  checkTap = checkUnitConfig "Tap" tunTapChecks;
+
+  checkBond = checkUnitConfig "Bond" [
+    (assertOnlyFields [
+      "Mode" "TransmitHashPolicy" "LACPTransmitRate" "MIIMonitorSec"
+      "UpDelaySec" "DownDelaySec"
+    ])
+    (assertValueOneOf "Mode" [
+      "balance-rr" "active-backup" "balance-xor"
+      "broadcast" "802.3ad" "balance-tlb" "balance-alb"
+    ])
+    (assertValueOneOf "TransmitHashPolicy" [
+      "layer2" "layer3+4" "layer2+3" "encap2+3" "802.3ad" "encap3+4"
+    ])
+    (assertValueOneOf "LACPTransmitRate" ["slow" "fast"])
+  ];
+
+  checkNetwork = checkUnitConfig "Network" [
+    (assertOnlyFields [
+      "Description" "DHCP" "DHCPServer" "IPv4LL" "IPv4LLRoute"
+      "LLMNR" "Domains" "Bridge" "Bond"
+    ])
+    (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"])
+    (assertValueOneOf "DHCPServer" boolValues)
+    (assertValueOneOf "IPv4LL" boolValues)
+    (assertValueOneOf "IPv4LLRoute" boolValues)
+    (assertValueOneOf "LLMNR" boolValues)
+  ];
+
+  checkAddress = checkUnitConfig "Address" [
+    (assertOnlyFields ["Address" "Peer" "Broadcast" "Label"])
+    (assertHasField "Address")
+  ];
+
+  checkRoute = checkUnitConfig "Route" [
+    (assertOnlyFields ["Gateway" "Destination" "Metric"])
+    (assertHasField "Gateway")
+  ];
+
+  checkDhcp = checkUnitConfig "DHCP" [
+    (assertOnlyFields [
+      "UseDNS" "UseMTU" "SendHostname" "UseHostname" "UseDomains" "UseRoutes"
+      "CriticalConnections" "VendorClassIdentifier" "RequestBroadcast"
+      "RouteMetric"
+    ])
+    (assertValueOneOf "UseDNS" boolValues)
+    (assertValueOneOf "UseMTU" boolValues)
+    (assertValueOneOf "SendHostname" boolValues)
+    (assertValueOneOf "UseHostname" boolValues)
+    (assertValueOneOf "UseDomains" boolValues)
+    (assertValueOneOf "UseRoutes" boolValues)
+    (assertValueOneOf "CriticalConnections" boolValues)
+    (assertValueOneOf "RequestBroadcast" boolValues)
+  ];
 
   unitOption = mkOptionType {
     name = "systemd option";
@@ -482,7 +651,7 @@ in rec {
     linkConfig = mkOption {
       default = {};
       example = { MACAddress = "00:ff:ee:aa:cc:dd"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkLink;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Link]</literal> section of the unit.  See
@@ -498,7 +667,7 @@ in rec {
     netdevConfig = mkOption {
       default = {};
       example = { Name = "mybridge"; Kind = "bridge"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkNetdev;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Netdev]</literal> section of the unit.  See
@@ -510,7 +679,7 @@ in rec {
     vlanConfig = mkOption {
       default = {};
       example = { Id = "4"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkVlan;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[VLAN]</literal> section of the unit.  See
@@ -522,7 +691,7 @@ in rec {
     macvlanConfig = mkOption {
       default = {};
       example = { Mode = "private"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkMacvlan;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[MACVLAN]</literal> section of the unit.  See
@@ -534,7 +703,7 @@ in rec {
     vxlanConfig = mkOption {
       default = {};
       example = { Id = "4"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkVxlan;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[VXLAN]</literal> section of the unit.  See
@@ -546,7 +715,7 @@ in rec {
     tunnelConfig = mkOption {
       default = {};
       example = { Remote = "192.168.1.1"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkTunnel;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Tunnel]</literal> section of the unit.  See
@@ -558,7 +727,7 @@ in rec {
     peerConfig = mkOption {
       default = {};
       example = { Name = "veth2"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkPeer;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Peer]</literal> section of the unit.  See
@@ -570,7 +739,7 @@ in rec {
     tunConfig = mkOption {
       default = {};
       example = { User = "openvpn"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkTun;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Tun]</literal> section of the unit.  See
@@ -582,7 +751,7 @@ in rec {
     tapConfig = mkOption {
       default = {};
       example = { User = "openvpn"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkTap;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Tap]</literal> section of the unit.  See
@@ -594,7 +763,7 @@ in rec {
     bondConfig = mkOption {
       default = {};
       example = { Mode = "802.3ad"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkBond;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Bond]</literal> section of the unit.  See
@@ -610,7 +779,7 @@ in rec {
     addressConfig = mkOption {
       default = {};
       example = { Address = "192.168.0.100/24"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkAddress;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Address]</literal> section of the unit.  See
@@ -626,7 +795,7 @@ in rec {
     routeConfig = mkOption {
       default = {};
       example = { Gateway = "192.168.0.1"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkRoute;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Route]</literal> section of the unit.  See
@@ -642,7 +811,7 @@ in rec {
     networkConfig = mkOption {
       default = {};
       example = { Description = "My Network"; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkNetwork;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[Network]</literal> section of the unit.  See
@@ -654,7 +823,7 @@ in rec {
     dhcpConfig = mkOption {
       default = {};
       example = { UseDNS = true; UseRoutes = true; };
-      type = types.attrsOf unitOption;
+      type = types.addCheck (types.attrsOf unitOption) checkDhcp;
       description = ''
         Each attribute in this set specifies an option in the
         <literal>[DHCP]</literal> section of the unit.  See