Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/gitea-actions-runner: init #228422

Merged
merged 1 commit into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2305.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ In addition to numerous new and upgraded packages, this release has the followin

- [gemstash](https://github.com/rubygems/gemstash), a RubyGems.org cache and private gem server. Available as [services.gemstash](#opt-services.gemstash.enable).

- [gitea-actions-runner](https://gitea.com/gitea/act_runner), a CI runner for Gitea/Forgejo Actions. Available as [services.gitea-actions-runner](#opt-services.gitea-actions-runner.instances).

- [gmediarender](https://github.com/hzeller/gmrender-resurrect), a simple, headless UPnP/DLNA renderer. Available as [services.gmediarender](options.html#opt-services.gmediarender.enable).

- [hyprland](https://github.com/hyprwm/hyprland), a dynamic tiling Wayland compositor that doesn't sacrifice on its looks. Available as [programs.hyprland](#opt-programs.hyprland.enable).
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@
./services/continuous-integration/buildbot/master.nix
./services/continuous-integration/buildbot/worker.nix
./services/continuous-integration/buildkite-agents.nix
./services/continuous-integration/gitea-actions-runner.nix
./services/continuous-integration/github-runner.nix
./services/continuous-integration/github-runners.nix
./services/continuous-integration/gitlab-runner.nix
Expand Down
237 changes: 237 additions & 0 deletions nixos/modules/services/continuous-integration/gitea-actions-runner.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
{ config
, lib
, pkgs
, utils
, ...
}:

let
inherit (lib)
any
attrValues
concatStringsSep
escapeShellArg
hasInfix
hasSuffix
optionalAttrs
optionals
literalExpression
mapAttrs'
mkEnableOption
mkOption
mkPackageOptionMD
mkIf
nameValuePair
types
;

inherit (utils)
escapeSystemdPath
;

cfg = config.services.gitea-actions-runner;

# Check whether any runner instance label requires a container runtime
# Empty label strings result in the upstream defined defaultLabels, which require docker
# https://gitea.com/gitea/act_runner/src/tag/v0.1.5/internal/app/cmd/register.go#L93-L98
hasDockerScheme = instance:
instance.labels == [] || any (label: hasInfix ":docker:" label) instance.labels;
wantsContainerRuntime = any hasDockerScheme (attrValues cfg.instances);

hasHostScheme = instance: any (label: hasSuffix ":host" label) instance.labels;

# provide shorthands for whether container runtimes are enabled
hasDocker = config.virtualisation.docker.enable;
hasPodman = config.virtualisation.podman.enable;

tokenXorTokenFile = instance:
(instance.token == null && instance.tokenFile != null) ||
(instance.token != null && instance.tokenFile == null);
in
{
meta.maintainers = with lib.maintainers; [
hexa
];

options.services.gitea-actions-runner = with types; {
package = mkPackageOptionMD pkgs "gitea-actions-runner" { };

instances = mkOption {
default = {};
description = lib.mdDoc ''
Gitea Actions Runner instances.
'';
type = attrsOf (submodule {
options = {
enable = mkEnableOption (lib.mdDoc "Gitea Actions Runner instance");

name = mkOption {
type = str;
example = literalExpression "config.networking.hostName";
description = lib.mdDoc ''
The name identifying the runner instance towards the Gitea/Forgejo instance.
'';
};

url = mkOption {
type = str;
example = "https://forge.example.com";
mweinelt marked this conversation as resolved.
Show resolved Hide resolved
description = lib.mdDoc ''
Base URL of your Gitea/Forgejo instance.
'';
};

token = mkOption {
type = nullOr str;
default = null;
description = lib.mdDoc ''
Plain token to register at the configured Gitea/Forgejo instance.
'';
};
mweinelt marked this conversation as resolved.
Show resolved Hide resolved

tokenFile = mkOption {
type = nullOr (either str path);
default = null;
description = lib.mdDoc ''
Path to an environment file, containing the `TOKEN` environment
variable, that holds a token to register at the configured
Gitea/Forgejo instance.
'';
};

labels = mkOption {
type = listOf str;
example = literalExpression ''
[
# provide a debian base with nodejs for actions
"debian-latest:docker://node:18-bullseye"
# fake the ubuntu name, because node provides no ubuntu builds
"ubuntu-latest:docker://node:18-bullseye"
# provide native execution on the host
#"native:host"
]
'';
description = lib.mdDoc ''
Labels used to map jobs to their runtime environment. Changing these
labels currently requires a new registration token.

Many common actions require bash, git and nodejs, as well as a filesystem
that follows the filesystem hierarchy standard.
'';
};

hostPackages = mkOption {
type = listOf package;
default = with pkgs; [
bash
coreutils
curl
gawk
gitMinimal
gnused
nodejs
wget
];
defaultText = literalExpression ''
with pkgs; [
bash
coreutils
curl
gawk
gitMinimal
gnused
nodejs
wget
]
'';
description = lib.mdDoc ''
List of packages, that are available to actions, when the runner is configured
with a host execution label.
'';
};
};
});
};
};

config = mkIf (cfg.instances != {}) {
assertions = [ {
assertion = any tokenXorTokenFile (attrValues cfg.instances);
message = "Instances of gitea-actions-runner can have `token` or `tokenFile`, not both.";
} {
assertion = wantsContainerRuntime -> hasDocker || hasPodman;
message = "Label configuration on gitea-actions-runner instance requires either docker or podman.";
} ];

systemd.services = let
mkRunnerService = name: instance: let
wantsContainerRuntime = hasDockerScheme instance;
wantsHost = hasHostScheme instance;
wantsDocker = wantsContainerRuntime && config.virtualisation.docker.enable;
wantsPodman = wantsContainerRuntime && config.virtualisation.podman.enable;
in
nameValuePair "gitea-runner-${escapeSystemdPath name}" {
inherit (instance) enable;
description = "Gitea Actions Runner";
after = [
mweinelt marked this conversation as resolved.
Show resolved Hide resolved
"network-online.target"
] ++ optionals (wantsDocker) [
"docker.service"
] ++ optionals (wantsPodman) [
"podman.service"
];
wantedBy = [
"multi-user.target"
];
environment = optionalAttrs (instance.token != null) {
TOKEN = "${instance.token}";
} // optionalAttrs (wantsPodman) {
DOCKER_HOST = "unix:///run/podman/podman.sock";
};
path = with pkgs; [
coreutils
] ++ lib.optionals wantsHost instance.hostPackages;
serviceConfig = {
DynamicUser = true;
User = "gitea-runner";
StateDirectory = "gitea-runner";
WorkingDirectory = "-/var/lib/gitea-runner/${name}";
ExecStartPre = pkgs.writeShellScript "gitea-register-runner-${name}" ''
export INSTANCE_DIR="$STATE_DIRECTORY/${name}"
mkdir -vp "$INSTANCE_DIR"
cd "$INSTANCE_DIR"

# force reregistration on changed labels
export LABELS_FILE="$INSTANCE_DIR/.labels"
export LABELS_WANTED="$(echo ${escapeShellArg (concatStringsSep "\n" instance.labels)} | sort)"
export LABELS_CURRENT="$(cat $LABELS_FILE 2>/dev/null || echo 0)"

if [ ! -e "$INSTANCE_DIR/.runner" ] || [ "$LABELS_WANTED" != "$LABELS_CURRENT" ]; then
# remove existing registration file, so that changing the labels forces a re-registation
rm -v "$INSTANCE_DIR/.runner" || true

# perform the registration
${cfg.package}/bin/act_runner register --no-interactive \
--instance ${escapeShellArg instance.url} \
--token "$TOKEN" \
--name ${escapeShellArg instance.name} \
--labels ${escapeShellArg (concatStringsSep "," instance.labels)}

# and write back the configured labels
echo "$LABELS_WANTED" > "$LABELS_FILE"
fi

'';
ExecStart = "${cfg.package}/bin/act_runner daemon";
SupplementaryGroups = optionals (wantsDocker) [
"docker"
] ++ optionals (wantsPodman) [
"podman"
];
} // optionalAttrs (instance.tokenFile != null) {
EnvironmentFile = instance.tokenFile;
};
};
in mapAttrs' mkRunnerService cfg.instances;
};
}