vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / continuous-integration / buildbot / master.nix
blob300e4e72a01ed8e61c4c747f1531071399acdb3e
1 # NixOS module for Buildbot continuous integration server.
2 { config, lib, options, pkgs, ... }:
3 let
4   cfg = config.services.buildbot-master;
5   opt = options.services.buildbot-master;
7   package = pkgs.python3.pkgs.toPythonModule cfg.package;
8   python = package.pythonModule;
10   escapeStr = lib.escape [ "'" ];
12   defaultMasterCfg = pkgs.writeText "master.cfg" ''
13     from buildbot.plugins import *
14     ${cfg.extraImports}
15     factory = util.BuildFactory()
16     c = BuildmasterConfig = dict(
17      workers       = [${lib.concatStringsSep "," cfg.workers}],
18      protocols     = { 'pb': {'port': ${toString cfg.pbPort} } },
19      title         = '${escapeStr cfg.title}',
20      titleURL      = '${escapeStr cfg.titleUrl}',
21      buildbotURL   = '${escapeStr cfg.buildbotUrl}',
22      db            = dict(db_url='${escapeStr cfg.dbUrl}'),
23      www           = dict(port=${toString cfg.port}),
24      change_source = [ ${lib.concatStringsSep "," cfg.changeSource} ],
25      schedulers    = [ ${lib.concatStringsSep "," cfg.schedulers} ],
26      builders      = [ ${lib.concatStringsSep "," cfg.builders} ],
27      services      = [ ${lib.concatStringsSep "," cfg.reporters} ],
28      configurators = [ ${lib.concatStringsSep "," cfg.configurators} ],
29     )
30     for step in [ ${lib.concatStringsSep "," cfg.factorySteps} ]:
31       factory.addStep(step)
33     ${cfg.extraConfig}
34   '';
36   tacFile = pkgs.writeText "buildbot-master.tac" ''
37     import os
39     from twisted.application import service
40     from buildbot.master import BuildMaster
42     basedir = '${cfg.buildbotDir}'
44     configfile = '${cfg.masterCfg}'
46     # Default umask for server
47     umask = None
49     # note: this line is matched against to check that this is a buildmaster
50     # directory; do not edit it.
51     application = service.Application('buildmaster')
53     m = BuildMaster(basedir, configfile, umask)
54     m.setServiceParent(application)
55   '';
57 in {
58   options = {
59     services.buildbot-master = {
61       factorySteps = lib.mkOption {
62         type = lib.types.listOf lib.types.str;
63         description = "Factory Steps";
64         default = [];
65         example = [
66           "steps.Git(repourl='https://github.com/buildbot/pyflakes.git', mode='incremental')"
67           "steps.ShellCommand(command=['trial', 'pyflakes'])"
68         ];
69       };
71       changeSource = lib.mkOption {
72         type = lib.types.listOf lib.types.str;
73         description = "List of Change Sources.";
74         default = [];
75         example = [
76           "changes.GitPoller('https://github.com/buildbot/pyflakes.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)"
77         ];
78       };
80       configurators = lib.mkOption {
81         type = lib.types.listOf lib.types.str;
82         description = "Configurator Steps, see https://docs.buildbot.net/latest/manual/configuration/configurators.html";
83         default = [];
84         example = [
85           "util.JanitorConfigurator(logHorizon=timedelta(weeks=4), hour=12, dayOfWeek=6)"
86         ];
87       };
89       enable = lib.mkOption {
90         type = lib.types.bool;
91         default = false;
92         description = "Whether to enable the Buildbot continuous integration server.";
93       };
95       extraConfig = lib.mkOption {
96         type = lib.types.str;
97         description = "Extra configuration to append to master.cfg";
98         default = "c['buildbotNetUsageData'] = None";
99       };
101       extraImports = lib.mkOption {
102         type = lib.types.str;
103         description = "Extra python imports to prepend to master.cfg";
104         default = "";
105         example = "from buildbot.process.project import Project";
106       };
108       masterCfg = lib.mkOption {
109         type = lib.types.path;
110         description = "Optionally pass master.cfg path. Other options in this configuration will be ignored.";
111         default = defaultMasterCfg;
112         defaultText = lib.literalMD ''generated configuration file'';
113         example = "/etc/nixos/buildbot/master.cfg";
114       };
116       schedulers = lib.mkOption {
117         type = lib.types.listOf lib.types.str;
118         description = "List of Schedulers.";
119         default = [
120           "schedulers.SingleBranchScheduler(name='all', change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=['runtests'])"
121           "schedulers.ForceScheduler(name='force',builderNames=['runtests'])"
122         ];
123       };
125       builders = lib.mkOption {
126         type = lib.types.listOf lib.types.str;
127         description = "List of Builders.";
128         default = [
129           "util.BuilderConfig(name='runtests',workernames=['example-worker'],factory=factory)"
130         ];
131       };
133       workers = lib.mkOption {
134         type = lib.types.listOf lib.types.str;
135         description = "List of Workers.";
136         default = [ "worker.Worker('example-worker', 'pass')" ];
137       };
139       reporters = lib.mkOption {
140         default = [];
141         type = lib.types.listOf lib.types.str;
142         description = "List of reporter objects used to present build status to various users.";
143       };
145       user = lib.mkOption {
146         default = "buildbot";
147         type = lib.types.str;
148         description = "User the buildbot server should execute under.";
149       };
151       group = lib.mkOption {
152         default = "buildbot";
153         type = lib.types.str;
154         description = "Primary group of buildbot user.";
155       };
157       extraGroups = lib.mkOption {
158         type = lib.types.listOf lib.types.str;
159         default = [];
160         description = "List of extra groups that the buildbot user should be a part of.";
161       };
163       home = lib.mkOption {
164         default = "/home/buildbot";
165         type = lib.types.path;
166         description = "Buildbot home directory.";
167       };
169       buildbotDir = lib.mkOption {
170         default = "${cfg.home}/master";
171         defaultText = lib.literalExpression ''"''${config.${opt.home}}/master"'';
172         type = lib.types.path;
173         description = "Specifies the Buildbot directory.";
174       };
176       pbPort = lib.mkOption {
177         default = 9989;
178         type = lib.types.either lib.types.str lib.types.int;
179         example = "'tcp:9990:interface=127.0.0.1'";
180         description = ''
181           The buildmaster will listen on a TCP port of your choosing
182           for connections from workers.
183           It can also use this port for connections from remote Change Sources,
184           status clients, and debug tools.
185           This port should be visible to the outside world, and you’ll need to tell
186           your worker admins about your choice.
187           If put in (single) quotes, this can also be used as a connection string,
188           as defined in the [ConnectionStrings guide](https://twistedmatrix.com/documents/current/core/howto/endpoints.html).
189         '';
190       };
192       listenAddress = lib.mkOption {
193         default = "0.0.0.0";
194         type = lib.types.str;
195         description = "Specifies the bind address on which the buildbot HTTP interface listens.";
196       };
198       buildbotUrl = lib.mkOption {
199         default = "http://localhost:8010/";
200         type = lib.types.str;
201         description = "Specifies the Buildbot URL.";
202       };
204       title = lib.mkOption {
205         default = "Buildbot";
206         type = lib.types.str;
207         description = "Specifies the Buildbot Title.";
208       };
210       titleUrl = lib.mkOption {
211         default = "Buildbot";
212         type = lib.types.str;
213         description = "Specifies the Buildbot TitleURL.";
214       };
216       dbUrl = lib.mkOption {
217         default = "sqlite:///state.sqlite";
218         type = lib.types.str;
219         description = "Specifies the database connection string.";
220       };
222       port = lib.mkOption {
223         default = 8010;
224         type = lib.types.port;
225         description = "Specifies port number on which the buildbot HTTP interface listens.";
226       };
228       package = lib.mkPackageOption pkgs "buildbot-full" {
229         example = "buildbot";
230       };
232       packages = lib.mkOption {
233         default = [ pkgs.git ];
234         defaultText = lib.literalExpression "[ pkgs.git ]";
235         type = lib.types.listOf lib.types.package;
236         description = "Packages to add to PATH for the buildbot process.";
237       };
239       pythonPackages = lib.mkOption {
240         type = lib.types.functionTo (lib.types.listOf lib.types.package);
241         default = pythonPackages: with pythonPackages; [ ];
242         defaultText = lib.literalExpression "pythonPackages: with pythonPackages; [ ]";
243         description = "Packages to add the to the PYTHONPATH of the buildbot process.";
244         example = lib.literalExpression "pythonPackages: with pythonPackages; [ requests ]";
245       };
246     };
247   };
249   config = lib.mkIf cfg.enable {
250     users.groups = lib.optionalAttrs (cfg.group == "buildbot") {
251       buildbot = { };
252     };
254     users.users = lib.optionalAttrs (cfg.user == "buildbot") {
255       buildbot = {
256         description = "Buildbot User.";
257         isNormalUser = true;
258         createHome = true;
259         inherit (cfg) home group extraGroups;
260         useDefaultShell = true;
261       };
262     };
264     systemd.services.buildbot-master = {
265       description = "Buildbot Continuous Integration Server.";
266       after = [ "network.target" ];
267       wantedBy = [ "multi-user.target" ];
268       path = cfg.packages ++ cfg.pythonPackages python.pkgs;
269       environment.PYTHONPATH = "${python.withPackages (self: cfg.pythonPackages self ++ [ package ])}/${python.sitePackages}";
271       preStart = ''
272         mkdir -vp "${cfg.buildbotDir}"
273         # Link the tac file so buildbot command line tools recognize the directory
274         ln -sf "${tacFile}" "${cfg.buildbotDir}/buildbot.tac"
275         ${cfg.package}/bin/buildbot create-master --db "${cfg.dbUrl}" "${cfg.buildbotDir}"
276         rm -f buildbot.tac.new master.cfg.sample
277       '';
279       serviceConfig = {
280         Type = "simple";
281         User = cfg.user;
282         Group = cfg.group;
283         WorkingDirectory = cfg.home;
284         # NOTE: call twistd directly with stdout logging for systemd
285         ExecStart = "${python.pkgs.twisted}/bin/twistd -o --nodaemon --pidfile= --logfile - --python ${cfg.buildbotDir}/buildbot.tac";
286         # To reload on upgrade, set the following in your configuration:
287         # systemd.services.buildbot-master.reloadIfChanged = true;
288         ExecReload = [
289           "${pkgs.coreutils}/bin/ln -sf ${tacFile} ${cfg.buildbotDir}/buildbot.tac"
290           "${pkgs.coreutils}/bin/kill -HUP $MAINPID"
291         ];
292       };
293     };
294   };
296   imports = [
297     (lib.mkRenamedOptionModule [ "services" "buildbot-master" "bpPort" ] [ "services" "buildbot-master" "pbPort" ])
298     (lib.mkRemovedOptionModule [ "services" "buildbot-master" "status" ] ''
299       Since Buildbot 0.9.0, status targets are deprecated and ignored.
300       Review your configuration and migrate to reporters (available at services.buildbot-master.reporters).
301     '')
302   ];
304   meta.maintainers = lib.teams.buildbot.members;