2011-05-05 06:27:38 +00:00
|
|
|
{ config, pkgs, ... }:
|
|
|
|
|
|
|
|
with pkgs.lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.hydra;
|
|
|
|
|
2013-01-22 13:41:02 +00:00
|
|
|
hydraConf = pkgs.writeScript "hydra.conf"
|
2011-05-05 06:27:38 +00:00
|
|
|
''
|
|
|
|
using_frontend_proxy 1
|
|
|
|
base_uri ${cfg.hydraURL}
|
|
|
|
notification_sender ${cfg.notificationSender}
|
|
|
|
max_servers 25
|
|
|
|
'';
|
2013-01-22 13:41:02 +00:00
|
|
|
|
2013-03-22 12:58:08 +00:00
|
|
|
env =
|
|
|
|
{ NIX_REMOTE = "daemon";
|
|
|
|
HYDRA_DBI = cfg.dbi;
|
|
|
|
HYDRA_CONFIG = "${cfg.baseDir}/data/hydra.conf";
|
|
|
|
HYDRA_DATA = "${cfg.baseDir}/data";
|
|
|
|
HYDRA_PORT = "${toString cfg.port}";
|
|
|
|
OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
|
|
|
|
};
|
|
|
|
|
|
|
|
serverEnv = env //
|
|
|
|
{ HYDRA_LOGO = if cfg.logo != null then cfg.logo else "";
|
|
|
|
HYDRA_TRACKER = cfg.tracker;
|
|
|
|
};
|
2011-05-05 06:27:38 +00:00
|
|
|
in
|
|
|
|
|
|
|
|
{
|
|
|
|
###### interface
|
|
|
|
options = {
|
|
|
|
services.hydra = rec {
|
2013-01-22 13:41:02 +00:00
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
enable = mkOption {
|
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
Whether to run Hydra services.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
baseDir = mkOption {
|
|
|
|
default = "/home/${user.default}";
|
|
|
|
description = ''
|
|
|
|
The directory holding configuration, logs and temporary files.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
user = mkOption {
|
|
|
|
default = "hydra";
|
|
|
|
description = ''
|
|
|
|
The user the Hydra services should run as.
|
|
|
|
'';
|
|
|
|
};
|
2013-01-22 13:41:02 +00:00
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
dbi = mkOption {
|
|
|
|
default = "dbi:Pg:dbname=hydra;host=localhost;user=root;";
|
2011-05-05 10:07:59 +00:00
|
|
|
example = "dbi:SQLite:/home/hydra/db/hydra.sqlite";
|
2011-05-05 06:27:38 +00:00
|
|
|
description = ''
|
2011-05-05 10:07:59 +00:00
|
|
|
The DBI string for Hydra database connection.
|
2011-05-05 06:27:38 +00:00
|
|
|
'';
|
|
|
|
};
|
2013-01-22 13:41:02 +00:00
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
hydra = mkOption {
|
2013-03-22 12:58:08 +00:00
|
|
|
#default = pkgs.hydra;
|
2011-05-05 06:27:38 +00:00
|
|
|
description = ''
|
|
|
|
Location of hydra
|
|
|
|
'';
|
|
|
|
};
|
2013-01-22 13:41:02 +00:00
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
hydraURL = mkOption {
|
|
|
|
default = "http://hydra.nixos.org";
|
|
|
|
description = ''
|
2013-01-22 13:41:02 +00:00
|
|
|
The base URL for the Hydra webserver instance. Used for links in emails.
|
2011-05-05 06:27:38 +00:00
|
|
|
'';
|
|
|
|
};
|
2011-05-05 10:07:56 +00:00
|
|
|
|
|
|
|
port = mkOption {
|
|
|
|
default = 3000;
|
|
|
|
description = ''
|
|
|
|
TCP port the web server should listen to.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
minimumDiskFree = mkOption {
|
|
|
|
default = 5;
|
|
|
|
description = ''
|
2013-01-22 13:41:02 +00:00
|
|
|
Threshold of minimum disk space (G) to determine if queue runner should run or not.
|
2011-05-05 06:27:38 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
minimumDiskFreeEvaluator = mkOption {
|
|
|
|
default = 2;
|
|
|
|
description = ''
|
2013-01-22 13:41:02 +00:00
|
|
|
Threshold of minimum disk space (G) to determine if evaluator should run or not.
|
2011-05-05 06:27:38 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
notificationSender = mkOption {
|
|
|
|
default = "e.dolstra@tudelft.nl";
|
|
|
|
description = ''
|
2013-01-22 13:41:02 +00:00
|
|
|
Sender email address used for email notifications.
|
2011-05-05 06:27:38 +00:00
|
|
|
'';
|
2013-01-22 13:41:02 +00:00
|
|
|
};
|
2011-05-05 06:27:38 +00:00
|
|
|
|
|
|
|
tracker = mkOption {
|
|
|
|
default = "";
|
|
|
|
description = ''
|
|
|
|
Piece of HTML that is included on all pages.
|
|
|
|
'';
|
2011-05-05 10:07:59 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
logo = mkOption {
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
File name of an alternate logo to be displayed on the web pages.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
autoStart = mkOption {
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
If hydra upstart jobs should start automatically.
|
|
|
|
'';
|
2013-01-22 13:41:02 +00:00
|
|
|
};
|
2013-03-22 12:58:08 +00:00
|
|
|
|
|
|
|
useWAL = mkOption {
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
Whether to use SQLite's Write-Ahead Logging, which may improve performance.
|
|
|
|
'';
|
|
|
|
};
|
2013-01-22 13:41:02 +00:00
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
};
|
2013-01-22 13:41:02 +00:00
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
|
|
|
|
###### implementation
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
environment.systemPackages = [ cfg.hydra ];
|
|
|
|
|
|
|
|
users.extraUsers = [
|
|
|
|
{ name = cfg.user;
|
|
|
|
description = "Hydra";
|
|
|
|
home = cfg.baseDir;
|
|
|
|
createHome = true;
|
|
|
|
useDefaultShell = true;
|
2013-01-22 13:41:02 +00:00
|
|
|
}
|
2011-05-05 06:27:38 +00:00
|
|
|
];
|
|
|
|
|
2012-06-14 08:57:12 +00:00
|
|
|
# We have our own crontab entries for GC, see below.
|
|
|
|
nix.gc.automatic = false;
|
|
|
|
|
2011-05-05 06:27:38 +00:00
|
|
|
nix.extraOptions = ''
|
|
|
|
gc-keep-outputs = true
|
|
|
|
gc-keep-derivations = true
|
|
|
|
|
|
|
|
# The default (`true') slows Nix down a lot since the build farm
|
|
|
|
# has so many GC roots.
|
|
|
|
gc-check-reachability = false
|
|
|
|
|
|
|
|
# Hydra needs caching of build failures.
|
|
|
|
build-cache-failure = true
|
|
|
|
|
|
|
|
build-poll-interval = 10
|
2013-03-22 12:58:08 +00:00
|
|
|
|
|
|
|
# Online log compression makes it impossible to get the tail of
|
|
|
|
# builds that are in progress.
|
|
|
|
build-compress-log = false
|
2011-05-05 06:27:38 +00:00
|
|
|
|
2013-03-22 12:58:08 +00:00
|
|
|
use-sqlite-wal = ${if cfg.useWAL then "true" else "false"}
|
2011-05-05 06:27:38 +00:00
|
|
|
'';
|
|
|
|
|
2013-03-22 12:58:08 +00:00
|
|
|
jobs."hydra-init" =
|
|
|
|
{ wantedBy = [ "multi-user.target" ];
|
|
|
|
script = ''
|
2011-05-05 06:27:38 +00:00
|
|
|
mkdir -p ${cfg.baseDir}/data
|
|
|
|
chown ${cfg.user} ${cfg.baseDir}/data
|
|
|
|
ln -sf ${hydraConf} ${cfg.baseDir}/data/hydra.conf
|
|
|
|
'';
|
2013-03-22 12:58:08 +00:00
|
|
|
task = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.services."hydra-server" =
|
|
|
|
{ wantedBy = [ "multi-user.target" ];
|
|
|
|
wants = [ "hydra-init.service" ];
|
|
|
|
after = [ "hydra-init.service" ];
|
|
|
|
environment = serverEnv;
|
|
|
|
serviceConfig =
|
|
|
|
{ ExecStart = "@${cfg.hydra}/bin/hydra-server hydra-server -f -h \* --max_spare_servers 5 --max_servers 25 --max_requests 100";
|
|
|
|
User = cfg.user;
|
|
|
|
Restart = "always";
|
|
|
|
};
|
2011-05-05 06:27:38 +00:00
|
|
|
};
|
|
|
|
|
2013-03-22 12:58:08 +00:00
|
|
|
systemd.services."hydra-queue-runner" =
|
|
|
|
{ wantedBy = [ "multi-user.target" ];
|
|
|
|
wants = [ "hydra-init.service" ];
|
|
|
|
after = [ "hydra-init.service" "network.target" ];
|
|
|
|
path = [ pkgs.nettools pkgs.ssmtp ];
|
|
|
|
environment = env;
|
|
|
|
serviceConfig =
|
|
|
|
{ ExecStartPre = "${cfg.hydra}/bin/hydra-queue-runner --unlock";
|
|
|
|
ExecStart = "@${cfg.hydra}/bin/hydra-queue-runner hydra-queue-runner";
|
|
|
|
User = cfg.user;
|
|
|
|
Restart = "always";
|
|
|
|
};
|
2011-05-05 06:27:38 +00:00
|
|
|
};
|
|
|
|
|
2013-03-22 12:58:08 +00:00
|
|
|
systemd.services."hydra-evaluator" =
|
|
|
|
{ wantedBy = [ "multi-user.target" ];
|
|
|
|
wants = [ "hydra-init.service" ];
|
|
|
|
after = [ "hydra-init.service" "network.target" ];
|
|
|
|
path = [ pkgs.nettools pkgs.ssmtp ];
|
|
|
|
environment = env;
|
|
|
|
serviceConfig =
|
|
|
|
{ ExecStart = "@${cfg.hydra}/bin/hydra-evaluator hydra-evaluator";
|
|
|
|
User = cfg.user;
|
|
|
|
Restart = "always";
|
|
|
|
};
|
2011-05-05 06:27:38 +00:00
|
|
|
};
|
|
|
|
|
2013-03-22 12:58:08 +00:00
|
|
|
systemd.services."hydra-update-gc-roots" =
|
|
|
|
{ wants = [ "hydra-init.service" ];
|
|
|
|
after = [ "hydra-init.service" ];
|
|
|
|
environment = env;
|
|
|
|
serviceConfig =
|
|
|
|
{ ExecStart = "@${cfg.hydra}/bin/hydra-update-gc-roots hydra-update-gc-roots";
|
|
|
|
User = cfg.user;
|
|
|
|
};
|
2011-05-05 06:27:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
services.cron.systemCronJobs =
|
2012-06-14 08:57:12 +00:00
|
|
|
let
|
|
|
|
# If there is less than ... GiB of free disk space, stop the queue
|
|
|
|
# to prevent builds from failing or aborting.
|
|
|
|
checkSpace = pkgs.writeScript "hydra-check-space"
|
|
|
|
''
|
|
|
|
#! /bin/sh
|
|
|
|
if [ $(($(stat -f -c '%a' /nix/store) * $(stat -f -c '%S' /nix/store))) -lt $((${toString cfg.minimumDiskFree} * 1024**3)) ]; then
|
2013-03-22 12:58:08 +00:00
|
|
|
stop hydra_queue_runner
|
|
|
|
fi
|
|
|
|
if [ $(($(stat -f -c '%a' /nix/store) * $(stat -f -c '%S' /nix/store))) -lt $((${toString cfg.minimumDiskFreeEvaluator} * 1024**3)) ]; then
|
|
|
|
stop hydra_evaluator
|
2012-06-14 08:57:12 +00:00
|
|
|
fi
|
|
|
|
'';
|
|
|
|
|
|
|
|
compressLogs = pkgs.writeScript "compress-logs" ''
|
|
|
|
#! /bin/sh -e
|
|
|
|
touch -d 'last month' r
|
|
|
|
find /nix/var/log/nix/drvs -type f -a ! -newer r -name '*.drv' | xargs bzip2 -v
|
|
|
|
'';
|
|
|
|
in
|
2013-03-22 12:58:08 +00:00
|
|
|
[ "*/5 * * * * root ${checkSpace} &> ${cfg.baseDir}/data/checkspace.log"
|
2012-06-14 08:57:12 +00:00
|
|
|
"15 5 * * * root ${compressLogs} &> ${cfg.baseDir}/data/compress.log"
|
2013-03-22 12:58:08 +00:00
|
|
|
"15 2 * * * root ${pkgs.systemd}/bin/systemctl start hydra-update-gc-roots.service"
|
2012-06-14 08:57:12 +00:00
|
|
|
];
|
|
|
|
};
|
2011-05-05 06:27:38 +00:00
|
|
|
}
|