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