Unify Hydra's NixOS module with the one used for hydra.nixos.org

In particular, the queue runner and web server now run under different
UIDs.
This commit is contained in:
Eelco Dolstra 2015-07-02 01:01:44 +02:00
parent 3e0f5f664a
commit dffb629b8a
3 changed files with 90 additions and 40 deletions

View file

@ -3,6 +3,7 @@
with lib;
let
cfg = config.services.hydra;
baseDir = "/var/lib/hydra";
@ -11,19 +12,25 @@ let
hydraEnv =
{ HYDRA_DBI = cfg.dbi;
HYDRA_CONFIG = "${baseDir}/data/hydra.conf";
HYDRA_DATA = "${baseDir}/data";
HYDRA_CONFIG = "${baseDir}/hydra.conf";
HYDRA_DATA = "${baseDir}";
};
env =
{ NIX_REMOTE = "daemon";
OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
GIT_SSL_CAINFO = "/etc/ssl/certs/ca-bundle.crt";
SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
PGPASSFILE = "${baseDir}/pgpass";
} // hydraEnv // cfg.extraEnv;
serverEnv = env //
{ HYDRA_TRACKER = cfg.tracker;
COLUMNS = "80";
} // (optionalAttrs cfg.debugServer { DBIC_TRACE = 1; });
localDB = "dbi:Pg:dbname=hydra;user=hydra;";
haveLocalDB = cfg.dbi == localDB;
in
{
@ -42,7 +49,7 @@ in
dbi = mkOption {
type = types.str;
default = "dbi:Pg:dbname=hydra;user=hydra;";
default = localDB;
example = "dbi:Pg:dbname=hydra;host=postgres.example.org;user=foo;";
description = ''
The DBI string for Hydra database connection.
@ -82,7 +89,7 @@ in
minimumDiskFree = mkOption {
type = types.int;
default = 5;
default = 0;
description = ''
Threshold of minimum disk space (GiB) to determine if queue runner should run or not.
'';
@ -90,7 +97,7 @@ in
minimumDiskFreeEvaluator = mkOption {
type = types.int;
default = 2;
default = 0;
description = ''
Threshold of minimum disk space (GiB) to determine if evaluator should run or not.
'';
@ -115,25 +122,25 @@ in
type = types.nullOr types.path;
default = null;
description = ''
File name of an alternate logo to be displayed on the web pages.
Path to a file containing the logo of your Hydra instance.
'';
};
debugServer = mkOption {
type = types.bool;
default = false;
description = "Whether to run the server in debug mode";
description = "Whether to run the server in debug mode.";
};
extraConfig = mkOption {
type = types.lines;
description = "Extra lines for the hydra config";
description = "Extra lines for the Hydra configuration.";
};
extraEnv = mkOption {
type = types.attrsOf types.str;
default = {};
description = "Extra environment variables for Hydra";
description = "Extra environment variables for Hydra.";
};
};
@ -144,6 +151,30 @@ in
config = mkIf cfg.enable {
users.extraGroups.hydra = { };
users.extraUsers.hydra =
{ description = "Hydra";
group = "hydra";
createHome = true;
home = baseDir;
useDefaultShell = true;
};
users.extraUsers.hydra-queue-runner =
{ description = "Hydra queue runner";
group = "hydra";
useDefaultShell = true;
};
users.extraUsers.hydra-www =
{ description = "Hydra web server";
group = "hydra";
useDefaultShell = true;
};
nix.trustedUsers = [ "hydra-queue-runner" ];
services.hydra.package = mkDefault ((import ./release.nix {}).build.x86_64-linux);
services.hydra.extraConfig =
@ -161,13 +192,6 @@ in
environment.variables = hydraEnv;
users.extraUsers.hydra =
{ description = "Hydra";
home = baseDir;
createHome = true;
useDefaultShell = true;
};
nix.extraOptions = ''
gc-keep-outputs = true
gc-keep-derivations = true
@ -177,18 +201,26 @@ in
gc-check-reachability = false
'';
nix.trustedUsers = [ "hydra" ];
systemd.services.hydra-init =
{ wantedBy = [ "multi-user.target" ];
requires = [ "postgresql.service" ];
after = [ "postgresql.service" ];
environment = env;
preStart = ''
mkdir -m 0700 -p ${baseDir}/data
chown hydra ${baseDir}/data
ln -sf ${hydraConf} ${baseDir}/data/hydra.conf
${optionalString (cfg.dbi == "dbi:Pg:dbname=hydra;user=hydra;") ''
mkdir -p ${baseDir}
chown hydra.hydra ${baseDir}
chmod 0750 ${baseDir}
ln -sf ${hydraConf} ${baseDir}/hydra.conf
mkdir -m 0700 -p /var/lib/hydra/www
chown hydra-www.hydra /var/lib/hydra/www
mkdir -m 0700 -p /var/lib/hydra/queue-runner
mkdir -m 0750 -p /var/lib/hydra/build-logs
chown hydra-queue-runner.hydra /var/lib/hydra/queue-runner /var/lib/hydra/build-logs
${optionalString haveLocalDB ''
if ! [ -e ${baseDir}/.db-created ]; then
${config.services.postgresql.package}/bin/createuser hydra
${config.services.postgresql.package}/bin/createdb -O hydra hydra
@ -207,13 +239,14 @@ in
{ wantedBy = [ "multi-user.target" ];
requires = [ "hydra-init.service" ];
after = [ "hydra-init.service" ];
environment = serverEnv // { COLUMNS = "80"; };
environment = serverEnv;
serviceConfig =
{ ExecStart =
"@${cfg.package}/bin/hydra-server hydra-server -f -h '${cfg.listenHost}' "
+ "-p ${toString cfg.port} --max_spare_servers 5 --max_servers 25 "
+ "--max_requests 100 ${optionalString cfg.debugServer "-d"}";
User = "hydra";
User = "hydra-www";
PermissionsStartOnly = true;
Restart = "always";
};
};
@ -225,9 +258,10 @@ in
path = [ pkgs.nettools ];
environment = env;
serviceConfig =
{ ExecStart = "@${cfg.package}/bin/hydra-queue-runner hydra-queue-runner";
{ ExecStartPre = "${cfg.package}/bin/hydra-queue-runner --unlock";
ExecStart = "@${cfg.package}/bin/hydra-queue-runner hydra-queue-runner";
ExecStopPost = "${cfg.package}/bin/hydra-queue-runner --unlock";
User = "hydra";
User = "hydra-queue-runner";
Restart = "always";
};
};
@ -253,7 +287,7 @@ in
{ ExecStart = "@${cfg.package}/bin/hydra-update-gc-roots hydra-update-gc-roots";
User = "hydra";
};
startAt = "02:15";
startAt = "2,14:15";
};
systemd.services.hydra-send-stats =
@ -266,13 +300,11 @@ in
};
};
services.cron.systemCronJobs =
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"
# If there is less than a certain amount of free disk space, stop
# the queue/evaluator to prevent builds from failing or aborting.
systemd.services.hydra-check-space =
{ script =
''
#! ${pkgs.stdenv.shell}
if [ $(($(stat -f -c '%a' /nix/store) * $(stat -f -c '%S' /nix/store))) -lt $((${toString cfg.minimumDiskFree} * 1024**3)) ]; then
echo "stopping Hydra queue runner due to lack of free space..."
systemctl stop hydra-queue-runner
@ -282,8 +314,24 @@ in
systemctl stop hydra-evaluator
fi
'';
in
[ "*/5 * * * * root ${checkSpace} &> ${baseDir}/data/checkspace.log"
];
startAt = "*:0/5";
};
services.postgresql.enable = mkIf haveLocalDB true;
services.postgresql.identMap = optionalString haveLocalDB
''
hydra-users hydra hydra
hydra-users hydra-queue-runner hydra
hydra-users hydra-www hydra
hydra-users root hydra
'';
services.postgresql.authentication = optionalString haveLocalDB
''
local hydra all ident map=hydra-users
'';
};
}

View file

@ -1568,7 +1568,9 @@ void State::notificationSender()
std::shared_ptr<PathLocks> State::acquireGlobalLock()
{
Path lockPath = hydraData + "/queue-runner";
Path lockPath = hydraData + "/queue-runner/lock";
createDirs(dirOf(lockPath));
auto lock = std::make_shared<PathLocks>();
if (!lock->lockPaths(PathSet({lockPath}), "", false)) return 0;

View file

@ -55,7 +55,7 @@ __PACKAGE__->config(
},
'Plugin::Session' => {
expires => 3600 * 24 * 7,
storage => ($ENV{'HYDRA_SERVER_DATA'} // Hydra::Model::DB::getHydraPath) . "/session_data",
storage => Hydra::Model::DB::getHydraPath . "/www/session_data",
unlink_on_exit => 0
},
'Plugin::AccessLog' => {