2016-10-13 21:49:04 +02:00
|
|
|
|
{ lib, ... }:
|
2015-07-24 12:23:52 +02:00
|
|
|
|
|
2016-10-20 20:21:59 +02:00
|
|
|
|
let
|
|
|
|
|
inherit (lib)
|
2018-02-28 14:30:11 +01:00
|
|
|
|
all any attrNames concatMapStringsSep concatStringsSep const filter flip
|
2018-12-02 14:14:03 +01:00
|
|
|
|
genid_uint31 hasSuffix head isInt isString length mergeOneOption mkOption
|
2016-10-20 20:21:59 +02:00
|
|
|
|
mkOptionType optional optionalAttrs optionals range splitString
|
2017-08-01 11:27:03 +02:00
|
|
|
|
stringLength substring test testString typeOf;
|
2016-10-20 20:21:59 +02:00
|
|
|
|
inherit (lib.types)
|
2022-01-29 20:50:32 +01:00
|
|
|
|
attrsOf bool either enum int lines listOf nullOr path str submodule;
|
2016-10-20 20:21:59 +02:00
|
|
|
|
in
|
2015-07-24 12:23:52 +02:00
|
|
|
|
|
2016-10-20 20:21:59 +02:00
|
|
|
|
rec {
|
2015-07-24 12:23:52 +02:00
|
|
|
|
|
2015-09-27 15:24:41 +02:00
|
|
|
|
host = submodule ({ config, ... }: {
|
2015-07-24 12:23:52 +02:00
|
|
|
|
options = {
|
|
|
|
|
name = mkOption {
|
|
|
|
|
type = label;
|
2016-02-06 18:54:01 +01:00
|
|
|
|
default = config._module.args.name;
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
|
|
|
|
cores = mkOption {
|
2018-12-05 16:52:32 +01:00
|
|
|
|
type = uint;
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
|
|
|
|
nets = mkOption {
|
|
|
|
|
type = attrsOf net;
|
2016-02-13 16:46:15 +01:00
|
|
|
|
default = {};
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
2015-08-13 12:03:59 +02:00
|
|
|
|
|
2016-10-20 20:21:59 +02:00
|
|
|
|
binary-cache.pubkey = mkOption {
|
|
|
|
|
type = nullOr binary-cache-pubkey;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-31 19:15:09 +02:00
|
|
|
|
ci = mkOption {
|
2017-05-19 00:24:52 +02:00
|
|
|
|
description = ''
|
2017-08-31 19:15:09 +02:00
|
|
|
|
If true, then the host wants to be tested by some CI system.
|
2021-11-08 04:58:14 +01:00
|
|
|
|
See ‹stockholm/krebs/2configs/buildbot-all.nix›
|
2017-05-19 00:24:52 +02:00
|
|
|
|
'';
|
|
|
|
|
type = bool;
|
2017-07-27 19:44:18 +02:00
|
|
|
|
default = false;
|
2017-05-19 00:24:52 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-08-31 19:45:58 +02:00
|
|
|
|
external = mkOption {
|
|
|
|
|
description = ''
|
|
|
|
|
Whether the host is defined externally (in contrast to being defined
|
2021-11-08 04:58:14 +01:00
|
|
|
|
in ‹stockholm›). This is useful e.g. when legacy and/or adopted
|
2017-08-31 19:45:58 +02:00
|
|
|
|
hosts should be part of retiolum or some other component.
|
|
|
|
|
'';
|
|
|
|
|
type = bool;
|
|
|
|
|
default = false;
|
|
|
|
|
};
|
|
|
|
|
|
2018-04-27 15:14:59 +02:00
|
|
|
|
monitoring = mkOption {
|
|
|
|
|
description = ''
|
|
|
|
|
Whether the host should be monitored by monitoring tools like Prometheus.
|
|
|
|
|
'';
|
|
|
|
|
type = bool;
|
|
|
|
|
default = false;
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-15 15:48:15 +01:00
|
|
|
|
consul = mkOption {
|
|
|
|
|
description = ''
|
|
|
|
|
Whether the host is a member of the global consul network
|
|
|
|
|
'';
|
|
|
|
|
type = bool;
|
|
|
|
|
default = false;
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-19 16:18:28 +01:00
|
|
|
|
owner = mkOption {
|
|
|
|
|
type = user;
|
|
|
|
|
};
|
|
|
|
|
|
2015-08-13 22:28:21 +02:00
|
|
|
|
extraZones = mkOption {
|
|
|
|
|
default = {};
|
|
|
|
|
# TODO: string is either MX, NS, A or AAAA
|
2020-04-22 16:41:58 +02:00
|
|
|
|
type = attrsOf str;
|
2015-08-13 22:28:21 +02:00
|
|
|
|
};
|
2015-09-27 00:22:50 +02:00
|
|
|
|
|
2015-07-24 18:36:16 +02:00
|
|
|
|
secure = mkOption {
|
|
|
|
|
type = bool;
|
|
|
|
|
default = false;
|
|
|
|
|
description = ''
|
|
|
|
|
If true, then the host is capable of keeping secret information.
|
|
|
|
|
|
|
|
|
|
TODO define minimum requirements for secure hosts
|
|
|
|
|
'';
|
|
|
|
|
};
|
2015-09-27 15:24:41 +02:00
|
|
|
|
|
|
|
|
|
ssh.pubkey = mkOption {
|
2016-03-16 01:54:49 +01:00
|
|
|
|
type = nullOr ssh-pubkey;
|
2015-09-27 15:24:41 +02:00
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
ssh.privkey = mkOption {
|
2016-03-16 01:54:49 +01:00
|
|
|
|
type = nullOr ssh-privkey;
|
2015-09-27 16:15:53 +02:00
|
|
|
|
default = null;
|
2015-09-27 15:24:41 +02:00
|
|
|
|
};
|
2019-03-22 07:56:13 +01:00
|
|
|
|
|
|
|
|
|
syncthing.id = mkOption {
|
|
|
|
|
# TODO syncthing id type
|
2019-04-13 14:06:36 +02:00
|
|
|
|
type = nullOr str;
|
2019-03-22 07:56:13 +01:00
|
|
|
|
default = null;
|
|
|
|
|
};
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
2015-09-27 15:24:41 +02:00
|
|
|
|
});
|
2015-07-24 12:23:52 +02:00
|
|
|
|
|
|
|
|
|
net = submodule ({ config, ... }: {
|
|
|
|
|
options = {
|
2016-04-08 03:53:34 +02:00
|
|
|
|
name = mkOption {
|
|
|
|
|
type = label;
|
|
|
|
|
default = config._module.args.name;
|
|
|
|
|
};
|
2015-07-24 12:23:52 +02:00
|
|
|
|
via = mkOption {
|
2021-11-08 04:58:14 +01:00
|
|
|
|
type =
|
|
|
|
|
# XXX break infinite recursion when generating manuals
|
|
|
|
|
if config._module.args.name == "‹name›" then
|
|
|
|
|
mkOptionType {
|
|
|
|
|
name = "‹net›";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
nullOr net;
|
2015-07-24 12:23:52 +02:00
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
addrs = mkOption {
|
2021-11-09 07:15:51 +01:00
|
|
|
|
type = listOf (either addr str);
|
2016-04-08 03:53:34 +02:00
|
|
|
|
default =
|
|
|
|
|
optional (config.ip4 != null) config.ip4.addr ++
|
|
|
|
|
optional (config.ip6 != null) config.ip6.addr;
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
|
|
|
|
aliases = mkOption {
|
|
|
|
|
# TODO nonEmptyListOf hostname
|
|
|
|
|
type = listOf hostname;
|
2015-09-27 15:24:41 +02:00
|
|
|
|
default = [];
|
|
|
|
|
};
|
2020-10-16 22:25:35 +02:00
|
|
|
|
mac = mkOption {
|
|
|
|
|
type = nullOr str;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
2016-04-08 03:53:34 +02:00
|
|
|
|
ip4 = mkOption {
|
2022-11-23 17:08:55 +01:00
|
|
|
|
type = nullOr (submodule (ip4: {
|
2016-04-08 03:53:34 +02:00
|
|
|
|
options = {
|
|
|
|
|
addr = mkOption {
|
|
|
|
|
type = addr4;
|
|
|
|
|
};
|
|
|
|
|
prefix = mkOption ({
|
2017-10-11 18:12:31 +02:00
|
|
|
|
type = cidr4;
|
2021-11-21 13:47:53 +01:00
|
|
|
|
} // {
|
|
|
|
|
retiolum.default = "10.243.0.0/16";
|
|
|
|
|
wiregrill.default = "10.244.0.0/16";
|
2022-11-23 17:08:55 +01:00
|
|
|
|
}.${config._module.args.name} or {
|
|
|
|
|
default = "${ip4.config.addr}/32";
|
|
|
|
|
});
|
2016-04-08 03:53:34 +02:00
|
|
|
|
};
|
2022-11-23 17:08:55 +01:00
|
|
|
|
}));
|
2016-04-08 03:53:34 +02:00
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
ip6 = mkOption {
|
2022-11-23 17:08:55 +01:00
|
|
|
|
type = nullOr (submodule (ip6: {
|
2016-04-08 03:53:34 +02:00
|
|
|
|
options = {
|
|
|
|
|
addr = mkOption {
|
|
|
|
|
type = addr6;
|
2017-04-13 11:13:59 +02:00
|
|
|
|
apply = lib.normalize-ip6-addr;
|
2016-04-08 03:53:34 +02:00
|
|
|
|
};
|
|
|
|
|
prefix = mkOption ({
|
2017-10-11 18:12:31 +02:00
|
|
|
|
type = cidr6;
|
2021-11-21 13:47:53 +01:00
|
|
|
|
} // {
|
|
|
|
|
retiolum.default = "42:0::/32";
|
|
|
|
|
wiregrill.default = "42:1::/32";
|
2022-11-23 17:08:55 +01:00
|
|
|
|
}.${config._module.args.name} or {
|
|
|
|
|
default = "${ip6.config.addr}/128";
|
|
|
|
|
});
|
2016-04-08 03:53:34 +02:00
|
|
|
|
};
|
2022-11-23 17:08:55 +01:00
|
|
|
|
}));
|
2016-04-08 03:53:34 +02:00
|
|
|
|
default = null;
|
|
|
|
|
};
|
2015-09-27 15:24:41 +02:00
|
|
|
|
ssh = mkOption {
|
|
|
|
|
type = submodule {
|
|
|
|
|
options = {
|
|
|
|
|
port = mkOption {
|
2016-04-17 04:13:32 +02:00
|
|
|
|
type = int;
|
|
|
|
|
default = 22;
|
2015-09-27 15:24:41 +02:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
default = {};
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
|
|
|
|
tinc = mkOption {
|
2016-02-06 15:11:30 +01:00
|
|
|
|
type = let net = config; in nullOr (submodule ({ config, ... }: {
|
2015-07-24 12:23:52 +02:00
|
|
|
|
options = {
|
|
|
|
|
config = mkOption {
|
|
|
|
|
type = str;
|
2016-02-06 15:11:30 +01:00
|
|
|
|
default = concatStringsSep "\n" (
|
|
|
|
|
(optionals (net.via != null)
|
2016-07-28 10:55:34 +02:00
|
|
|
|
(map (a: "Address = ${a} ${toString config.port}") net.via.addrs))
|
2016-02-06 15:11:30 +01:00
|
|
|
|
++
|
|
|
|
|
(map (a: "Subnet = ${a}") net.addrs)
|
|
|
|
|
++
|
2017-11-28 19:40:03 +01:00
|
|
|
|
(map (a: "Subnet = ${a}") config.subnets)
|
|
|
|
|
++
|
2016-07-28 13:02:41 +02:00
|
|
|
|
[config.extraConfig]
|
|
|
|
|
++
|
2016-02-06 15:11:30 +01:00
|
|
|
|
[config.pubkey]
|
2021-11-23 15:28:06 +01:00
|
|
|
|
++
|
2021-12-28 16:37:54 +01:00
|
|
|
|
optional (config.pubkey_ed25519 != null) ''
|
|
|
|
|
Ed25519PublicKey = ${config.pubkey_ed25519}
|
|
|
|
|
''
|
|
|
|
|
++
|
2021-11-23 15:28:06 +01:00
|
|
|
|
optional (config.weight != null) "Weight = ${toString config.weight}"
|
2016-02-06 15:11:30 +01:00
|
|
|
|
);
|
2021-11-08 04:58:14 +01:00
|
|
|
|
defaultText = ''
|
|
|
|
|
Address = ‹addr› ‹port› # for each ‹net.via.addrs›
|
|
|
|
|
Subnet = ‹addr› # for each ‹net.addrs›
|
|
|
|
|
‹extraConfig›
|
|
|
|
|
‹pubkey›
|
|
|
|
|
'';
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
|
|
|
|
pubkey = mkOption {
|
2016-03-16 02:04:22 +01:00
|
|
|
|
type = tinc-pubkey;
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
2020-09-05 01:17:51 +02:00
|
|
|
|
pubkey_ed25519 = mkOption {
|
|
|
|
|
type = nullOr tinc-pubkey;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
2016-07-28 13:02:41 +02:00
|
|
|
|
extraConfig = mkOption {
|
|
|
|
|
description = "Extra Configuration to be appended to the hosts file";
|
|
|
|
|
default = "";
|
2022-01-29 20:50:32 +01:00
|
|
|
|
type = lines;
|
2016-07-28 13:02:41 +02:00
|
|
|
|
};
|
2016-07-28 10:55:34 +02:00
|
|
|
|
port = mkOption {
|
|
|
|
|
type = int;
|
|
|
|
|
description = "tinc port to use to connect to host";
|
|
|
|
|
default = 655;
|
|
|
|
|
};
|
2017-11-28 19:40:03 +01:00
|
|
|
|
subnets = mkOption {
|
|
|
|
|
type = listOf cidr;
|
|
|
|
|
description = "tinc subnets";
|
|
|
|
|
default = [];
|
|
|
|
|
};
|
2021-11-23 15:28:06 +01:00
|
|
|
|
weight = mkOption {
|
|
|
|
|
type = nullOr int;
|
|
|
|
|
description = ''
|
|
|
|
|
global tinc weight (latency in ms) of this particular node.
|
|
|
|
|
can be set to some high value to make it unprobable to be used as router.
|
|
|
|
|
if set to null, tinc will autogenerate the value based on latency.
|
|
|
|
|
'';
|
|
|
|
|
default = if net.via != null then null else 300;
|
|
|
|
|
};
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
2015-07-27 02:45:03 +02:00
|
|
|
|
}));
|
|
|
|
|
default = null;
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
2018-12-09 16:50:58 +01:00
|
|
|
|
wireguard = mkOption {
|
|
|
|
|
type = nullOr (submodule ({ config, ... }: {
|
|
|
|
|
options = {
|
|
|
|
|
port = mkOption {
|
|
|
|
|
type = int;
|
|
|
|
|
description = "tinc port to use to connect to host";
|
|
|
|
|
default = 51820;
|
|
|
|
|
};
|
|
|
|
|
pubkey = mkOption {
|
|
|
|
|
type = wireguard-pubkey;
|
|
|
|
|
};
|
|
|
|
|
subnets = mkOption {
|
|
|
|
|
type = listOf cidr;
|
|
|
|
|
description = ''
|
|
|
|
|
wireguard subnets,
|
|
|
|
|
this defines how routing behaves for hosts that can't reach each other.
|
|
|
|
|
'';
|
|
|
|
|
default = [];
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
}));
|
2021-11-14 09:36:27 +01:00
|
|
|
|
default = null;
|
2018-12-09 16:50:58 +01:00
|
|
|
|
};
|
2015-07-24 12:23:52 +02:00
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
positive = mkOptionType {
|
|
|
|
|
name = "positive integer";
|
|
|
|
|
check = x: isInt x && x > 0;
|
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2016-06-07 22:36:40 +02:00
|
|
|
|
uint = mkOptionType {
|
|
|
|
|
name = "unsigned integer";
|
|
|
|
|
check = x: isInt x && x >= 0;
|
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-21 05:27:37 +01:00
|
|
|
|
secret-file = submodule ({ config, ... }: {
|
|
|
|
|
options = {
|
2016-07-03 19:44:41 +02:00
|
|
|
|
name = mkOption {
|
2020-08-04 22:22:43 +02:00
|
|
|
|
type = pathname;
|
2016-07-03 19:44:41 +02:00
|
|
|
|
default = config._module.args.name;
|
|
|
|
|
};
|
|
|
|
|
path = mkOption {
|
|
|
|
|
type = absolute-pathname;
|
|
|
|
|
default = "/run/keys/${config.name}";
|
2021-11-08 04:58:14 +01:00
|
|
|
|
defaultText = "/run/keys/‹name›";
|
2016-07-03 19:44:41 +02:00
|
|
|
|
};
|
|
|
|
|
mode = mkOption {
|
|
|
|
|
type = file-mode;
|
|
|
|
|
default = "0400";
|
|
|
|
|
};
|
2016-02-21 07:18:13 +01:00
|
|
|
|
owner = mkOption {
|
|
|
|
|
type = user;
|
|
|
|
|
};
|
|
|
|
|
group-name = mkOption {
|
|
|
|
|
type = str;
|
|
|
|
|
default = "root";
|
|
|
|
|
};
|
2020-08-04 20:28:04 +02:00
|
|
|
|
service = mkOption {
|
2020-08-04 22:22:43 +02:00
|
|
|
|
type = systemd.unit-name;
|
|
|
|
|
default = "secret-${lib.systemd.encodeName config.name}.service";
|
2021-11-08 04:58:14 +01:00
|
|
|
|
defaultText = "secret-‹name›.service";
|
2020-08-04 20:28:04 +02:00
|
|
|
|
};
|
2016-02-21 05:27:37 +01:00
|
|
|
|
source-path = mkOption {
|
|
|
|
|
type = str;
|
2016-07-03 19:44:41 +02:00
|
|
|
|
default = toString <secrets> + "/${config.name}";
|
2021-11-08 04:58:14 +01:00
|
|
|
|
defaultText = "‹secrets/‹name››";
|
2016-02-21 05:27:37 +01:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2016-07-16 21:43:38 +02:00
|
|
|
|
|
|
|
|
|
source = submodule ({ config, ... }: {
|
|
|
|
|
options = {
|
|
|
|
|
type = let
|
2018-02-28 14:30:11 +01:00
|
|
|
|
known-types = attrNames source-types;
|
|
|
|
|
type-candidates = filter (k: config.${k} != null) known-types;
|
2016-07-16 21:43:38 +02:00
|
|
|
|
in mkOption {
|
2018-02-28 14:30:11 +01:00
|
|
|
|
default = if length type-candidates == 1
|
|
|
|
|
then head type-candidates
|
|
|
|
|
else throw "cannot determine type";
|
|
|
|
|
type = enum known-types;
|
|
|
|
|
};
|
|
|
|
|
file = mkOption {
|
2016-07-16 21:43:38 +02:00
|
|
|
|
apply = x:
|
2018-02-28 14:30:11 +01:00
|
|
|
|
if absolute-pathname.check x
|
2016-07-16 21:43:38 +02:00
|
|
|
|
then { path = x; }
|
|
|
|
|
else x;
|
2018-02-28 14:30:11 +01:00
|
|
|
|
default = null;
|
|
|
|
|
type = nullOr (either absolute-pathname source-types.file);
|
2016-07-16 21:43:38 +02:00
|
|
|
|
};
|
|
|
|
|
git = mkOption {
|
|
|
|
|
default = null;
|
2018-02-28 14:30:11 +01:00
|
|
|
|
type = nullOr source-types.git;
|
2016-07-16 21:43:38 +02:00
|
|
|
|
};
|
2017-12-15 03:33:43 +01:00
|
|
|
|
pass = mkOption {
|
|
|
|
|
default = null;
|
2018-02-28 14:30:11 +01:00
|
|
|
|
type = nullOr source-types.pass;
|
2017-12-15 03:33:43 +01:00
|
|
|
|
};
|
2018-02-28 14:15:29 +01:00
|
|
|
|
pipe = mkOption {
|
|
|
|
|
apply = x:
|
|
|
|
|
if absolute-pathname.check x
|
|
|
|
|
then { command = x; }
|
|
|
|
|
else x;
|
|
|
|
|
default = null;
|
|
|
|
|
type = nullOr (either absolute-pathname source-types.pipe);
|
|
|
|
|
};
|
2018-02-28 14:30:11 +01:00
|
|
|
|
symlink = mkOption {
|
|
|
|
|
type = nullOr (either pathname source-types.symlink);
|
2016-07-16 21:43:38 +02:00
|
|
|
|
default = null;
|
|
|
|
|
apply = x:
|
2018-02-28 14:30:11 +01:00
|
|
|
|
if pathname.check x
|
2016-07-16 21:43:38 +02:00
|
|
|
|
then { target = x; }
|
|
|
|
|
else x;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2018-02-28 14:30:11 +01:00
|
|
|
|
source-types = {
|
|
|
|
|
file = submodule {
|
|
|
|
|
options = {
|
|
|
|
|
path = mkOption {
|
|
|
|
|
type = absolute-pathname;
|
|
|
|
|
};
|
2016-07-16 21:43:38 +02:00
|
|
|
|
};
|
|
|
|
|
};
|
2018-02-28 14:30:11 +01:00
|
|
|
|
git = submodule {
|
|
|
|
|
options = {
|
|
|
|
|
ref = mkOption {
|
|
|
|
|
type = str; # TODO types.git.ref
|
|
|
|
|
};
|
|
|
|
|
url = mkOption {
|
|
|
|
|
type = str; # TODO types.git.url
|
|
|
|
|
};
|
2016-07-16 21:43:38 +02:00
|
|
|
|
};
|
|
|
|
|
};
|
2018-02-28 14:30:11 +01:00
|
|
|
|
pass = submodule {
|
|
|
|
|
options = {
|
|
|
|
|
dir = mkOption {
|
|
|
|
|
type = absolute-pathname;
|
|
|
|
|
};
|
|
|
|
|
name = mkOption {
|
|
|
|
|
type = pathname; # TODO relative-pathname
|
|
|
|
|
};
|
2017-12-15 03:33:43 +01:00
|
|
|
|
};
|
|
|
|
|
};
|
2018-02-28 14:15:29 +01:00
|
|
|
|
pipe = submodule {
|
|
|
|
|
options = {
|
|
|
|
|
command = mkOption {
|
|
|
|
|
type = absolute-pathname;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2018-02-28 14:30:11 +01:00
|
|
|
|
symlink = submodule {
|
|
|
|
|
options = {
|
|
|
|
|
target = mkOption {
|
|
|
|
|
type = pathname; # TODO relative-pathname
|
|
|
|
|
};
|
2016-07-16 21:43:38 +02:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2018-02-28 14:30:11 +01:00
|
|
|
|
};
|
2016-07-16 21:43:38 +02:00
|
|
|
|
|
2015-10-09 14:07:29 +02:00
|
|
|
|
suffixed-str = suffs:
|
|
|
|
|
mkOptionType {
|
|
|
|
|
name = "string suffixed by ${concatStringsSep ", " suffs}";
|
|
|
|
|
check = x: isString x && any (flip hasSuffix x) suffs;
|
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-06 18:54:01 +01:00
|
|
|
|
user = submodule ({ config, ... }: {
|
2015-07-24 20:48:00 +02:00
|
|
|
|
options = {
|
2016-02-21 06:38:09 +01:00
|
|
|
|
home = mkOption {
|
|
|
|
|
type = absolute-pathname;
|
|
|
|
|
default = "/home/${config.name}";
|
2021-11-08 04:58:14 +01:00
|
|
|
|
defaultText = "/home/‹name›";
|
2016-02-21 06:38:09 +01:00
|
|
|
|
};
|
2015-07-25 01:05:14 +02:00
|
|
|
|
mail = mkOption {
|
2017-04-27 19:43:12 +02:00
|
|
|
|
type = nullOr str;
|
|
|
|
|
default = null;
|
2015-07-25 01:05:14 +02:00
|
|
|
|
};
|
2015-07-24 20:48:00 +02:00
|
|
|
|
name = mkOption {
|
2016-02-06 19:37:14 +01:00
|
|
|
|
type = username;
|
2016-02-06 18:54:01 +01:00
|
|
|
|
default = config._module.args.name;
|
2015-07-24 20:48:00 +02:00
|
|
|
|
};
|
2016-03-16 01:57:03 +01:00
|
|
|
|
pgp.pubkeys = mkOption {
|
|
|
|
|
type = attrsOf pgp-pubkey;
|
|
|
|
|
default = {};
|
|
|
|
|
description = ''
|
|
|
|
|
Set of user's PGP public keys.
|
|
|
|
|
|
2016-06-07 02:15:58 +02:00
|
|
|
|
Modules supporting PGP may use well-known key names to define
|
|
|
|
|
default values for options, in which case the well-known name
|
|
|
|
|
should be documented in the respective option's description.
|
2016-03-16 01:57:03 +01:00
|
|
|
|
'';
|
|
|
|
|
};
|
2015-07-24 20:48:00 +02:00
|
|
|
|
pubkey = mkOption {
|
2016-03-16 01:54:49 +01:00
|
|
|
|
type = nullOr ssh-pubkey;
|
2016-02-21 07:39:24 +01:00
|
|
|
|
default = null;
|
2015-07-24 20:48:00 +02:00
|
|
|
|
};
|
2016-02-21 06:56:57 +01:00
|
|
|
|
uid = mkOption {
|
|
|
|
|
type = int;
|
2018-12-02 14:14:03 +01:00
|
|
|
|
default = genid_uint31 config.name;
|
2021-11-08 04:58:14 +01:00
|
|
|
|
defaultText = "genid_uint31 ‹name›";
|
2016-02-21 06:56:57 +01:00
|
|
|
|
};
|
2015-07-24 20:48:00 +02:00
|
|
|
|
};
|
2016-02-06 18:54:01 +01:00
|
|
|
|
});
|
2016-04-27 01:33:39 +02:00
|
|
|
|
group = submodule ({ config, ... }: {
|
|
|
|
|
options = {
|
|
|
|
|
name = mkOption {
|
|
|
|
|
type = username;
|
|
|
|
|
default = config._module.args.name;
|
2021-11-08 04:58:14 +01:00
|
|
|
|
defaultText = "genid_uint31 ‹name›";
|
2016-04-27 01:33:39 +02:00
|
|
|
|
};
|
|
|
|
|
gid = mkOption {
|
|
|
|
|
type = int;
|
2018-12-02 14:14:03 +01:00
|
|
|
|
default = genid_uint31 config.name;
|
2021-11-08 04:58:14 +01:00
|
|
|
|
defaultText = "genid_uint31 ‹name›";
|
2016-04-27 01:33:39 +02:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
});
|
2015-07-24 20:48:00 +02:00
|
|
|
|
|
2016-04-07 20:29:07 +02:00
|
|
|
|
addr = either addr4 addr6;
|
|
|
|
|
addr4 = mkOptionType {
|
|
|
|
|
name = "IPv4 address";
|
|
|
|
|
check = let
|
|
|
|
|
IPv4address = let d = "([1-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"; in
|
|
|
|
|
concatMapStringsSep "." (const d) (range 1 4);
|
2017-06-18 15:36:18 +02:00
|
|
|
|
in
|
|
|
|
|
test IPv4address;
|
2016-04-07 20:29:07 +02:00
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
2016-04-08 04:41:30 +02:00
|
|
|
|
addr6 = mkOptionType {
|
|
|
|
|
name = "IPv6 address";
|
|
|
|
|
check = let
|
|
|
|
|
# TODO check IPv6 address harder
|
|
|
|
|
IPv6address = "[0-9a-f.:]+";
|
2017-06-18 15:36:18 +02:00
|
|
|
|
in
|
|
|
|
|
test IPv6address;
|
2016-04-08 04:41:30 +02:00
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
2016-03-16 01:57:03 +01:00
|
|
|
|
|
2017-10-11 18:12:31 +02:00
|
|
|
|
cidr = either cidr4 cidr6;
|
|
|
|
|
cidr4 = mkOptionType {
|
|
|
|
|
name = "CIDRv4 address";
|
|
|
|
|
check = let
|
|
|
|
|
CIDRv4address = let d = "([1-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"; in
|
|
|
|
|
concatMapStringsSep "." (const d) (range 1 4) + "(/([1-2]?[0-9]|3[0-2]))?";
|
|
|
|
|
in
|
|
|
|
|
test CIDRv4address;
|
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
cidr6 = mkOptionType {
|
|
|
|
|
name = "CIDRv6 address";
|
|
|
|
|
check = let
|
|
|
|
|
# TODO check IPv6 address harder
|
|
|
|
|
CIDRv6address = "[0-9a-f.:]+(/([0-9][0-9]?|1[0-2][0-8]))?";
|
|
|
|
|
in
|
|
|
|
|
test CIDRv6address;
|
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2016-10-20 20:21:59 +02:00
|
|
|
|
binary-cache-pubkey = str;
|
|
|
|
|
|
2016-03-16 01:57:03 +01:00
|
|
|
|
pgp-pubkey = str;
|
|
|
|
|
|
2017-08-01 11:27:03 +02:00
|
|
|
|
sitemap.entry = submodule ({ config, ... }: {
|
|
|
|
|
options = {
|
|
|
|
|
desc = mkOption {
|
|
|
|
|
default = null;
|
|
|
|
|
type = nullOr str;
|
|
|
|
|
};
|
|
|
|
|
href = mkOption {
|
|
|
|
|
${if testString "https?://.*" config._module.args.name
|
|
|
|
|
then "default" else null} = config._module.args.name;
|
|
|
|
|
type = nullOr str; # TODO nullOr uri?
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2016-03-16 01:54:49 +01:00
|
|
|
|
ssh-pubkey = str;
|
|
|
|
|
ssh-privkey = submodule {
|
|
|
|
|
options = {
|
|
|
|
|
bits = mkOption {
|
|
|
|
|
type = nullOr (enum ["4096"]);
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
path = mkOption {
|
|
|
|
|
type = either path str;
|
|
|
|
|
apply = x: {
|
|
|
|
|
path = toString x;
|
|
|
|
|
string = x;
|
|
|
|
|
}.${typeOf x};
|
|
|
|
|
};
|
|
|
|
|
type = mkOption {
|
|
|
|
|
type = enum ["rsa" "ed25519"];
|
|
|
|
|
default = "ed25519";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2015-12-28 19:43:31 +01:00
|
|
|
|
|
2016-03-16 02:04:22 +01:00
|
|
|
|
tinc-pubkey = str;
|
|
|
|
|
|
2016-10-20 20:21:59 +02:00
|
|
|
|
krebs.file-location = submodule {
|
2015-12-28 19:43:31 +01:00
|
|
|
|
options = {
|
|
|
|
|
# TODO user
|
|
|
|
|
host = mkOption {
|
|
|
|
|
type = host;
|
|
|
|
|
};
|
|
|
|
|
# TODO merge with ssl.privkey.path
|
|
|
|
|
path = mkOption {
|
2016-10-20 20:21:59 +02:00
|
|
|
|
type = either path str;
|
2015-12-28 19:43:31 +01:00
|
|
|
|
apply = x: {
|
|
|
|
|
path = toString x;
|
|
|
|
|
string = x;
|
|
|
|
|
}.${typeOf x};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2016-02-06 19:37:14 +01:00
|
|
|
|
|
2016-06-13 01:37:51 +02:00
|
|
|
|
file-mode = mkOptionType {
|
|
|
|
|
name = "file mode";
|
2017-06-18 15:36:18 +02:00
|
|
|
|
check = test "[0-7]{4}";
|
2016-06-13 01:37:51 +02:00
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2016-06-04 19:06:50 +02:00
|
|
|
|
haskell.conid = mkOptionType {
|
|
|
|
|
name = "Haskell constructor identifier";
|
2017-06-18 15:36:18 +02:00
|
|
|
|
check = test "[[:upper:]][[:lower:]_[:upper:]0-9']*";
|
2016-06-04 19:06:50 +02:00
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
haskell.modid = mkOptionType {
|
|
|
|
|
name = "Haskell module identifier";
|
|
|
|
|
check = x: isString x && all haskell.conid.check (splitString "." x);
|
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2020-08-05 10:57:09 +02:00
|
|
|
|
systemd.unit-name = mkOptionType {
|
|
|
|
|
name = "systemd unit name";
|
|
|
|
|
check = x:
|
|
|
|
|
test "^[0-9A-Za-z:_.\\-]+@?\\.(service|socket|device|mount|automount|swap|target|path|timer|slice|scope)$" x &&
|
|
|
|
|
stringLength x <= 256;
|
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-07 05:08:32 +01:00
|
|
|
|
# RFC952, B. Lexical grammar, <hname>
|
|
|
|
|
hostname = mkOptionType {
|
|
|
|
|
name = "hostname";
|
2016-06-13 01:40:57 +02:00
|
|
|
|
check = x: isString x && all label.check (splitString "." x);
|
2016-02-07 05:08:32 +01:00
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
# RFC952, B. Lexical grammar, <name>
|
|
|
|
|
# RFC1123, 2.1 Host Names and Numbers
|
|
|
|
|
label = mkOptionType {
|
|
|
|
|
name = "label";
|
|
|
|
|
# TODO case-insensitive labels
|
2017-06-18 16:17:55 +02:00
|
|
|
|
check = test "[0-9A-Za-z]([0-9A-Za-z-]*[0-9A-Za-z])?";
|
2016-02-07 05:08:32 +01:00
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-17 20:19:39 +02:00
|
|
|
|
# POSIX.1‐2017, 3.190 Group Name
|
|
|
|
|
groupname = mkOptionType {
|
|
|
|
|
name = "POSIX group name";
|
|
|
|
|
check = filename.check;
|
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-17 20:19:12 +02:00
|
|
|
|
# POSIX.1‐2017, 3.281 Portable Filename
|
2016-02-06 19:37:14 +01:00
|
|
|
|
filename = mkOptionType {
|
2019-04-17 20:19:12 +02:00
|
|
|
|
name = "POSIX portable filename";
|
2019-02-16 19:18:04 +01:00
|
|
|
|
check = test "[0-9A-Za-z._][0-9A-Za-z._-]*";
|
2016-02-06 19:37:14 +01:00
|
|
|
|
merge = mergeOneOption;
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-17 20:19:12 +02:00
|
|
|
|
# POSIX.1‐2017, 3.2 Absolute Pathname
|
2016-02-21 06:38:09 +01:00
|
|
|
|
absolute-pathname = mkOptionType {
|
|
|
|
|
name = "POSIX absolute pathname";
|
2017-03-31 15:08:16 +02:00
|
|
|
|
check = x: isString x && substring 0 1 x == "/" && pathname.check x;
|
2016-06-11 16:36:42 +02:00
|
|
|
|
merge = mergeOneOption;
|
2016-02-21 06:38:09 +01:00
|
|
|
|
};
|
|
|
|
|
|
2019-04-17 20:19:12 +02:00
|
|
|
|
# POSIX.1-2017, 3.271 Pathname
|
2016-02-21 06:38:09 +01:00
|
|
|
|
pathname = mkOptionType {
|
|
|
|
|
name = "POSIX pathname";
|
2017-03-31 15:08:16 +02:00
|
|
|
|
check = x:
|
|
|
|
|
let
|
|
|
|
|
# The filter is used to normalize paths, i.e. to remove duplicated and
|
|
|
|
|
# trailing slashes. It also removes leading slashes, thus we have to
|
|
|
|
|
# check for "/" explicitly below.
|
|
|
|
|
xs = filter (s: stringLength s > 0) (splitString "/" x);
|
|
|
|
|
in
|
|
|
|
|
isString x && (x == "/" || (length xs > 0 && all filename.check xs));
|
2016-06-11 16:36:42 +02:00
|
|
|
|
merge = mergeOneOption;
|
2016-02-21 06:38:09 +01:00
|
|
|
|
};
|
|
|
|
|
|
2019-04-17 20:19:12 +02:00
|
|
|
|
# POSIX.1-2017, 3.216 Login Name
|
2016-02-06 19:37:14 +01:00
|
|
|
|
username = mkOptionType {
|
2019-04-17 20:19:12 +02:00
|
|
|
|
name = "POSIX login name";
|
2016-06-11 16:29:18 +02:00
|
|
|
|
check = filename.check;
|
2016-06-11 16:36:42 +02:00
|
|
|
|
merge = mergeOneOption;
|
2016-02-06 19:37:14 +01:00
|
|
|
|
};
|
2018-12-09 16:50:58 +01:00
|
|
|
|
|
|
|
|
|
wireguard-pubkey = str;
|
2015-07-24 12:23:52 +02:00
|
|
|
|
}
|