swarm-ci-runner: run the forge CI runner as a swarm service
The CI runner was a hive deploy module: hive-ci.nix ran it beside the forge, and hive-c0re registered it through the forge's admin API with the `core` token, writing the registration token through hive-priv. It could only run on the forge's host, and it kept an admin-scoped forge token on a hive. Now the runner is a swarm service: - swarm-ci-runner.nix runs it in a `swarm-ci-runner` container on the host that sets deploy.ci-runner.enable, reaching the forge by name. It needs neither the forge nor a hive there. - swarm-controller reads the forge's runner registration token with its own admin token and writes it to swarm/services/ci-runner/ registration-token whenever it differs from what it last wrote. Its grant on that path is create/update only. - The runner's own leaf (CN swarm-ci-runner, role and policy of the same name) reads that one path. swarm-bao-ci-runner.service fetches it into the runner's EnvironmentFile and restarts the runner on a change. - A pre-start step removes .runner when the daemon's journal since its last start holds Forgejo's "unregistered runner" refusal (the daemon exits 1 when its startup Declare gets it), or when .runner names another forge address; upstream's pre-start step then registers again. Removed from the hive side: hive-ci.nix and deploy.forgejo.ci.*, forge/ci_runner.rs, PrivRequest::RegisterCiRunner and its handler and ReadWritePaths entry, InfraContainer::Ci with hivectl's --ci and the dashboard's hive-ci journal entry, HYPERHIVE_FORGE_CI_ENABLED, and read:admin,write:admin from CORE_TOKEN_SCOPES: nothing else in hive-c0re calls /api/v1/admin/*. The old ci options, under both swarm.forge.ci and deploy.forgejo.ci, now fail evaluation naming deploy.ci-runner. The forge's half of the old ci.enable, the actions/checkout mirror and DEFAULT_ACTIONS_URL = self, is deploy.forgejo.actionsFromSelf. Closes #4954
This commit is contained in:
parent
3d43e9588c
commit
e2da5509ae
60 changed files with 1088 additions and 1201 deletions
|
|
@ -20,9 +20,9 @@
|
|||
#
|
||||
# ⚠️ Each entry is an attrset with an `enable`, not a bare bool, so a
|
||||
# service that grows a second *deployment* decision has somewhere to put
|
||||
# it — `deploy.forgejo = { enable; ci; }` is then an ordinary addition
|
||||
# rather than a migration. `ci` ("does this host run the runner too") is
|
||||
# exactly that shape, and a bare bool leaves it unrepresentable.
|
||||
# it — `deploy.nats = { enable; autoGenerateCallout; }` is then an ordinary
|
||||
# addition rather than a migration, where a bare bool leaves it
|
||||
# unrepresentable.
|
||||
#
|
||||
# ⚠️ The renames below are deliberately in this one file rather than
|
||||
# spread across the service modules, so all of them have a single home
|
||||
|
|
@ -31,6 +31,32 @@
|
|||
{ lib, config, ... }:
|
||||
let
|
||||
deployCfg = config.services.hyperhive.deploy;
|
||||
|
||||
# A removed CI-runner option. Its replacement has the same name under
|
||||
# `deploy.ci-runner`.
|
||||
ciRunnerRemoved =
|
||||
from: opt:
|
||||
lib.mkRemovedOptionModule
|
||||
(
|
||||
[
|
||||
"services"
|
||||
"hyperhive"
|
||||
]
|
||||
++ from
|
||||
++ [ opt ]
|
||||
)
|
||||
''
|
||||
The CI runner is the swarm service in swarm-ci-runner.nix. It runs on
|
||||
any host, needs neither the forge nor a hive there, and registers with
|
||||
the token swarm-controller publishes to the secret store. Set
|
||||
services.hyperhive.deploy.ci-runner.${opt} instead.
|
||||
|
||||
The runner registers as a new runner on the forge, so delete the old
|
||||
one in the forge's admin panel (Site administration, Actions, Runners).
|
||||
To keep resolving `uses: actions/checkout` from the forge, set
|
||||
services.hyperhive.deploy.forgejo.actionsFromSelf = true on its host.
|
||||
See docs/scheduler/ci.md.
|
||||
'';
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
|
|
@ -146,33 +172,20 @@ in
|
|||
[ "services" "hyperhive" "deploy" "swarm-otel" "clientSecretFile" ]
|
||||
)
|
||||
|
||||
# The CI runner, and the only entry here that renames more than an
|
||||
# `enable`: every knob under it describes the runner THIS host would run,
|
||||
# so leaving `name`/`concurrency`/`labels`/`package` in the namespace that
|
||||
# must be identical swarm-wide would keep the original defect for four
|
||||
# more options. Renamed one by one because `ci` is a plain attrset of
|
||||
# options rather than a submodule type, so there is no parent path to
|
||||
# rename in a single entry.
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "hyperhive" "swarm" "forge" "ci" "enable" ]
|
||||
[ "services" "hyperhive" "deploy" "forgejo" "ci" "enable" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "hyperhive" "swarm" "forge" "ci" "name" ]
|
||||
[ "services" "hyperhive" "deploy" "forgejo" "ci" "name" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "hyperhive" "swarm" "forge" "ci" "concurrency" ]
|
||||
[ "services" "hyperhive" "deploy" "forgejo" "ci" "concurrency" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "hyperhive" "swarm" "forge" "ci" "labels" ]
|
||||
[ "services" "hyperhive" "deploy" "forgejo" "ci" "labels" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "hyperhive" "swarm" "forge" "ci" "package" ]
|
||||
[ "services" "hyperhive" "deploy" "forgejo" "ci" "package" ]
|
||||
)
|
||||
# Removed rather than renamed: the runner is a different container with a
|
||||
# registration of its own, so an old definition is a deployment to re-read
|
||||
# rather than a path to forward.
|
||||
(ciRunnerRemoved [ "swarm" "forge" "ci" ] "enable")
|
||||
(ciRunnerRemoved [ "swarm" "forge" "ci" ] "name")
|
||||
(ciRunnerRemoved [ "swarm" "forge" "ci" ] "concurrency")
|
||||
(ciRunnerRemoved [ "swarm" "forge" "ci" ] "labels")
|
||||
(ciRunnerRemoved [ "swarm" "forge" "ci" ] "package")
|
||||
(ciRunnerRemoved [ "deploy" "forgejo" "ci" ] "enable")
|
||||
(ciRunnerRemoved [ "deploy" "forgejo" "ci" ] "name")
|
||||
(ciRunnerRemoved [ "deploy" "forgejo" "ci" ] "concurrency")
|
||||
(ciRunnerRemoved [ "deploy" "forgejo" "ci" ] "labels")
|
||||
(ciRunnerRemoved [ "deploy" "forgejo" "ci" ] "package")
|
||||
(ciRunnerRemoved [ "deploy" "forgejo" "ci" ] "jobTimeout")
|
||||
|
||||
# The queue's callout identity. What stays under `swarm.nats` is what the
|
||||
# queue IS to every hive — the ports it answers on and the client id it is
|
||||
|
|
@ -216,8 +229,7 @@ in
|
|||
#
|
||||
# `mirrors` renames in one entry rather than one per field: it is a single
|
||||
# option of a list-of-submodule type, so the rename carries its whole
|
||||
# value. The `ci` block above needs five because it is a plain attrset of
|
||||
# separate options, which is the case with no parent path to rename.
|
||||
# value.
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "hyperhive" "swarm" "forge" "openFirewall" ]
|
||||
[ "services" "hyperhive" "deploy" "forgejo" "openFirewall" ]
|
||||
|
|
@ -451,9 +463,8 @@ in
|
|||
];
|
||||
|
||||
# ⚠️ Only `deploy.forgejo.enable` is declared here. The rest of
|
||||
# `deploy.forgejo` is in ./hive-forge/default.nix and ./hive-ci.nix: the
|
||||
# knobs live with the module that reads them; this file stays the registry
|
||||
# of toggles.
|
||||
# `deploy.forgejo` is in ./hive-forge/default.nix: the knobs live with the
|
||||
# module that reads them; this file stays the registry of toggles.
|
||||
options.services.hyperhive.deploy = {
|
||||
forgejo.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
|
|
@ -602,6 +613,23 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
ci-runner.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Run the swarm's Forgejo Actions runner in a `swarm-ci-runner`
|
||||
container on this host. It reaches the forge at
|
||||
{option}`services.hyperhive.swarm.forge.domain` and registers with
|
||||
the token swarm-controller publishes to the secret store, so it
|
||||
needs neither the forge nor a hive on this host.
|
||||
|
||||
Not derived from
|
||||
{option}`services.hyperhive.deploy.allSwarmServices`: a runner
|
||||
executes pull-request code, so running one is a decision of its own.
|
||||
'';
|
||||
};
|
||||
|
||||
hive-controller.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
|
|
|
|||
Loading…
Reference in a new issue