268 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			268 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
# 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.pythonPackages.buildbot-full;
 | 
						|
        defaultText = "pkgs.pythonPackages.buildbot-full";
 | 
						|
        description = "Package to use for buildbot.";
 | 
						|
        example = literalExample "pkgs.python3Packages.buildbot-full";
 | 
						|
      };
 | 
						|
 | 
						|
      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 ];
 | 
						|
}
 |