diff options
Diffstat (limited to 'nixpkgs/nixos/modules/services/continuous-integration/buildbot')
-rw-r--r-- | nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix | 267 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/services/continuous-integration/buildbot/worker.nix | 186 |
2 files changed, 453 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix new file mode 100644 index 000000000000..9c615fbe885f --- /dev/null +++ b/nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix @@ -0,0 +1,267 @@ +# NixOS module for Buildbot continous integration server. + +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.buildbot-master; + + python = cfg.package.pythonModule; + + escapeStr = s: escape ["'"] s; + + defaultMasterCfg = pkgs.writeText "master.cfg" '' + from buildbot.plugins import * + factory = util.BuildFactory() + c = BuildmasterConfig = dict( + workers = [${concatStringsSep "," cfg.workers}], + protocols = { 'pb': {'port': ${toString cfg.bpPort} } }, + title = '${escapeStr cfg.title}', + titleURL = '${escapeStr cfg.titleUrl}', + buildbotURL = '${escapeStr cfg.buildbotUrl}', + db = dict(db_url='${escapeStr cfg.dbUrl}'), + www = dict(port=${toString cfg.port}), + change_source = [ ${concatStringsSep "," cfg.changeSource} ], + schedulers = [ ${concatStringsSep "," cfg.schedulers} ], + builders = [ ${concatStringsSep "," cfg.builders} ], + status = [ ${concatStringsSep "," cfg.status} ], + ) + for step in [ ${concatStringsSep "," cfg.factorySteps} ]: + factory.addStep(step) + + ${cfg.extraConfig} + ''; + + tacFile = pkgs.writeText "buildbot-master.tac" '' + import os + + from twisted.application import service + from buildbot.master import BuildMaster + + basedir = '${cfg.buildbotDir}' + + configfile = '${cfg.masterCfg}' + + # Default umask for server + umask = None + + # note: this line is matched against to check that this is a buildmaster + # directory; do not edit it. + application = service.Application('buildmaster') + + m = BuildMaster(basedir, configfile, umask) + m.setServiceParent(application) + ''; + +in { + options = { + services.buildbot-master = { + + factorySteps = mkOption { + type = types.listOf types.str; + description = "Factory Steps"; + default = []; + example = [ + "steps.Git(repourl='git://github.com/buildbot/pyflakes.git', mode='incremental')" + "steps.ShellCommand(command=['trial', 'pyflakes'])" + ]; + }; + + changeSource = mkOption { + type = types.listOf types.str; + description = "List of Change Sources."; + default = []; + example = [ + "changes.GitPoller('git://github.com/buildbot/pyflakes.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)" + ]; + }; + + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the Buildbot continuous integration server."; + }; + + extraConfig = mkOption { + type = types.str; + description = "Extra configuration to append to master.cfg"; + default = "c['buildbotNetUsageData'] = None"; + }; + + masterCfg = mkOption { + type = types.path; + description = "Optionally pass master.cfg path. Other options in this configuration will be ignored."; + default = defaultMasterCfg; + example = "/etc/nixos/buildbot/master.cfg"; + }; + + schedulers = mkOption { + type = types.listOf types.str; + description = "List of Schedulers."; + default = [ + "schedulers.SingleBranchScheduler(name='all', change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=['runtests'])" + "schedulers.ForceScheduler(name='force',builderNames=['runtests'])" + ]; + }; + + builders = mkOption { + type = types.listOf types.str; + description = "List of Builders."; + default = [ + "util.BuilderConfig(name='runtests',workernames=['example-worker'],factory=factory)" + ]; + }; + + workers = mkOption { + type = types.listOf types.str; + description = "List of Workers."; + default = [ "worker.Worker('example-worker', 'pass')" ]; + }; + + status = mkOption { + default = []; + type = types.listOf types.str; + description = "List of status notification endpoints."; + }; + + user = mkOption { + default = "buildbot"; + type = types.str; + description = "User the buildbot server should execute under."; + }; + + group = mkOption { + default = "buildbot"; + type = types.str; + description = "Primary group of buildbot user."; + }; + + extraGroups = mkOption { + type = types.listOf types.str; + default = []; + description = "List of extra groups that the buildbot user should be a part of."; + }; + + home = mkOption { + default = "/home/buildbot"; + type = types.path; + description = "Buildbot home directory."; + }; + + buildbotDir = mkOption { + default = "${cfg.home}/master"; + type = types.path; + description = "Specifies the Buildbot directory."; + }; + + bpPort = mkOption { + default = 9989; + type = types.int; + description = "Port where the master will listen to Buildbot Worker."; + }; + + listenAddress = mkOption { + default = "0.0.0.0"; + type = types.str; + description = "Specifies the bind address on which the buildbot HTTP interface listens."; + }; + + buildbotUrl = mkOption { + default = "http://localhost:8010/"; + type = types.str; + description = "Specifies the Buildbot URL."; + }; + + title = mkOption { + default = "Buildbot"; + type = types.str; + description = "Specifies the Buildbot Title."; + }; + + titleUrl = mkOption { + default = "Buildbot"; + type = types.str; + description = "Specifies the Buildbot TitleURL."; + }; + + dbUrl = mkOption { + default = "sqlite:///state.sqlite"; + type = types.str; + description = "Specifies the database connection string."; + }; + + port = mkOption { + default = 8010; + type = types.int; + description = "Specifies port number on which the buildbot HTTP interface listens."; + }; + + package = mkOption { + type = types.package; + default = pkgs.python3Packages.buildbot-full; + defaultText = "pkgs.python3Packages.buildbot-full"; + description = "Package to use for buildbot."; + example = literalExample "pkgs.python3Packages.buildbot"; + }; + + packages = mkOption { + default = [ pkgs.git ]; + example = literalExample "[ pkgs.git ]"; + type = types.listOf types.package; + description = "Packages to add to PATH for the buildbot process."; + }; + + pythonPackages = mkOption { + default = pythonPackages: with pythonPackages; [ ]; + defaultText = "pythonPackages: with pythonPackages; [ ]"; + description = "Packages to add the to the PYTHONPATH of the buildbot process."; + example = literalExample "pythonPackages: with pythonPackages; [ requests ]"; + }; + }; + }; + + config = mkIf cfg.enable { + users.groups = optional (cfg.group == "buildbot") { + name = "buildbot"; + }; + + users.users = optional (cfg.user == "buildbot") { + name = "buildbot"; + description = "Buildbot User."; + isNormalUser = true; + createHome = true; + home = cfg.home; + group = cfg.group; + extraGroups = cfg.extraGroups; + useDefaultShell = true; + }; + + systemd.services.buildbot-master = { + description = "Buildbot Continuous Integration Server."; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + path = cfg.packages ++ cfg.pythonPackages python.pkgs; + environment.PYTHONPATH = "${python.withPackages (self: cfg.pythonPackages self ++ [ cfg.package ])}/${python.sitePackages}"; + + preStart = '' + mkdir -vp "${cfg.buildbotDir}" + # Link the tac file so buildbot command line tools recognize the directory + ln -sf "${tacFile}" "${cfg.buildbotDir}/buildbot.tac" + ${cfg.package}/bin/buildbot create-master --db "${cfg.dbUrl}" "${cfg.buildbotDir}" + rm -f buildbot.tac.new master.cfg.sample + ''; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + WorkingDirectory = cfg.home; + # NOTE: call twistd directly with stdout logging for systemd + ExecStart = "${python.pkgs.twisted}/bin/twistd -o --nodaemon --pidfile= --logfile - --python ${tacFile}"; + }; + }; + }; + + meta.maintainers = with lib.maintainers; [ nand0p mic92 ]; +} diff --git a/nixpkgs/nixos/modules/services/continuous-integration/buildbot/worker.nix b/nixpkgs/nixos/modules/services/continuous-integration/buildbot/worker.nix new file mode 100644 index 000000000000..49e04ca36228 --- /dev/null +++ b/nixpkgs/nixos/modules/services/continuous-integration/buildbot/worker.nix @@ -0,0 +1,186 @@ +# NixOS module for Buildbot Worker. + +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.buildbot-worker; + + python = cfg.package.pythonModule; + + tacFile = pkgs.writeText "aur-buildbot-worker.tac" '' + import os + from io import open + + from buildbot_worker.bot import Worker + from twisted.application import service + + basedir = '${cfg.buildbotDir}' + + # note: this line is matched against to check that this is a worker + # directory; do not edit it. + application = service.Application('buildbot-worker') + + master_url_split = '${cfg.masterUrl}'.split(':') + buildmaster_host = master_url_split[0] + port = int(master_url_split[1]) + workername = '${cfg.workerUser}' + + with open('${cfg.workerPassFile}', 'r', encoding='utf-8') as passwd_file: + passwd = passwd_file.read().strip('\r\n') + keepalive = 600 + umask = None + maxdelay = 300 + numcpus = None + allow_shutdown = None + + s = Worker(buildmaster_host, port, workername, passwd, basedir, + keepalive, umask=umask, maxdelay=maxdelay, + numcpus=numcpus, allow_shutdown=allow_shutdown) + s.setServiceParent(application) + ''; + +in { + options = { + services.buildbot-worker = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the Buildbot Worker."; + }; + + user = mkOption { + default = "bbworker"; + type = types.str; + description = "User the buildbot Worker should execute under."; + }; + + group = mkOption { + default = "bbworker"; + type = types.str; + description = "Primary group of buildbot Worker user."; + }; + + extraGroups = mkOption { + type = types.listOf types.str; + default = []; + description = "List of extra groups that the Buildbot Worker user should be a part of."; + }; + + home = mkOption { + default = "/home/bbworker"; + type = types.path; + description = "Buildbot home directory."; + }; + + buildbotDir = mkOption { + default = "${cfg.home}/worker"; + type = types.path; + description = "Specifies the Buildbot directory."; + }; + + workerUser = mkOption { + default = "example-worker"; + type = types.str; + description = "Specifies the Buildbot Worker user."; + }; + + workerPass = mkOption { + default = "pass"; + type = types.str; + description = "Specifies the Buildbot Worker password."; + }; + + workerPassFile = mkOption { + type = types.path; + description = "File used to store the Buildbot Worker password"; + }; + + hostMessage = mkOption { + default = null; + type = types.nullOr types.str; + description = "Description of this worker"; + }; + + adminMessage = mkOption { + default = null; + type = types.nullOr types.str; + description = "Name of the administrator of this worker"; + }; + + masterUrl = mkOption { + default = "localhost:9989"; + type = types.str; + description = "Specifies the Buildbot Worker connection string."; + }; + + package = mkOption { + type = types.package; + default = pkgs.python3Packages.buildbot-worker; + defaultText = "pkgs.python3Packages.buildbot-worker"; + description = "Package to use for buildbot worker."; + example = literalExample "pkgs.python2Packages.buildbot-worker"; + }; + + packages = mkOption { + default = with pkgs; [ git ]; + example = literalExample "[ pkgs.git ]"; + type = types.listOf types.package; + description = "Packages to add to PATH for the buildbot process."; + }; + }; + }; + + config = mkIf cfg.enable { + services.buildbot-worker.workerPassFile = mkDefault (pkgs.writeText "buildbot-worker-password" cfg.workerPass); + + users.groups = optional (cfg.group == "bbworker") { + name = "bbworker"; + }; + + users.users = optional (cfg.user == "bbworker") { + name = "bbworker"; + description = "Buildbot Worker User."; + isNormalUser = true; + createHome = true; + home = cfg.home; + group = cfg.group; + extraGroups = cfg.extraGroups; + useDefaultShell = true; + }; + + systemd.services.buildbot-worker = { + description = "Buildbot Worker."; + after = [ "network.target" "buildbot-master.service" ]; + wantedBy = [ "multi-user.target" ]; + path = cfg.packages; + environment.PYTHONPATH = "${python.withPackages (p: [ cfg.package ])}/${python.sitePackages}"; + + preStart = '' + mkdir -vp "${cfg.buildbotDir}/info" + ${optionalString (cfg.hostMessage != null) '' + ln -sf "${pkgs.writeText "buildbot-worker-host" cfg.hostMessage}" "${cfg.buildbotDir}/info/host" + ''} + ${optionalString (cfg.adminMessage != null) '' + ln -sf "${pkgs.writeText "buildbot-worker-admin" cfg.adminMessage}" "${cfg.buildbotDir}/info/admin" + ''} + ''; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + WorkingDirectory = cfg.home; + + # NOTE: call twistd directly with stdout logging for systemd + ExecStart = "${python.pkgs.twisted}/bin/twistd --nodaemon --pidfile= --logfile - --python ${tacFile}"; + }; + + }; + }; + + meta.maintainers = with lib.maintainers; [ nand0p ]; + +} |