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