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