parent
0149bdac53
commit
346a1b0ec6
@ -0,0 +1,213 @@ |
||||
/* |
||||
|
||||
This file is for options that NixOS and nix-darwin have in common. |
||||
|
||||
Platform-specific code is in the respective default.nix files. |
||||
|
||||
*/ |
||||
|
||||
{ config, lib, options, pkgs, ... }: |
||||
|
||||
let |
||||
inherit (lib) mkOption mkIf types filterAttrs literalExample mkRenamedOptionModule; |
||||
|
||||
cfg = |
||||
config.services.hercules-ci-agent; |
||||
|
||||
format = pkgs.formats.toml {}; |
||||
|
||||
settingsModule = { config, ... }: { |
||||
freeformType = format.type; |
||||
options = { |
||||
baseDirectory = mkOption { |
||||
type = types.path; |
||||
default = "/var/lib/hercules-ci-agent"; |
||||
description = '' |
||||
State directory (secrets, work directory, etc) for agent |
||||
''; |
||||
}; |
||||
concurrentTasks = mkOption { |
||||
description = '' |
||||
Number of tasks to perform simultaneously, such as evaluations, derivations. |
||||
|
||||
You must have a total capacity across agents of at least 2 concurrent tasks on <literal>x86_64-linux</literal> |
||||
to allow for import from derivation. |
||||
''; |
||||
type = types.int; |
||||
default = 4; |
||||
}; |
||||
workDirectory = mkOption { |
||||
description = '' |
||||
The directory in which temporary subdirectories are created for task state. This includes sources for Nix evaluation. |
||||
''; |
||||
type = types.path; |
||||
default = config.baseDirectory + "/work"; |
||||
defaultText = literalExample ''baseDirectory + "/work"''; |
||||
}; |
||||
staticSecretsDirectory = mkOption { |
||||
description = '' |
||||
This is the default directory to look for statically configured secrets like <literal>cluster-join-token.key</literal>. |
||||
''; |
||||
type = types.path; |
||||
default = config.baseDirectory + "/secrets"; |
||||
defaultText = literalExample ''baseDirectory + "/secrets"''; |
||||
}; |
||||
clusterJoinTokenPath = mkOption { |
||||
description = '' |
||||
Location of the cluster-join-token.key file. |
||||
''; |
||||
type = types.path; |
||||
default = config.staticSecretsDirectory + "/cluster-join-token.key"; |
||||
defaultText = literalExample ''staticSecretsDirectory + "/cluster-join-token.key"''; |
||||
# internal: It's a bit too detailed to show by default in the docs, |
||||
# but useful to define explicitly to allow reuse by other modules. |
||||
internal = true; |
||||
}; |
||||
binaryCachesPath = mkOption { |
||||
description = '' |
||||
Location of the binary-caches.json file. |
||||
''; |
||||
type = types.path; |
||||
default = config.staticSecretsDirectory + "/binary-caches.json"; |
||||
defaultText = literalExample ''staticSecretsDirectory + "/binary-caches.json"''; |
||||
# internal: It's a bit too detailed to show by default in the docs, |
||||
# but useful to define explicitly to allow reuse by other modules. |
||||
internal = true; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
checkNix = |
||||
if !cfg.checkNix |
||||
then "" |
||||
else if lib.versionAtLeast config.nix.package.version "2.4.0" |
||||
then "" |
||||
else pkgs.stdenv.mkDerivation { |
||||
name = "hercules-ci-check-system-nix-src"; |
||||
inherit (config.nix.package) src patches; |
||||
configurePhase = ":"; |
||||
buildPhase = '' |
||||
echo "Checking in-memory pathInfoCache expiry" |
||||
if ! grep 'struct PathInfoCacheValue' src/libstore/store-api.hh >/dev/null; then |
||||
cat 1>&2 <<EOF |
||||
|
||||
You are deploying Hercules CI Agent on a system with an incompatible |
||||
nix-daemon. Please |
||||
- either upgrade Nix to version 2.4.0 (when released), |
||||
- or set option services.hercules-ci-agent.patchNix = true; |
||||
- or set option nix.package to a build of Nix 2.3 with this patch applied: |
||||
https://github.com/NixOS/nix/pull/3405 |
||||
|
||||
The patch is required for Nix-daemon clients that expect a change in binary |
||||
cache contents while running, like the agent's evaluator. Without it, import |
||||
from derivation will fail if your cluster has more than one machine. |
||||
We are conservative with changes to the overall system, which is why we |
||||
keep changes to a minimum and why we ask for confirmation in the form of |
||||
services.hercules-ci-agent.patchNix = true before applying. |
||||
|
||||
EOF |
||||
exit 1 |
||||
fi |
||||
''; |
||||
installPhase = "touch $out"; |
||||
}; |
||||
|
||||
patchedNix = lib.mkIf (!lib.versionAtLeast pkgs.nix.version "2.4.0") ( |
||||
if lib.versionAtLeast pkgs.nix.version "2.4pre" |
||||
then lib.warn "Hercules CI Agent module will not patch 2.4 pre-release. Make sure it includes (equivalently) PR #3043, commit d048577909 or is no older than 2020-03-13." pkgs.nix |
||||
else pkgs.nix.overrideAttrs ( |
||||
o: { |
||||
patches = (o.patches or []) ++ [ backportNix3398 ]; |
||||
} |
||||
) |
||||
); |
||||
|
||||
backportNix3398 = pkgs.fetchurl { |
||||
url = "https://raw.githubusercontent.com/hercules-ci/hercules-ci-agent/hercules-ci-agent-0.7.3/for-upstream/issue-3398-path-info-cache-ttls-backport-2.3.patch"; |
||||
sha256 = "0jfckqjir9il2il7904yc1qyadw366y7xqzg81sp9sl3f1pw70ib"; |
||||
}; |
||||
in |
||||
{ |
||||
imports = [ |
||||
(mkRenamedOptionModule ["services" "hercules-ci-agent" "extraOptions"] ["services" "hercules-ci-agent" "settings"]) |
||||
(mkRenamedOptionModule ["services" "hercules-ci-agent" "baseDirectory"] ["services" "hercules-ci-agent" "settings" "baseDirectory"]) |
||||
(mkRenamedOptionModule ["services" "hercules-ci-agent" "concurrentTasks"] ["services" "hercules-ci-agent" "settings" "concurrentTasks"]) |
||||
]; |
||||
|
||||
options.services.hercules-ci-agent = { |
||||
enable = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Enable to run Hercules CI Agent as a system service. |
||||
|
||||
<link xlink:href="https://hercules-ci.com">Hercules CI</link> is a |
||||
continuous integation service that is centered around Nix. |
||||
|
||||
Support is available at <link xlink:href="mailto:help@hercules-ci.com">help@hercules-ci.com</link>. |
||||
''; |
||||
}; |
||||
patchNix = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Fix Nix 2.3 cache path metadata caching behavior. Has the effect of <literal>nix.package = patch pkgs.nix;</literal> |
||||
|
||||
This option will be removed when Hercules CI Agent moves to Nix 2.4 (upcoming Nix release). |
||||
''; |
||||
}; |
||||
checkNix = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to make sure that the system's Nix (nix-daemon) is compatible. |
||||
|
||||
If you set this to false, please keep up with the change log. |
||||
''; |
||||
}; |
||||
package = mkOption { |
||||
description = '' |
||||
Package containing the bin/hercules-ci-agent executable. |
||||
''; |
||||
type = types.package; |
||||
default = pkgs.hercules-ci-agent; |
||||
defaultText = literalExample "pkgs.hercules-ci-agent"; |
||||
}; |
||||
settings = mkOption { |
||||
description = '' |
||||
These settings are written to the <literal>agent.toml</literal> file. |
||||
|
||||
Not all settings are listed as options, can be set nonetheless. |
||||
|
||||
For the exhaustive list of settings, see <link xlink:href="https://docs.hercules-ci.com/hercules-ci/reference/agent-config/"/>. |
||||
''; |
||||
type = types.submoduleWith { modules = [ settingsModule ]; }; |
||||
}; |
||||
|
||||
/* |
||||
Internal and/or computed values. |
||||
|
||||
These are written as options instead of let binding to allow sharing with |
||||
default.nix on both NixOS and nix-darwin. |
||||
*/ |
||||
tomlFile = mkOption { |
||||
type = types.path; |
||||
internal = true; |
||||
defaultText = "generated hercules-ci-agent.toml"; |
||||
description = '' |
||||
The fully assembled config file. |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
nix.extraOptions = lib.addContextFrom checkNix '' |
||||
# A store path that was missing at first may well have finished building, |
||||
# even shortly after the previous lookup. This *also* applies to the daemon. |
||||
narinfo-cache-negative-ttl = 0 |
||||
''; |
||||
nix.package = mkIf cfg.patchNix patchedNix; |
||||
services.hercules-ci-agent.tomlFile = |
||||
format.generate "hercules-ci-agent.toml" cfg.settings; |
||||
}; |
||||
} |
@ -0,0 +1,86 @@ |
||||
/* |
||||
|
||||
This file is for NixOS-specific options and configs. |
||||
|
||||
Code that is shared with nix-darwin goes in common.nix. |
||||
|
||||
*/ |
||||
|
||||
{ pkgs, config, lib, ... }: |
||||
|
||||
let |
||||
|
||||
inherit (lib) mkIf mkDefault; |
||||
|
||||
cfg = config.services.hercules-ci-agent; |
||||
|
||||
command = "${cfg.package}/bin/hercules-ci-agent --config ${cfg.tomlFile}"; |
||||
testCommand = "${command} --test-configuration"; |
||||
|
||||
in |
||||
{ |
||||
imports = [ |
||||
./common.nix |
||||
(lib.mkRenamedOptionModule ["services" "hercules-ci-agent" "user"] ["systemd" "services" "hercules-ci-agent" "serviceConfig" "User"]) |
||||
]; |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
systemd.services.hercules-ci-agent = { |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "network-online.target" ]; |
||||
wants = [ "network-online.target" ]; |
||||
path = [ config.nix.package ]; |
||||
serviceConfig = { |
||||
User = "hercules-ci-agent"; |
||||
ExecStart = command; |
||||
ExecStartPre = testCommand; |
||||
Restart = "on-failure"; |
||||
RestartSec = 120; |
||||
StartLimitBurst = 30 * 1000000; # practically infinite |
||||
}; |
||||
}; |
||||
|
||||
# Changes in the secrets do not affect the unit in any way that would cause |
||||
# a restart, which is currently necessary to reload the secrets. |
||||
systemd.paths.hercules-ci-agent-restart-files = { |
||||
wantedBy = [ "hercules-ci-agent.service" ]; |
||||
pathConfig = { |
||||
Unit = "hercules-ci-agent-restarter.service"; |
||||
PathChanged = [ cfg.settings.clusterJoinTokenPath cfg.settings.binaryCachesPath ]; |
||||
}; |
||||
}; |
||||
systemd.services.hercules-ci-agent-restarter = { |
||||
serviceConfig.Type = "oneshot"; |
||||
script = '' |
||||
# Wait a bit, with the effect of bundling up file changes into a single |
||||
# run of this script and hopefully a single restart. |
||||
sleep 10 |
||||
if systemctl is-active --quiet hercules-ci-agent.service; then |
||||
if ${testCommand}; then |
||||
systemctl restart hercules-ci-agent.service |
||||
else |
||||
echo 1>&2 "WARNING: Not restarting agent because config is not valid at this time." |
||||
fi |
||||
else |
||||
echo 1>&2 "Not restarting hercules-ci-agent despite config file update, because it is not already active." |
||||
fi |
||||
''; |
||||
}; |
||||
|
||||
# Trusted user allows simplified configuration and better performance |
||||
# when operating in a cluster. |
||||
nix.trustedUsers = [ config.systemd.services.hercules-ci-agent.serviceConfig.User ]; |
||||
services.hercules-ci-agent.settings.nixUserIsTrusted = true; |
||||
|
||||
users.users.hercules-ci-agent = { |
||||
home = cfg.settings.baseDirectory; |
||||
createHome = true; |
||||
group = "hercules-ci-agent"; |
||||
description = "Hercules CI Agent system user"; |
||||
isSystemUser = true; |
||||
}; |
||||
|
||||
users.groups.hercules-ci-agent = {}; |
||||
}; |
||||
} |
Loading…
Reference in new issue