1# NixOS module for Buildbot Worker.
2{
3 config,
4 lib,
5 options,
6 pkgs,
7 ...
8}:
9let
10 cfg = config.services.buildbot-worker;
11 opt = options.services.buildbot-worker;
12
13 package = pkgs.python3.pkgs.toPythonModule cfg.package;
14 python = package.pythonModule;
15
16 tacFile = pkgs.writeText "aur-buildbot-worker.tac" ''
17 import os
18 from io import open
19
20 from buildbot_worker.bot import Worker
21 from twisted.application import service
22
23 basedir = '${cfg.buildbotDir}'
24
25 # note: this line is matched against to check that this is a worker
26 # directory; do not edit it.
27 application = service.Application('buildbot-worker')
28
29 master_url_split = '${cfg.masterUrl}'.split(':')
30 buildmaster_host = master_url_split[0]
31 port = int(master_url_split[1])
32 workername = '${cfg.workerUser}'
33
34 with open('${cfg.workerPassFile}', 'r', encoding='utf-8') as passwd_file:
35 passwd = passwd_file.read().strip('\r\n')
36 keepalive = ${toString cfg.keepalive}
37 umask = None
38 maxdelay = 300
39 numcpus = None
40 allow_shutdown = None
41
42 s = Worker(buildmaster_host, port, workername, passwd, basedir,
43 keepalive, umask=umask, maxdelay=maxdelay,
44 numcpus=numcpus, allow_shutdown=allow_shutdown)
45 s.setServiceParent(application)
46 '';
47
48in
49{
50 options = {
51 services.buildbot-worker = {
52
53 enable = lib.mkOption {
54 type = lib.types.bool;
55 default = false;
56 description = "Whether to enable the Buildbot Worker.";
57 };
58
59 user = lib.mkOption {
60 default = "bbworker";
61 type = lib.types.str;
62 description = "User the buildbot Worker should execute under.";
63 };
64
65 group = lib.mkOption {
66 default = "bbworker";
67 type = lib.types.str;
68 description = "Primary group of buildbot Worker user.";
69 };
70
71 extraGroups = lib.mkOption {
72 type = lib.types.listOf lib.types.str;
73 default = [ ];
74 description = "List of extra groups that the Buildbot Worker user should be a part of.";
75 };
76
77 home = lib.mkOption {
78 default = "/home/bbworker";
79 type = lib.types.path;
80 description = "Buildbot home directory.";
81 };
82
83 buildbotDir = lib.mkOption {
84 default = "${cfg.home}/worker";
85 defaultText = lib.literalExpression ''"''${config.${opt.home}}/worker"'';
86 type = lib.types.path;
87 description = "Specifies the Buildbot directory.";
88 };
89
90 workerUser = lib.mkOption {
91 default = "example-worker";
92 type = lib.types.str;
93 description = "Specifies the Buildbot Worker user.";
94 };
95
96 workerPass = lib.mkOption {
97 default = "pass";
98 type = lib.types.str;
99 description = "Specifies the Buildbot Worker password.";
100 };
101
102 workerPassFile = lib.mkOption {
103 type = lib.types.path;
104 description = "File used to store the Buildbot Worker password";
105 };
106
107 hostMessage = lib.mkOption {
108 default = null;
109 type = lib.types.nullOr lib.types.str;
110 description = "Description of this worker";
111 };
112
113 adminMessage = lib.mkOption {
114 default = null;
115 type = lib.types.nullOr lib.types.str;
116 description = "Name of the administrator of this worker";
117 };
118
119 masterUrl = lib.mkOption {
120 default = "localhost:9989";
121 type = lib.types.str;
122 description = "Specifies the Buildbot Worker connection string.";
123 };
124
125 keepalive = lib.mkOption {
126 default = 600;
127 type = lib.types.int;
128 description = ''
129 This is a number that indicates how frequently keepalive messages should be sent
130 from the worker to the buildmaster, expressed in seconds.
131 '';
132 };
133
134 package = lib.mkPackageOption pkgs "buildbot-worker" { };
135
136 packages = lib.mkOption {
137 default = with pkgs; [ git ];
138 defaultText = lib.literalExpression "[ pkgs.git ]";
139 type = lib.types.listOf lib.types.package;
140 description = "Packages to add to PATH for the buildbot process.";
141 };
142 };
143 };
144
145 config = lib.mkIf cfg.enable {
146 services.buildbot-worker.workerPassFile = lib.mkDefault (
147 pkgs.writeText "buildbot-worker-password" cfg.workerPass
148 );
149
150 users.groups = lib.optionalAttrs (cfg.group == "bbworker") {
151 bbworker = { };
152 };
153
154 users.users = lib.optionalAttrs (cfg.user == "bbworker") {
155 bbworker = {
156 description = "Buildbot Worker User.";
157 isNormalUser = true;
158 createHome = true;
159 home = cfg.home;
160 group = cfg.group;
161 extraGroups = cfg.extraGroups;
162 useDefaultShell = true;
163 };
164 };
165
166 systemd.services.buildbot-worker = {
167 description = "Buildbot Worker.";
168 after = [
169 "network.target"
170 "buildbot-master.service"
171 ];
172 wantedBy = [ "multi-user.target" ];
173 path = cfg.packages;
174 environment.PYTHONPATH = "${python.withPackages (p: [ package ])}/${python.sitePackages}";
175
176 preStart = ''
177 mkdir -vp "${cfg.buildbotDir}/info"
178 ${lib.optionalString (cfg.hostMessage != null) ''
179 ln -sf "${pkgs.writeText "buildbot-worker-host" cfg.hostMessage}" "${cfg.buildbotDir}/info/host"
180 ''}
181 ${lib.optionalString (cfg.adminMessage != null) ''
182 ln -sf "${pkgs.writeText "buildbot-worker-admin" cfg.adminMessage}" "${cfg.buildbotDir}/info/admin"
183 ''}
184 '';
185
186 serviceConfig = {
187 Type = "simple";
188 User = cfg.user;
189 Group = cfg.group;
190 WorkingDirectory = cfg.home;
191
192 # NOTE: call twistd directly with stdout logging for systemd
193 ExecStart = "${python.pkgs.twisted}/bin/twistd --nodaemon --pidfile= --logfile - --python ${tacFile}";
194 };
195
196 };
197 };
198
199 meta.maintainers = lib.teams.buildbot.members;
200
201}