systemd-network: Add assertions for user clarity

This commit is contained in:
William A. Kennington III 2014-11-20 01:41:05 -08:00
parent a332c4eac5
commit 045132a9b0

@ -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