]> git.immae.eu Git - perso/Immae/Config/Nix.git/blame - modules/private/buildbot/default.nix
Switch to colemna
[perso/Immae/Config/Nix.git] / modules / private / buildbot / default.nix
CommitLineData
ab8f306d 1{ lib, pkgs, config, ... }:
9fb4205e
IB
2let
3 varDir = "/var/lib/buildbot";
bc0f9fcf
IB
4 bb-python = buildbot.pythonModule;
5 buildbot = pkgs.immae-buildbot;
9fb4205e
IB
6in
7{
8 options = {
8d213e2b 9 myServices.buildbot.enable = lib.mkOption {
9fb4205e
IB
10 type = lib.types.bool;
11 default = false;
12 description = ''
13 Whether to enable buildbot.
14 '';
15 };
16 };
17
8d213e2b 18 config = lib.mkIf config.myServices.buildbot.enable {
120bcf4d
IB
19 myServices.chatonsProperties.hostings.buildbot = {
20 file.datetime = "2022-08-21T10:37:00";
21 hosting = {
22 name = "Buildbot";
23 description = "Python-based continuous integration testing framework";
24 type = "INSTANCE";
25 website = "https://git.immae.eu";
26 logo = "https://www.buildbot.net/img/icon.png";
27 status.level = "OK";
28 status.description = "OK";
29 registration.load = "OPEN";
30 install.type = "PACKAGE";
31 guide.user = "https://www.immae.eu/docs/forge-logicielle.html";
32 };
33 software = {
34 name = "Buildbot";
35 website = "https://www.buildbot.net/";
36 license.url = "https://github.com/buildbot/buildbot/blob/master/LICENSE";
37 license.name = "GNU General Public License v2.0";
38 version = pkgs.buildbot.version;
39 source.url = "https://github.com/buildbot/buildbot";
40 };
41 };
f6e48e3a
IB
42 nixpkgs.overlays = [
43 (self: super: {
44 follow-systemd-unit = self.writeScriptBin "follow-systemd-unit" ''
45 #!${self.stdenv.shell}
46
47 set -euo pipefail
48
49 service=$1
50 before_invocation_id=$2
51
52 get_id() {
53 systemctl show -p InvocationID --value "$service"
54 }
55
56 while [ "$(get_id)" = "$before_invocation_id" ]; do sleep 1; done
57
58 invocation_id="$(get_id)"
59 cursor="$(mktemp)"
60 trap "rm -f $cursor" EXIT
61
62 get_logs() {
63 journalctl --quiet --cursor-file=$cursor INVOCATION_ID=$invocation_id + _SYSTEMD_INVOCATION_ID=$invocation_id
64 }
65
66 while [ -n "$(systemctl show -p Job --value "$service")" ]; do
67 get_logs
68 done
69 get_logs
70 '';
71 })
72 ];
ab8f306d
IB
73 ids.uids.buildbot = config.myEnv.buildbot.user.uid;
74 ids.gids.buildbot = config.myEnv.buildbot.user.gid;
9fb4205e
IB
75
76 users.groups.buildbot.gid = config.ids.gids.buildbot;
77 users.users.buildbot = {
78 name = "buildbot";
79 uid = config.ids.uids.buildbot;
80 group = "buildbot";
81 description = "Buildbot user";
82 home = varDir;
f6e48e3a
IB
83 extraGroups = [ "keys" "systemd-journal" ];
84 useDefaultShell = true;
85 openssh.authorizedKeys.keys = [ config.myEnv.buildbot.ssh_key.public ];
9fb4205e
IB
86 };
87
29f8cb85 88 services.websites.env.tools.watchPaths = lib.attrsets.mapAttrsToList
da30ae4f 89 (k: project: config.secrets.fullPaths."buildbot/${project.name}/webhook-httpd-include")
ab8f306d 90 config.myEnv.buildbot.projects;
17f6eae9 91
29f8cb85 92 services.websites.env.tools.vhostConfs.git.extraConfig = lib.attrsets.mapAttrsToList (k: project: ''
9fb4205e
IB
93 RedirectMatch permanent "^/buildbot/${project.name}$" "/buildbot/${project.name}/"
94 RewriteEngine On
95 RewriteRule ^/buildbot/${project.name}/ws(.*)$ unix:///run/buildbot/${project.name}.sock|ws://git.immae.eu/ws$1 [P,NE,QSA,L]
96 ProxyPass /buildbot/${project.name}/ unix:///run/buildbot/${project.name}.sock|http://${project.name}-git.immae.eu/
97 ProxyPassReverse /buildbot/${project.name}/ unix:///run/buildbot/${project.name}.sock|http://${project.name}-git.immae.eu/
98 <Location /buildbot/${project.name}/>
99 Use LDAPConnect
e2b96bf5 100 Require ldap-group cn=users,ou=${project.name},cn=buildbot,ou=services,dc=immae,dc=eu
9fb4205e
IB
101
102 SetEnvIf X-Url-Scheme https HTTPS=1
103 ProxyPreserveHost On
104 </Location>
105 <Location /buildbot/${project.name}/change_hook/base>
85817848
IB
106 <RequireAny>
107 Require local
108 Require ldap-group cn=users,ou=${project.name},cn=buildbot,ou=services,dc=immae,dc=eu
da30ae4f 109 Include ${config.secrets.fullPaths."buildbot/${project.name}/webhook-httpd-include"}
85817848 110 </RequireAny>
9fb4205e 111 </Location>
ab8f306d 112 '') config.myEnv.buildbot.projects;
9fb4205e
IB
113
114 system.activationScripts = lib.attrsets.mapAttrs' (k: project: lib.attrsets.nameValuePair "buildbot-${project.name}" {
115 deps = [ "users" "wrappers" ];
8fa7ff2c
IB
116 text = ''
117 install -m 755 -o buildbot -g buildbot -d ${varDir}/${project.name}
118
119 ${project.activationScript}
120 '';
ab8f306d 121 }) config.myEnv.buildbot.projects;
6984f454 122
4c4652aa 123 secrets.keys = lib.listToAttrs (
6984f454
IB
124 lib.lists.flatten (
125 lib.attrsets.mapAttrsToList (k: project:
126 lib.attrsets.mapAttrsToList (k: v:
4c4652aa 127 (lib.nameValuePair "buildbot/${project.name}/${k}" {
6984f454
IB
128 permissions = "0600";
129 user = "buildbot";
130 group = "buildbot";
f6e48e3a 131 text = if builtins.isFunction v then v pkgs config else v;
4c4652aa 132 })
6984f454
IB
133 ) project.secrets
134 ++ [
4c4652aa 135 (lib.nameValuePair "buildbot/${project.name}/webhook-httpd-include" {
6984f454
IB
136 permissions = "0600";
137 user = "wwwrun";
138 group = "wwwrun";
ab8f306d 139 text = lib.optionalString (project.webhookTokens != null) ''
6984f454
IB
140 Require expr "req('Access-Key') in { ${builtins.concatStringsSep ", " (map (x: "'${x}'") project.webhookTokens)} }"
141 '';
4c4652aa
IB
142 })
143 (lib.nameValuePair "buildbot/${project.name}/environment_file" {
dcb8ad4c
IB
144 permissions = "0600";
145 user = "buildbot";
146 group = "buildbot";
dcb8ad4c
IB
147 text = let
148 project_env = with lib.attrsets;
2ff9258e 149 mapAttrs' (k: v: nameValuePair "BUILDBOT_${k}" (if builtins.isFunction v then v pkgs else v)) project.environment //
200690c9
IB
150 {
151 BUILDBOT_PROJECT_DIR = ./projects + "/${project.name}";
152 BUILDBOT_WORKER_PORT = builtins.toString project.workerPort;
153 BUILDBOT_HOST = config.hostEnv.fqdn;
154 BUILDBOT_VIRT_URL = "qemu+ssh://libvirt@dilion.immae.eu/system";
155 };
dcb8ad4c
IB
156 in builtins.concatStringsSep "\n"
157 (lib.mapAttrsToList (envK: envV: "${envK}=${envV}") project_env);
4c4652aa 158 })
6984f454 159 ]
ab8f306d 160 ) config.myEnv.buildbot.projects
6984f454 161 )
4c4652aa
IB
162 ) // {
163 "buildbot/ldap" = {
6984f454
IB
164 permissions = "0600";
165 user = "buildbot";
166 group = "buildbot";
ab8f306d 167 text = config.myEnv.buildbot.ldap.password;
4c4652aa
IB
168 };
169 "buildbot/worker_password" = {
200690c9
IB
170 permissions = "0600";
171 user = "buildbot";
172 group = "buildbot";
173 text = config.myEnv.buildbot.workerPassword;
4c4652aa
IB
174 };
175 "buildbot/ssh_key" = {
6984f454
IB
176 permissions = "0600";
177 user = "buildbot";
178 group = "buildbot";
282c67a1 179 text = config.myEnv.buildbot.ssh_key.private;
4c4652aa 180 };
bd0cb07b
IB
181 "buildbot/ssh_known_hosts" = {
182 permissions = "0644";
183 user = "buildbot";
184 group = "buildbot";
185 text = ''
186 git.immae.eu ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIFbhFTl2A2RJn5L51yxJM4XfCS2ZaiSX/jo9jFSdghF
187 eldiron ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIFbhFTl2A2RJn5L51yxJM4XfCS2ZaiSX/jo9jFSdghF
188 phare.normalesup.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN2GomItXICXpCtCFRMT2xuerqx2nLMO/3mNUuWyzFr1
189 '';
190 };
4c4652aa 191 };
6984f454 192
17f6eae9
IB
193 services.filesWatcher = lib.attrsets.mapAttrs' (k: project: lib.attrsets.nameValuePair "buildbot-${project.name}" {
194 restart = true;
195 paths = [
da30ae4f
IB
196 config.secrets.fullPaths."buildbot/ldap"
197 config.secrets.fullPaths."buildbot/worker_password"
198 config.secrets.fullPaths."buildbot/ssh_key"
199 config.secrets.fullPaths."buildbot/${project.name}/environment_file"
200 ] ++ lib.attrsets.mapAttrsToList (k: v: config.secrets.fullPaths."buildbot/${project.name}/${k}") project.secrets;
ab8f306d 201 }) config.myEnv.buildbot.projects;
17f6eae9 202
850adcf4
IB
203 systemd.slices.buildbot = {
204 description = "buildbot slice";
205 };
206
200690c9 207 networking.firewall.allowedTCPPorts = lib.attrsets.mapAttrsToList (k: v: v.workerPort) config.myEnv.buildbot.projects;
6984f454
IB
208 systemd.services = lib.attrsets.mapAttrs' (k: project: lib.attrsets.nameValuePair "buildbot-${project.name}" {
209 description = "Buildbot Continuous Integration Server ${project.name}.";
ca330baa 210 after = [ "network-online.target" ];
6984f454 211 wantedBy = [ "multi-user.target" ];
bc0f9fcf 212 path = project.packages pkgs;
6984f454 213 preStart = let
bc0f9fcf 214 master-cfg = "${buildbot.buildbot_common}/${bb-python.pythonForBuild.sitePackages}/buildbot_common/master.cfg";
e2b96bf5
IB
215 tac_file = pkgs.writeText "buildbot.tac" ''
216 import os
217
218 from twisted.application import service
219 from buildbot.master import BuildMaster
220
221 basedir = '${varDir}/${project.name}'
222 rotateLength = 10000000
223 maxRotatedFiles = 10
224 configfile = '${master-cfg}'
225
226 # Default umask for server
227 umask = None
228
229 # if this is a relocatable tac file, get the directory containing the TAC
230 if basedir == '.':
231 import os
232 basedir = os.path.abspath(os.path.dirname(__file__))
233
234 # note: this line is matched against to check that this is a buildmaster
235 # directory; do not edit it.
236 application = service.Application('buildmaster')
237 from twisted.python.logfile import LogFile
238 from twisted.python.log import ILogObserver, FileLogObserver
239 logfile = LogFile.fromFullPath(os.path.join(basedir, "twistd.log"), rotateLength=rotateLength,
240 maxRotatedFiles=maxRotatedFiles)
241 application.setComponent(ILogObserver, FileLogObserver(logfile).emit)
242
243 m = BuildMaster(basedir, configfile, umask)
244 m.setServiceParent(application)
245 m.log_rotation.rotateLength = rotateLength
246 m.log_rotation.maxRotatedFiles = maxRotatedFiles
247 '';
9fb4205e 248 in ''
9fb4205e 249 if [ ! -f ${varDir}/${project.name}/buildbot.tac ]; then
6984f454 250 ${buildbot}/bin/buildbot create-master -c "${master-cfg}" "${varDir}/${project.name}"
9fb4205e 251 rm -f ${varDir}/${project.name}/master.cfg.sample
e2b96bf5 252 rm -f ${varDir}/${project.name}/buildbot.tac
9fb4205e 253 fi
e2b96bf5 254 ln -sf ${tac_file} ${varDir}/${project.name}/buildbot.tac
ca330baa 255 # different buildbots may be trying that simultaneously, add the || true to avoid complaining in case of race
da30ae4f 256 install -Dm600 -o buildbot -g buildbot -T ${config.secrets.fullPaths."buildbot/ssh_key"} ${varDir}/buildbot_key || true
bd0cb07b 257 install -Dm600 -o buildbot -g buildbot -T ${config.secrets.fullPaths."buildbot/ssh_known_hosts"} ${varDir}/buildbot_hosts || true
9fb4205e 258 buildbot_secrets=${varDir}/${project.name}/secrets
6984f454 259 install -m 0700 -o buildbot -g buildbot -d $buildbot_secrets
da30ae4f
IB
260 install -Dm600 -o buildbot -g buildbot -T ${config.secrets.fullPaths."buildbot/ldap"} $buildbot_secrets/ldap
261 install -Dm600 -o buildbot -g buildbot -T ${config.secrets.fullPaths."buildbot/worker_password"} $buildbot_secrets/worker_password
9fb4205e 262 ${builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList
da30ae4f 263 (k: v: "install -Dm600 -o buildbot -g buildbot -T ${config.secrets.fullPaths."buildbot/${project.name}/${k}"} $buildbot_secrets/${k}") project.secrets
9fb4205e 264 )}
5400b9b6 265 ${buildbot}/bin/buildbot upgrade-master ${varDir}/${project.name}
9fb4205e 266 '';
9fb4205e 267 environment = let
9fb4205e 268 HOME = "${varDir}/${project.name}";
bc0f9fcf
IB
269 PYTHONPATH = "${bb-python.withPackages (self:
270 buildbot.common_packages self ++
271 [ (buildbot.buildbot_config project) ]
272 )}/${bb-python.sitePackages}${if project.pythonPathHome then ":${varDir}/${project.name}/.local/${bb-python.sitePackages}" else ""}";
dcb8ad4c 273 in { inherit PYTHONPATH HOME; };
9fb4205e
IB
274
275 serviceConfig = {
850adcf4 276 Slice = "buildbot.slice";
9fb4205e
IB
277 Type = "forking";
278 User = "buildbot";
279 Group = "buildbot";
81b9ff89
IB
280 RuntimeDirectory = "buildbot";
281 RuntimeDirectoryPreserve = "yes";
282 StateDirectory = "buildbot";
6984f454 283 SupplementaryGroups = "keys";
9fb4205e
IB
284 WorkingDirectory = "${varDir}/${project.name}";
285 ExecStart = "${buildbot}/bin/buildbot start";
da30ae4f 286 EnvironmentFile = config.secrets.fullPaths."buildbot/${project.name}/environment_file";
9fb4205e 287 };
ab8f306d 288 }) config.myEnv.buildbot.projects;
9fb4205e
IB
289 };
290}