-
Notifications
You must be signed in to change notification settings - Fork 60
/
modules.nix
109 lines (99 loc) · 3.75 KB
/
modules.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
with builtins; {
assertionModule = { config, lib, ... }: {
assertions = lib.mapAttrsToList (key: opts: let
nonNulls = l: filter (x: x != null) l;
in {
assertion = length (nonNulls [opts.text opts.keyCommand opts.keyFile]) == 1;
message =
let prefix = "${name}.deployment.keys.${key}";
in "Exactly one of `${prefix}.text`, `${prefix}.keyCommand` and `${prefix}.keyFile` must be set.";
}) config.deployment.keys;
};
# Change the ownership of all keys uploaded pre-activation
#
# This is built as part of the system profile.
# We must be careful not to access `text` / `keyCommand` / `keyFile` here
keyChownModule = { lib, config, ... }: let
preActivationKeys = lib.filterAttrs (name: key: key.uploadAt == "pre-activation") config.deployment.keys;
scriptDeps = if config.system.activationScripts ? groups then [ "groups" ] else [ "users" ];
commands = lib.mapAttrsToList (name: key: let
keyPath = "${key.destDir}/${name}";
in ''
if [ -f "${keyPath}" ]; then
if ! chown ${key.user}:${key.group} "${keyPath}"; then
# Error should be visible in stderr
failed=1
fi
else
>&2 echo "Key ${keyPath} does not exist. Skipping chown."
fi
'') preActivationKeys;
script = lib.stringAfter scriptDeps ''
# This script is injected by Colmena to change the ownerships
# of keys (`deployment.keys`) deployed before system activation.
>&2 echo "setting up key ownerships..."
# We set the ownership of as many keys as possible before failing
failed=
${concatStringsSep "\n" commands}
if [ -n "$failed" ]; then
>&2 echo "Failed to set the ownership of some keys."
# The activation script has a trap to handle failed
# commands and print out various debug information.
# Let's trigger that instead of `exit 1`.
false
fi
'';
in {
system.activationScripts.colmena-chown-keys = lib.mkIf (length commands != 0) script;
};
# Create "${name}-key" services for NixOps compatibility
#
# This is built as part of the system profile.
# We must be careful not to access `text` / `keyCommand` / `keyFile` here
#
# Sadly, path units don't automatically deactivate the bound units when
# the key files are deleted, so we use inotifywait in the services' scripts.
#
# <https://github.com/systemd/systemd/issues/3642>
keyServiceModule = { pkgs, lib, config, ... }: {
systemd.paths = lib.mapAttrs' (name: val: {
name = "${name}-key";
value = {
wantedBy = [ "paths.target" ];
pathConfig = {
PathExists = val.path;
};
};
}) config.deployment.keys;
systemd.services = lib.mapAttrs' (name: val: {
name = "${name}-key";
value = {
enable = true;
serviceConfig = {
TimeoutStartSec = "infinity";
Restart = "always";
RestartSec = "100ms";
};
path = [ pkgs.inotify-tools ];
preStart = ''
(while read f; do if [ "$f" = "${val.name}" ]; then break; fi; done \
< <(inotifywait -qm --format '%f' -e create,move ${val.destDir}) ) &
if [[ -e "${val.path}" ]]; then
echo 'flapped down'
kill %1
exit 0
fi
wait %1
'';
script = ''
inotifywait -qq -e delete_self "${val.path}" &
if [[ ! -e "${val.path}" ]]; then
echo 'flapped up'
exit 0
fi
wait %1
'';
};
}) config.deployment.keys;
};
}