stockholm/krebs/4lib/types.nix
2016-04-07 20:29:07 +02:00

289 lines
6.9 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 = {
via = mkOption {
type = nullOr net;
default = null;
};
addrs = mkOption {
type = listOf addr;
default = config.addrs4 ++ config.addrs6;
# TODO only default addrs make sense
};
addrs4 = mkOption {
type = listOf addr4;
default = [];
};
addrs6 = mkOption {
type = listOf addr6;
default = [];
};
aliases = mkOption {
# TODO nonEmptyListOf hostname
type = listOf hostname;
default = [];
};
ssh = mkOption {
type = submodule {
options = {
port = mkOption {
type = nullOr int;
default = null;
};
};
};
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;
};
};
});
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 != null;
merge = mergeOneOption;
};
addr6 = str; # TODO
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 != "-";
};
}