stockholm/krebs/4lib/types.nix
2016-04-27 01:45:47 +02:00

336 lines
8.2 KiB
Nix
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ config, lib, ... }:
with builtins;
with lib;
with types;
let
# Inherited attributes are used in submodules that have their own `config`.
inherit (config.krebs) build users;
in
types // rec {
host = submodule ({ config, ... }: {
options = {
name = mkOption {
type = label;
default = config._module.args.name;
};
cores = mkOption {
type = positive;
};
nets = mkOption {
type = attrsOf net;
default = {};
};
owner = mkOption {
type = user;
default = users.krebs;
};
extraZones = mkOption {
default = {};
# TODO: string is either MX, NS, A or AAAA
type = with types; attrsOf string;
};
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
'';
};
ssh.pubkey = mkOption {
type = nullOr ssh-pubkey;
default = null;
apply = x:
optionalTrace (x == null && config.owner.name == build.user.name)
"The option `krebs.hosts.${config.name}.ssh.pubkey' is unused."
x;
};
ssh.privkey = mkOption {
type = nullOr ssh-privkey;
default = null;
};
};
});
net = submodule ({ config, ... }: {
options = {
name = mkOption {
type = label;
default = config._module.args.name;
};
via = mkOption {
type = nullOr net;
default = null;
};
addrs = mkOption {
type = listOf addr;
default =
optional (config.ip4 != null) config.ip4.addr ++
optional (config.ip6 != null) config.ip6.addr;
readOnly = true;
};
aliases = mkOption {
# TODO nonEmptyListOf hostname
type = listOf hostname;
default = [];
};
ip4 = mkOption {
type = nullOr (submodule {
options = {
addr = mkOption {
type = addr4;
};
prefix = mkOption ({
type = str; # TODO routing prefix (CIDR)
} // optionalAttrs (config.name == "retiolum") {
default = "10.243.0.0/16";
});
};
});
default = null;
};
ip6 = mkOption {
type = nullOr (submodule {
options = {
addr = mkOption {
type = addr6;
};
prefix = mkOption ({
type = str; # TODO routing prefix (CIDR)
} // optionalAttrs (config.name == "retiolum") {
default = "42::/16";
});
};
});
default = null;
};
ssh = mkOption {
type = submodule {
options = {
port = mkOption {
type = int;
default = 22;
};
};
};
default = {};
};
tinc = mkOption {
type = let net = config; in nullOr (submodule ({ config, ... }: {
options = {
config = mkOption {
type = str;
default = concatStringsSep "\n" (
(optionals (net.via != null)
(map (a: "Address = ${a}") net.via.addrs))
++
(map (a: "Subnet = ${a}") net.addrs)
++
[config.pubkey]
);
};
pubkey = mkOption {
type = tinc-pubkey;
};
};
}));
default = null;
};
};
});
positive = mkOptionType {
name = "positive integer";
check = x: isInt x && x > 0;
merge = mergeOneOption;
};
secret-file = submodule ({ config, ... }: {
options = {
path = mkOption { type = str; };
mode = mkOption { type = str; default = "0400"; };
owner = mkOption {
type = user;
default = config.krebs.users.root;
};
group-name = mkOption {
type = str;
default = "root";
};
source-path = mkOption {
type = str;
default = toString <secrets> + "/${config._module.args.name}";
};
};
});
suffixed-str = suffs:
mkOptionType {
name = "string suffixed by ${concatStringsSep ", " suffs}";
check = x: isString x && any (flip hasSuffix x) suffs;
merge = mergeOneOption;
};
user = submodule ({ config, ... }: {
options = {
home = mkOption {
type = absolute-pathname;
default = "/home/${config.name}";
};
mail = mkOption {
type = str; # TODO retiolum mail address
};
name = mkOption {
type = username;
default = config._module.args.name;
};
pgp.pubkeys = mkOption {
type = attrsOf pgp-pubkey;
default = {};
description = ''
Set of user's PGP public keys.
Modules supporting PGP may use well-known key names to define option
defaults, e.g. using `getAttrDef well-known-name pubkeys`.
'';
};
pubkey = mkOption {
type = nullOr ssh-pubkey;
default = null;
};
uid = mkOption {
type = int;
default = genid config.name;
};
};
});
group = submodule ({ config, ... }: {
options = {
name = mkOption {
type = username;
default = config._module.args.name;
};
gid = mkOption {
type = int;
default = genid config.name;
};
};
});
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);
in x: match IPv4address x != null;
merge = mergeOneOption;
};
addr6 = mkOptionType {
name = "IPv6 address";
check = let
# TODO check IPv6 address harder
IPv6address = "[0-9a-f.:]+";
in x: match IPv6address x != null;
merge = mergeOneOption;
};
pgp-pubkey = str;
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";
};
};
};
tinc-pubkey = str;
krebs.file-location = types.submodule {
options = {
# TODO user
host = mkOption {
type = host;
};
# TODO merge with ssl.privkey.path
path = mkOption {
type = types.either types.path types.str;
apply = x: {
path = toString x;
string = x;
}.${typeOf x};
};
};
};
# RFC952, B. Lexical grammar, <hname>
hostname = mkOptionType {
name = "hostname";
check = x: all label.check (splitString "." x);
merge = mergeOneOption;
};
# RFC952, B. Lexical grammar, <name>
# RFC1123, 2.1 Host Names and Numbers
label = mkOptionType {
name = "label";
# TODO case-insensitive labels
check = x: match "[0-9A-Za-z]([0-9A-Za-z-]*[0-9A-Za-z])?" x != null;
merge = mergeOneOption;
};
# POSIX.12013, 3.278 Portable Filename Character Set
filename = mkOptionType {
name = "POSIX filename";
check = let
filename-chars = stringToCharacters
"-.0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
in s: all (flip elem filename-chars) (stringToCharacters s);
merge = mergeOneOption;
};
# POSIX.12013, 3.2 Absolute Pathname
# TODO normalize slashes
# TODO two slashes
absolute-pathname = mkOptionType {
name = "POSIX absolute pathname";
check = s: pathname.check s && substring 0 1 s == "/";
};
# POSIX.12013, 3.267 Pathname
# TODO normalize slashes
pathname = mkOptionType {
name = "POSIX pathname";
check = s: isString s && all filename.check (splitString "/" s);
};
# POSIX.1-2013, 3.431 User Name
username = mkOptionType {
name = "POSIX username";
check = s: filename.check s && substring 0 1 s != "-";
};
}