nixos/hercules-ci-agent: sync module with upstream
This commit is contained in:
parent
e8d32cbe66
commit
ebafd551d7
|
@ -10,171 +10,18 @@
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
filterAttrs
|
filterAttrs
|
||||||
literalMD
|
|
||||||
literalExpression
|
literalExpression
|
||||||
mkIf
|
mkIf
|
||||||
mkOption
|
mkOption
|
||||||
mkRemovedOptionModule
|
mkRemovedOptionModule
|
||||||
mkRenamedOptionModule
|
mkRenamedOptionModule
|
||||||
types
|
types
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
cfg =
|
cfg = config.services.hercules-ci-agent;
|
||||||
config.services.hercules-ci-agent;
|
|
||||||
|
|
||||||
format = pkgs.formats.toml { };
|
inherit (import ./settings.nix { inherit pkgs lib; }) format settingsModule;
|
||||||
|
|
||||||
settingsModule = { config, ... }: {
|
|
||||||
freeformType = format.type;
|
|
||||||
options = {
|
|
||||||
apiBaseUrl = mkOption {
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
API base URL that the agent will connect to.
|
|
||||||
|
|
||||||
When using Hercules CI Enterprise, set this to the URL where your
|
|
||||||
Hercules CI server is reachable.
|
|
||||||
'';
|
|
||||||
type = types.str;
|
|
||||||
default = "https://hercules-ci.com";
|
|
||||||
};
|
|
||||||
baseDirectory = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/var/lib/hercules-ci-agent";
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
State directory (secrets, work directory, etc) for agent
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
concurrentTasks = mkOption {
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
Number of tasks to perform simultaneously.
|
|
||||||
|
|
||||||
A task is a single derivation build, an evaluation or an effect run.
|
|
||||||
At minimum, you need 2 concurrent tasks for `x86_64-linux`
|
|
||||||
in your cluster, to allow for import from derivation.
|
|
||||||
|
|
||||||
`concurrentTasks` can be around the CPU core count or lower if memory is
|
|
||||||
the bottleneck.
|
|
||||||
|
|
||||||
The optimal value depends on the resource consumption characteristics of your workload,
|
|
||||||
including memory usage and in-task parallelism. This is typically determined empirically.
|
|
||||||
|
|
||||||
When scaling, it is generally better to have a double-size machine than two machines,
|
|
||||||
because each split of resources causes inefficiencies; particularly with regards
|
|
||||||
to build latency because of extra downloads.
|
|
||||||
'';
|
|
||||||
type = types.either types.ints.positive (types.enum [ "auto" ]);
|
|
||||||
default = "auto";
|
|
||||||
};
|
|
||||||
labels = mkOption {
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
A key-value map of user data.
|
|
||||||
|
|
||||||
This data will be available to organization members in the dashboard and API.
|
|
||||||
|
|
||||||
The values can be of any TOML type that corresponds to a JSON type, but arrays
|
|
||||||
can not contain tables/objects due to limitations of the TOML library. Values
|
|
||||||
involving arrays of non-primitive types may not be representable currently.
|
|
||||||
'';
|
|
||||||
type = format.type;
|
|
||||||
defaultText = literalExpression ''
|
|
||||||
{
|
|
||||||
agent.source = "..."; # One of "nixpkgs", "flake", "override"
|
|
||||||
lib.version = "...";
|
|
||||||
pkgs.version = "...";
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
workDirectory = mkOption {
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
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 = literalExpression ''baseDirectory + "/work"'';
|
|
||||||
};
|
|
||||||
staticSecretsDirectory = mkOption {
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
This is the default directory to look for statically configured secrets like `cluster-join-token.key`.
|
|
||||||
|
|
||||||
See also `clusterJoinTokenPath` and `binaryCachesPath` for fine-grained configuration.
|
|
||||||
'';
|
|
||||||
type = types.path;
|
|
||||||
default = config.baseDirectory + "/secrets";
|
|
||||||
defaultText = literalExpression ''baseDirectory + "/secrets"'';
|
|
||||||
};
|
|
||||||
clusterJoinTokenPath = mkOption {
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
Location of the cluster-join-token.key file.
|
|
||||||
|
|
||||||
You can retrieve the contents of the file when creating a new agent via
|
|
||||||
<https://hercules-ci.com/dashboard>.
|
|
||||||
|
|
||||||
As this value is confidential, it should not be in the store, but
|
|
||||||
installed using other means, such as agenix, NixOps
|
|
||||||
`deployment.keys`, or manual installation.
|
|
||||||
|
|
||||||
The contents of the file are used for authentication between the agent and the API.
|
|
||||||
'';
|
|
||||||
type = types.path;
|
|
||||||
default = config.staticSecretsDirectory + "/cluster-join-token.key";
|
|
||||||
defaultText = literalExpression ''staticSecretsDirectory + "/cluster-join-token.key"'';
|
|
||||||
};
|
|
||||||
binaryCachesPath = mkOption {
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
Path to a JSON file containing binary cache secret keys.
|
|
||||||
|
|
||||||
As these values are confidential, they should not be in the store, but
|
|
||||||
copied over using other means, such as agenix, NixOps
|
|
||||||
`deployment.keys`, or manual installation.
|
|
||||||
|
|
||||||
The format is described on <https://docs.hercules-ci.com/hercules-ci-agent/binary-caches-json/>.
|
|
||||||
'';
|
|
||||||
type = types.path;
|
|
||||||
default = config.staticSecretsDirectory + "/binary-caches.json";
|
|
||||||
defaultText = literalExpression ''staticSecretsDirectory + "/binary-caches.json"'';
|
|
||||||
};
|
|
||||||
secretsJsonPath = mkOption {
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
Path to a JSON file containing secrets for effects.
|
|
||||||
|
|
||||||
As these values are confidential, they should not be in the store, but
|
|
||||||
copied over using other means, such as agenix, NixOps
|
|
||||||
`deployment.keys`, or manual installation.
|
|
||||||
|
|
||||||
The format is described on <https://docs.hercules-ci.com/hercules-ci-agent/secrets-json/>.
|
|
||||||
'';
|
|
||||||
type = types.path;
|
|
||||||
default = config.staticSecretsDirectory + "/secrets.json";
|
|
||||||
defaultText = literalExpression ''staticSecretsDirectory + "/secrets.json"'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# TODO (roberth, >=2022) remove
|
|
||||||
checkNix =
|
|
||||||
if !cfg.checkNix
|
|
||||||
then ""
|
|
||||||
else if lib.versionAtLeast config.nix.package.version "2.3.10"
|
|
||||||
then ""
|
|
||||||
else
|
|
||||||
pkgs.stdenv.mkDerivation {
|
|
||||||
name = "hercules-ci-check-system-nix-src";
|
|
||||||
inherit (config.nix.package) src patches;
|
|
||||||
dontConfigure = true;
|
|
||||||
buildPhase = ''
|
|
||||||
echo "Checking in-memory pathInfoCache expiry"
|
|
||||||
if ! grep '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 make sure nix.package is set to a Nix version of at
|
|
||||||
least 2.3.10 or a master version more recent than Mar 12, 2020.
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
installPhase = "touch $out";
|
|
||||||
};
|
|
||||||
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -198,15 +45,6 @@ in
|
||||||
Support is available at [help@hercules-ci.com](mailto:help@hercules-ci.com).
|
Support is available at [help@hercules-ci.com](mailto:help@hercules-ci.com).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
checkNix = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
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 {
|
package = mkOption {
|
||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
Package containing the bin/hercules-ci-agent executable.
|
Package containing the bin/hercules-ci-agent executable.
|
||||||
|
@ -235,7 +73,7 @@ in
|
||||||
tomlFile = mkOption {
|
tomlFile = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
internal = true;
|
internal = true;
|
||||||
defaultText = literalMD "generated `hercules-ci-agent.toml`";
|
defaultText = lib.literalMD "generated `hercules-ci-agent.toml`";
|
||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
The fully assembled config file.
|
The fully assembled config file.
|
||||||
'';
|
'';
|
||||||
|
@ -243,7 +81,27 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
nix.extraOptions = lib.addContextFrom checkNix ''
|
# Make sure that nix.extraOptions does not override trusted-users
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion =
|
||||||
|
(cfg.settings.nixUserIsTrusted or false) ->
|
||||||
|
builtins.match ".*(^|\n)[ \t]*trusted-users[ \t]*=.*" config.nix.extraOptions == null;
|
||||||
|
message = ''
|
||||||
|
hercules-ci-agent: Please do not set `trusted-users` in `nix.extraOptions`.
|
||||||
|
|
||||||
|
The hercules-ci-agent module by default relies on `nix.settings.trusted-users`
|
||||||
|
to be effectful, but a line like `trusted-users = ...` in `nix.extraOptions`
|
||||||
|
will override the value set in `nix.settings.trusted-users`.
|
||||||
|
|
||||||
|
Instead of setting `trusted-users` in the `nix.extraOptions` string, you should
|
||||||
|
set an option with additive semantics, such as
|
||||||
|
- the NixOS option `nix.settings.trusted-users`, or
|
||||||
|
- the Nix option in the `extraOptions` string, `extra-trusted-users`
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
nix.extraOptions = ''
|
||||||
# A store path that was missing at first may well have finished building,
|
# 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.
|
# even shortly after the previous lookup. This *also* applies to the daemon.
|
||||||
narinfo-cache-negative-ttl = 0
|
narinfo-cache-negative-ttl = 0
|
||||||
|
@ -251,14 +109,9 @@ in
|
||||||
services.hercules-ci-agent = {
|
services.hercules-ci-agent = {
|
||||||
tomlFile =
|
tomlFile =
|
||||||
format.generate "hercules-ci-agent.toml" cfg.settings;
|
format.generate "hercules-ci-agent.toml" cfg.settings;
|
||||||
|
settings.config._module.args = {
|
||||||
settings.labels = {
|
packageOption = options.services.hercules-ci-agent.package;
|
||||||
agent.source =
|
inherit pkgs;
|
||||||
if options.services.hercules-ci-agent.package.highestPrio == (lib.modules.mkOptionDefault { }).priority
|
|
||||||
then "nixpkgs"
|
|
||||||
else lib.mkOptionDefault "override";
|
|
||||||
pkgs.version = pkgs.lib.version;
|
|
||||||
lib.version = lib.version;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,8 +36,14 @@ in
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = 120;
|
RestartSec = 120;
|
||||||
|
|
||||||
LimitSTACK = 256 * 1024 * 1024;
|
# If a worker goes OOM, don't kill the main process. It needs to
|
||||||
|
# report the failure and it's unlikely to be part of the problem.
|
||||||
OOMPolicy = "continue";
|
OOMPolicy = "continue";
|
||||||
|
|
||||||
|
# Work around excessive stack use by libstdc++ regex
|
||||||
|
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
|
||||||
|
# A 256 MiB stack allows between 400 KiB and 1.5 MiB file to be matched by ".*".
|
||||||
|
LimitSTACK = 256 * 1024 * 1024;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
# Not a module
|
||||||
|
{ pkgs, lib }:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
types
|
||||||
|
literalExpression
|
||||||
|
mkOption
|
||||||
|
;
|
||||||
|
|
||||||
|
format = pkgs.formats.toml { };
|
||||||
|
|
||||||
|
settingsModule = { config, packageOption, pkgs, ... }: {
|
||||||
|
freeformType = format.type;
|
||||||
|
options = {
|
||||||
|
apiBaseUrl = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
API base URL that the agent will connect to.
|
||||||
|
|
||||||
|
When using Hercules CI Enterprise, set this to the URL where your
|
||||||
|
Hercules CI server is reachable.
|
||||||
|
'';
|
||||||
|
type = types.str;
|
||||||
|
default = "https://hercules-ci.com";
|
||||||
|
};
|
||||||
|
baseDirectory = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "/var/lib/hercules-ci-agent";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
State directory (secrets, work directory, etc) for agent
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
concurrentTasks = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Number of tasks to perform simultaneously.
|
||||||
|
|
||||||
|
A task is a single derivation build, an evaluation or an effect run.
|
||||||
|
At minimum, you need 2 concurrent tasks for `x86_64-linux`
|
||||||
|
in your cluster, to allow for import from derivation.
|
||||||
|
|
||||||
|
`concurrentTasks` can be around the CPU core count or lower if memory is
|
||||||
|
the bottleneck.
|
||||||
|
|
||||||
|
The optimal value depends on the resource consumption characteristics of your workload,
|
||||||
|
including memory usage and in-task parallelism. This is typically determined empirically.
|
||||||
|
|
||||||
|
When scaling, it is generally better to have a double-size machine than two machines,
|
||||||
|
because each split of resources causes inefficiencies; particularly with regards
|
||||||
|
to build latency because of extra downloads.
|
||||||
|
'';
|
||||||
|
type = types.either types.ints.positive (types.enum [ "auto" ]);
|
||||||
|
default = "auto";
|
||||||
|
defaultText = lib.literalMD ''
|
||||||
|
`"auto"`, meaning equal to the number of CPU cores.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
labels = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
A key-value map of user data.
|
||||||
|
|
||||||
|
This data will be available to organization members in the dashboard and API.
|
||||||
|
|
||||||
|
The values can be of any TOML type that corresponds to a JSON type, but arrays
|
||||||
|
can not contain tables/objects due to limitations of the TOML library. Values
|
||||||
|
involving arrays of non-primitive types may not be representable currently.
|
||||||
|
'';
|
||||||
|
type = format.type;
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
{
|
||||||
|
agent.source = "..."; # One of "nixpkgs", "flake", "override"
|
||||||
|
lib.version = "...";
|
||||||
|
pkgs.version = "...";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
workDirectory = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
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 = literalExpression ''baseDirectory + "/work"'';
|
||||||
|
};
|
||||||
|
staticSecretsDirectory = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
This is the default directory to look for statically configured secrets like `cluster-join-token.key`.
|
||||||
|
|
||||||
|
See also `clusterJoinTokenPath` and `binaryCachesPath` for fine-grained configuration.
|
||||||
|
'';
|
||||||
|
type = types.path;
|
||||||
|
default = config.baseDirectory + "/secrets";
|
||||||
|
defaultText = literalExpression ''baseDirectory + "/secrets"'';
|
||||||
|
};
|
||||||
|
clusterJoinTokenPath = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Location of the cluster-join-token.key file.
|
||||||
|
|
||||||
|
You can retrieve the contents of the file when creating a new agent via
|
||||||
|
<https://hercules-ci.com/dashboard>.
|
||||||
|
|
||||||
|
As this value is confidential, it should not be in the store, but
|
||||||
|
installed using other means, such as agenix, NixOps
|
||||||
|
`deployment.keys`, or manual installation.
|
||||||
|
|
||||||
|
The contents of the file are used for authentication between the agent and the API.
|
||||||
|
'';
|
||||||
|
type = types.path;
|
||||||
|
default = config.staticSecretsDirectory + "/cluster-join-token.key";
|
||||||
|
defaultText = literalExpression ''staticSecretsDirectory + "/cluster-join-token.key"'';
|
||||||
|
};
|
||||||
|
binaryCachesPath = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Path to a JSON file containing binary cache secret keys.
|
||||||
|
|
||||||
|
As these values are confidential, they should not be in the store, but
|
||||||
|
copied over using other means, such as agenix, NixOps
|
||||||
|
`deployment.keys`, or manual installation.
|
||||||
|
|
||||||
|
The format is described on <https://docs.hercules-ci.com/hercules-ci-agent/binary-caches-json/>.
|
||||||
|
'';
|
||||||
|
type = types.path;
|
||||||
|
default = config.staticSecretsDirectory + "/binary-caches.json";
|
||||||
|
defaultText = literalExpression ''staticSecretsDirectory + "/binary-caches.json"'';
|
||||||
|
};
|
||||||
|
secretsJsonPath = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Path to a JSON file containing secrets for effects.
|
||||||
|
|
||||||
|
As these values are confidential, they should not be in the store, but
|
||||||
|
copied over using other means, such as agenix, NixOps
|
||||||
|
`deployment.keys`, or manual installation.
|
||||||
|
|
||||||
|
The format is described on <https://docs.hercules-ci.com/hercules-ci-agent/secrets-json/>.
|
||||||
|
'';
|
||||||
|
type = types.path;
|
||||||
|
default = config.staticSecretsDirectory + "/secrets.json";
|
||||||
|
defaultText = literalExpression ''staticSecretsDirectory + "/secrets.json"'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
labels = {
|
||||||
|
agent.source =
|
||||||
|
if packageOption.highestPrio == (lib.modules.mkOptionDefault { }).priority
|
||||||
|
then "nixpkgs"
|
||||||
|
else lib.mkOptionDefault "override";
|
||||||
|
pkgs.version = pkgs.lib.version;
|
||||||
|
lib.version = lib.version;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit format settingsModule;
|
||||||
|
}
|
Loading…
Reference in a new issue