raito
2a7b42ef6b
Previously, we needed to hardcode the URL for private SSH keys, this is cleaned up and we can iterate over each project for its configuration. Configuration is at deployment time. Signed-off-by: Raito Bezarius <raito@lix.systems>
249 lines
7.9 KiB
Nix
249 lines
7.9 KiB
Nix
{ config
|
|
, pkgs
|
|
, lib
|
|
, ...
|
|
}:
|
|
let
|
|
cfg = config.services.buildbot-nix.coordinator;
|
|
in
|
|
{
|
|
options = {
|
|
services.buildbot-nix.coordinator = {
|
|
enable = lib.mkEnableOption "buildbot-coordinator";
|
|
dbUrl = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "postgresql://@/buildbot";
|
|
description = "Postgresql database url";
|
|
};
|
|
workersFile = lib.mkOption {
|
|
type = lib.types.path;
|
|
description = "File containing a list of nix workers";
|
|
};
|
|
oauth2SecretFile = lib.mkOption {
|
|
type = lib.types.path;
|
|
description = "File containing an OAuth 2 client secret";
|
|
};
|
|
buildSystems = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ pkgs.hostPlatform.system ];
|
|
description = "Systems that we will be build";
|
|
};
|
|
evalMaxMemorySize = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "2048";
|
|
description = ''
|
|
Maximum memory size for nix-eval-jobs (in MiB) per
|
|
worker. After the limit is reached, the worker is
|
|
restarted.
|
|
'';
|
|
};
|
|
evalWorkerCount = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.int;
|
|
default = null;
|
|
description = ''
|
|
Number of nix-eval-jobs worker processes. If null, the number of cores is used.
|
|
If you experience memory issues (buildbot-workers going out-of-memory), you can reduce this number.
|
|
'';
|
|
};
|
|
domain = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Buildbot domain";
|
|
example = "buildbot.numtide.com";
|
|
};
|
|
|
|
signingKeyFile = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.path;
|
|
description = "A path to a Nix signing key";
|
|
default = null;
|
|
example = "/run/agenix.d/signing-key";
|
|
};
|
|
|
|
gerrit = {
|
|
domain = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Domain to the Gerrit server";
|
|
example = "gerrit.lix.systems";
|
|
};
|
|
|
|
username = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Username to log in to the Gerrit API";
|
|
example = "buildbot";
|
|
};
|
|
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
description = "Port to log in to the Gerrit API";
|
|
example = 2022;
|
|
};
|
|
|
|
privateKeyFile = lib.mkOption {
|
|
type = lib.types.path;
|
|
description = ''
|
|
Path to the SSH private key to authenticate against the Gerrit API
|
|
'';
|
|
example = "/var/lib/buildbot/master/id_gerrit";
|
|
};
|
|
|
|
projects = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
description = ''
|
|
List of projects which are to check on Gerrit.
|
|
'';
|
|
example = [ "lix" ];
|
|
};
|
|
};
|
|
|
|
binaryCache = {
|
|
enable = lib.mkEnableOption " binary cache upload to a S3 bucket";
|
|
profileCredentialsFile = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.path;
|
|
description = "A path to the various AWS profile credentials related to the S3 bucket containing a profile named `default`";
|
|
default = null;
|
|
example = "/run/agenix.d/aws-profile";
|
|
};
|
|
bucket = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
description = "Bucket where to store the data";
|
|
default = null;
|
|
example = "lix-cache";
|
|
};
|
|
endpoint = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
description = "Endpoint for the S3 server";
|
|
default = null;
|
|
example = "s3.lix.systems";
|
|
};
|
|
region = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
description = "Region for the S3 bucket";
|
|
default = null;
|
|
example = "garage";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
config = lib.mkIf cfg.enable {
|
|
# By default buildbot uses a normal user, which is not a good default, because
|
|
# we grant normal users potentially access to other resources. Also
|
|
# we don't to be able to ssh into buildbot.
|
|
|
|
users.users.buildbot = {
|
|
isNormalUser = lib.mkForce false;
|
|
isSystemUser = true;
|
|
};
|
|
|
|
services.buildbot-master = {
|
|
enable = true;
|
|
|
|
# disable example workers from nixpkgs
|
|
builders = [ ];
|
|
schedulers = [ ];
|
|
workers = [ ];
|
|
|
|
home = "/var/lib/buildbot";
|
|
extraImports = ''
|
|
from datetime import timedelta
|
|
from buildbot_nix import GerritNixConfigurator
|
|
'';
|
|
configurators = [
|
|
''
|
|
util.JanitorConfigurator(logHorizon=timedelta(weeks=4), hour=12, dayOfWeek=6)
|
|
''
|
|
''
|
|
GerritNixConfigurator(
|
|
"${cfg.gerrit.domain}",
|
|
"${cfg.gerrit.username}",
|
|
"${toString cfg.gerrit.port}",
|
|
"${cfg.gerrit.privateKeyFile}",
|
|
projects=${builtins.toJSON cfg.gerrit.projects},
|
|
url=${builtins.toJSON config.services.buildbot-master.buildbotUrl},
|
|
nix_eval_max_memory_size=${builtins.toJSON cfg.evalMaxMemorySize},
|
|
nix_eval_worker_count=${if cfg.evalWorkerCount == null then "None" else builtins.toString cfg.evalWorkerCount},
|
|
nix_supported_systems=${builtins.toJSON cfg.buildSystems},
|
|
# Signing key file must be available on the workers and readable.
|
|
signing_keyfile=${if cfg.signingKeyFile == null then "None" else builtins.toJSON cfg.signingKeyFile},
|
|
binary_cache_config=${if (!cfg.binaryCache.enable) then "None" else builtins.toJSON {
|
|
inherit (cfg.binaryCache) bucket region endpoint;
|
|
profile = "default";
|
|
}}
|
|
)
|
|
''
|
|
];
|
|
buildbotUrl =
|
|
let
|
|
host = config.services.nginx.virtualHosts.${cfg.domain};
|
|
hasSSL = host.forceSSL || host.addSSL;
|
|
in
|
|
"${if hasSSL then "https" else "http"}://${cfg.domain}/";
|
|
dbUrl = cfg.dbUrl;
|
|
pythonPackages = ps: [
|
|
ps.requests
|
|
ps.treq
|
|
ps.psycopg2
|
|
(ps.toPythonModule pkgs.buildbot-worker)
|
|
pkgs.buildbot-plugins.www
|
|
(pkgs.python3.pkgs.callPackage ../default.nix { })
|
|
];
|
|
};
|
|
|
|
# TODO(raito): we assume worker runs on coordinator. please clean up this later.
|
|
systemd.services.buildbot-worker.serviceConfig.Environment =
|
|
lib.mkIf cfg.binaryCache.enable (
|
|
let
|
|
awsConfigFile = pkgs.writeText "config.ini" ''
|
|
[default]
|
|
region = ${cfg.binaryCache.region}
|
|
endpoint_url = ${cfg.binaryCache.endpoint}
|
|
'';
|
|
in
|
|
[
|
|
"AWS_CONFIG_FILE=${awsConfigFile}"
|
|
"AWS_SHARED_CREDENTIALS_FILE=${cfg.binaryCache.profileCredentialsFile}"
|
|
]
|
|
);
|
|
|
|
systemd.services.buildbot-master = {
|
|
after = [ "postgresql.service" ];
|
|
serviceConfig = {
|
|
# in master.py we read secrets from $CREDENTIALS_DIRECTORY
|
|
LoadCredential = [
|
|
"buildbot-nix-workers:${cfg.workersFile}"
|
|
"buildbot-oauth2-secret:${cfg.oauth2SecretFile}"
|
|
];
|
|
};
|
|
};
|
|
|
|
services.postgresql = {
|
|
enable = true;
|
|
ensureDatabases = [ "buildbot" ];
|
|
ensureUsers = [{
|
|
name = "buildbot";
|
|
ensureDBOwnership = true;
|
|
}];
|
|
};
|
|
|
|
services.nginx.enable = true;
|
|
services.nginx.virtualHosts.${cfg.domain} =
|
|
let
|
|
port = config.services.buildbot-master.port;
|
|
in
|
|
{
|
|
locations = {
|
|
"/".proxyPass = "http://127.0.0.1:${builtins.toString port}/";
|
|
"/sse" = {
|
|
proxyPass = "http://127.0.0.1:${builtins.toString port}/sse";
|
|
# proxy buffering will prevent sse to work
|
|
extraConfig = "proxy_buffering off;";
|
|
};
|
|
"/ws" = {
|
|
proxyPass = "http://127.0.0.1:${builtins.toString port}/ws";
|
|
proxyWebsockets = true;
|
|
# raise the proxy timeout for the websocket
|
|
extraConfig = "proxy_read_timeout 6000s;";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|