-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathmodule.nix
183 lines (166 loc) · 6.01 KB
/
module.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.queued-build-hook;
queued-build-hook = pkgs.callPackage ./. { };
in
{
options.queued-build-hook = {
enable = mkEnableOption "queued-build-hook";
package = mkOption {
type = types.package;
default = queued-build-hook;
description = mdDoc ''
The queued-build-hook package to use.
'';
};
socketDirectory = mkOption {
description = mdDoc ''
Path to store the queued-build-hook daemon's unix socket.
'';
default = "/var/lib/nix";
type = types.path;
};
socketUser = mkOption {
type = types.str;
example = "user";
default = "root";
description = mdDoc ''
This users will have read/write access to the Unix socket.
'';
};
socketGroup = mkOption {
description = mdDoc ''
The users in this group will have read/write access to the Unix socket.
'';
type = types.str;
default = "nixbld";
};
retryInterval = mkOption {
description = mdDoc ''
The number of seconds between attempts to run the hook for a package after an initial failure.
'';
type = types.int;
default = 1;
};
retries = mkOption {
description = mdDoc ''
The maximum number of attempts that will be made to run the hook for a package before giving up and dropping the task altogether.
'';
type = types.int;
default = 5;
};
concurrency = mkOption {
description = mdDoc ''
Sets the maximum number of tasks that can be executed simultaneously.
By default it is set to 0 which means there is no limit to the number of tasks that can be run concurrently.
'';
type = types.int;
default = 0;
};
enqueueScriptContent = mkOption {
description = mdDoc ''
The script's content responsible for enqueuing newly-built packages and passing them to the daemon.
Although the default configuration should suffice, there may be situations that require customized handling of specific packages.
For example, it may be necessary to process certain packages synchronously using the 'queued-build-hook wait' command, or to ignore certain packages entirely.
'';
default = ''
${cfg.package}/bin/queued-build-hook queue --socket "${cfg.socketDirectory}/async-nix-post-build-hook.sock"
'';
type = types.str;
};
postBuildScript = mkOption {
description = mdDoc ''
Specify the path to your postBuildScript
'';
type = types.nullOr types.path;
default = null;
};
postBuildScriptContent = mkOption {
description = mdDoc ''
Specify the content of the script that will manage the newly built package.
The script must be able to handle the OUT_PATHS environment variable, which contains a list of the paths to the newly built packages.
'';
example = literalExpression ''
exec nix copy --experimental-features nix-command --to "file:///var/nix-cache" $OUT_PATHS
'';
type = types.nullOr types.str;
default = null;
};
credentials = mkOption {
description = mdDoc ''
Credentials to load by startup. Keys that are UPPER_SNAKE will be loaded as env vars. Values are absolute paths to the credentials.
'';
type = types.attrsOf types.str;
default = { };
example = {
AWS_SHARED_CREDENTIALS_FILE = "/run/keys/aws-credentials";
binary-cache-key = "/run/keys/binary-cache-key";
};
};
};
config = mkIf cfg.enable {
assertions =
[{
assertion = cfg.postBuildScript != null || cfg.postBuildScriptContent != null;
message = "Either postBuildScript or postBuildScriptContent must be set";
}];
nix.settings.post-build-hook =
let
enqueueScript = pkgs.writeShellScriptBin "enqueue-package" cfg.enqueueScriptContent;
in
"${enqueueScript}/bin/enqueue-package";
systemd.sockets = {
async-nix-post-build-hook = {
description = "Async nix post build hooks socket";
wantedBy = [ "sockets.target" ];
socketConfig = {
ListenStream = "${cfg.socketDirectory}/async-nix-post-build-hook.sock";
SocketMode = "0660";
SocketUser = cfg.socketUser;
SocketGroup = cfg.socketGroup;
Service = "async-nix-post-build-hook.service";
};
};
};
systemd.services =
let
hook = if (cfg.postBuildScript != null) then cfg.postBuildScript else (pkgs.writeShellScript "hook" cfg.postBuildScriptContent);
in
{
async-nix-post-build-hook = {
description = "Run nix post build hooks asynchronously";
wantedBy = [ "multi-user.target" ];
requires = [
"async-nix-post-build-hook.socket"
];
script = ''
set -euo pipefail
shopt -u nullglob
# Load all credentials into env if they are in UPPER_SNAKE form.
if [[ -n "''${CREDENTIALS_DIRECTORY:-}" ]]; then
for file in "$CREDENTIALS_DIRECTORY"/*; do
key=$(basename "$file")
if [[ $key =~ ^[A-Z0-9_]+$ ]]; then
echo "Environ $key"
export "$key=$(< "$file")"
fi
done
fi
exec ${cfg.package}/bin/queued-build-hook daemon --hook ${hook} --retry-interval ${toString cfg.retryInterval} --retries ${toString cfg.retries} --concurrency ${toString cfg.concurrency}
'';
environment.HOME = "/var/lib/async-nix-post-build-hook";
serviceConfig = {
DynamicUser = true;
User = "queued-build-hook";
Group = "queued-build-hook";
LoadCredential = mapAttrsToList (key: value: "${key}:${value}") cfg.credentials;
KillMode = "process";
Restart = "on-failure";
FileDescriptorStoreMax = 1;
StateDirectory = "async-nix-post-build-hook";
};
};
};
};
}