Merge pull request #205526 from newAM/github-runner-oom

nixos/github-runner: add workDir option
This commit is contained in:
Aaron Andersen
2023-01-08 19:01:44 -05:00
committed by GitHub
2 changed files with 36 additions and 15 deletions

View File

@@ -170,4 +170,16 @@ with lib;
default = null; default = null;
defaultText = literalExpression "username"; defaultText = literalExpression "username";
}; };
workDir = mkOption {
type = with types; nullOr str;
description = lib.mdDoc ''
Working directory, available as `$GITHUB_WORKSPACE` during workflow runs
and used as a default for [repository checkouts](https://github.com/actions/checkout).
The service cleans this directory on every service start.
A value of `null` will default to the systemd `RuntimeDirectory`.
'';
default = null;
};
} }

View File

@@ -20,6 +20,9 @@
with lib; with lib;
let
workDir = if cfg.workDir == null then runtimeDir else cfg.workDir;
in
{ {
description = "GitHub Actions runner"; description = "GitHub Actions runner";
@@ -28,7 +31,7 @@ with lib;
after = [ "network.target" "network-online.target" ]; after = [ "network.target" "network-online.target" ];
environment = { environment = {
HOME = runtimeDir; HOME = workDir;
RUNNER_ROOT = stateDir; RUNNER_ROOT = stateDir;
} // cfg.extraEnvironment; } // cfg.extraEnvironment;
@@ -42,7 +45,7 @@ with lib;
config.nix.package config.nix.package
] ++ cfg.extraPackages; ] ++ cfg.extraPackages;
serviceConfig = rec { serviceConfig = {
ExecStart = "${cfg.package}/bin/Runner.Listener run --startuptype service"; ExecStart = "${cfg.package}/bin/Runner.Listener run --startuptype service";
# Does the following, sequentially: # Does the following, sequentially:
@@ -54,7 +57,7 @@ with lib;
# - Set up the directory structure by creating the necessary symlinks. # - Set up the directory structure by creating the necessary symlinks.
ExecStartPre = ExecStartPre =
let let
# Wrapper script which expects the full path of the state, runtime and logs # Wrapper script which expects the full path of the state, working and logs
# directory as arguments. Overrides the respective systemd variables to provide # directory as arguments. Overrides the respective systemd variables to provide
# unambiguous directory names. This becomes relevant, for example, if the # unambiguous directory names. This becomes relevant, for example, if the
# caller overrides any of the StateDirectory=, RuntimeDirectory= or LogDirectory= # caller overrides any of the StateDirectory=, RuntimeDirectory= or LogDirectory=
@@ -65,12 +68,12 @@ with lib;
set -euo pipefail set -euo pipefail
STATE_DIRECTORY="$1" STATE_DIRECTORY="$1"
RUNTIME_DIRECTORY="$2" WORK_DIRECTORY="$2"
LOGS_DIRECTORY="$3" LOGS_DIRECTORY="$3"
${lines} ${lines}
''; '';
runnerRegistrationConfig = getAttrs [ "name" "tokenFile" "url" "runnerGroup" "extraLabels" "ephemeral" ] cfg; runnerRegistrationConfig = getAttrs [ "name" "tokenFile" "url" "runnerGroup" "extraLabels" "ephemeral" "workDir" ] cfg;
newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig); newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig);
currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json"; currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json";
newConfigTokenPath= "$STATE_DIRECTORY/.new-token"; newConfigTokenPath= "$STATE_DIRECTORY/.new-token";
@@ -119,14 +122,15 @@ with lib;
else else
# The state directory is entirely empty which indicates a first start # The state directory is entirely empty which indicates a first start
copy_tokens copy_tokens
fi ''; fi
'';
configureRunner = writeScript "configure" '' configureRunner = writeScript "configure" ''
if [[ -e "${newConfigTokenPath}" ]]; then if [[ -e "${newConfigTokenPath}" ]]; then
echo "Configuring GitHub Actions Runner" echo "Configuring GitHub Actions Runner"
args=( args=(
--unattended --unattended
--disableupdate --disableupdate
--work "$RUNTIME_DIRECTORY" --work "$WORK_DIRECTORY"
--url ${escapeShellArg cfg.url} --url ${escapeShellArg cfg.url}
--labels ${escapeShellArg (concatStringsSep "," cfg.extraLabels)} --labels ${escapeShellArg (concatStringsSep "," cfg.extraLabels)}
--name ${escapeShellArg cfg.name} --name ${escapeShellArg cfg.name}
@@ -153,18 +157,21 @@ with lib;
ln -s '${newConfigPath}' "${currentConfigPath}" ln -s '${newConfigPath}' "${currentConfigPath}"
fi fi
''; '';
setupRuntimeDir = writeScript "setup-runtime-dirs" '' setupWorkDir = writeScript "setup-work-dirs" ''
# Link _diag dir # Cleanup previous service
ln -s "$LOGS_DIRECTORY" "$RUNTIME_DIRECTORY/_diag" ${pkgs.findutils}/bin/find -H "$WORK_DIRECTORY" -mindepth 1 -delete
# Link the runner credentials to the runtime dir # Link _diag dir
ln -s "$STATE_DIRECTORY"/{${lib.concatStringsSep "," runnerCredFiles}} "$RUNTIME_DIRECTORY/" ln -s "$LOGS_DIRECTORY" "$WORK_DIRECTORY/_diag"
# Link the runner credentials to the work dir
ln -s "$STATE_DIRECTORY"/{${lib.concatStringsSep "," runnerCredFiles}} "$WORK_DIRECTORY/"
''; '';
in in
map (x: "${x} ${escapeShellArgs [ stateDir runtimeDir logsDir ]}") [ map (x: "${x} ${escapeShellArgs [ stateDir workDir logsDir ]}") [
"+${unconfigureRunner}" # runs as root "+${unconfigureRunner}" # runs as root
configureRunner configureRunner
setupRuntimeDir setupWorkDir
]; ];
# If running in ephemeral mode, restart the service on-exit (i.e., successful de-registration of the runner) # If running in ephemeral mode, restart the service on-exit (i.e., successful de-registration of the runner)
@@ -181,7 +188,7 @@ with lib;
# Home of persistent runner data, e.g., credentials # Home of persistent runner data, e.g., credentials
StateDirectory = [ systemdDir ]; StateDirectory = [ systemdDir ];
StateDirectoryMode = "0700"; StateDirectoryMode = "0700";
WorkingDirectory = runtimeDir; WorkingDirectory = workDir;
InaccessiblePaths = [ InaccessiblePaths = [
# Token file path given in the configuration, if visible to the service # Token file path given in the configuration, if visible to the service
@@ -232,6 +239,8 @@ with lib;
]; ];
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" "AF_NETLINK" ]; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" "AF_NETLINK" ];
BindPaths = lib.optionals (cfg.workDir != null) [ cfg.workDir ];
# Needs network access # Needs network access
PrivateNetwork = false; PrivateNetwork = false;
# Cannot be true due to Node # Cannot be true due to Node