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
83 lines
4 KiB
Nix
83 lines
4 KiB
Nix
# Hive-internal DNS resolver + DHCP, running on the host alongside the
|
|
# gateway's nginx — single front-door for both DNS and HTTP, and no
|
|
# container of its own. Listens on the bridge interface from
|
|
# `services.hyperhive.network`; authoritative for the hive domain +
|
|
# sub-domains, forwards everything else upstream. Returns the
|
|
# `services.dnsmasq` value (see ./default.nix); the DHCP pool bounds
|
|
# are computed by hive-network.
|
|
{
|
|
lib,
|
|
cfg, # services.hyperhive.gateway
|
|
networkCfg,
|
|
hyperhiveDomain,
|
|
}:
|
|
{
|
|
enable = true;
|
|
# ON for its *plumbing*, not for the address it publishes.
|
|
#
|
|
# This flag does two separable things upstream. The one that matters
|
|
# here: it points dnsmasq's own upstream servers at a SEPARATE file
|
|
# (`resolv-file = /etc/dnsmasq-resolv.conf`, kept current by
|
|
# resolvconf). Without that, dnsmasq reads `/etc/resolv.conf` for its
|
|
# upstreams — so the moment the host's resolver is pointed at dnsmasq,
|
|
# every non-hive query goes in a circle.
|
|
#
|
|
# The other thing it does is publish `127.0.0.1` as the host's
|
|
# nameserver, which is the wrong address for this hive: see the
|
|
# `nameservers` override in ./default.nix, where the reason lives.
|
|
resolveLocalQueries = true;
|
|
settings = {
|
|
# Bind only on the bridge interface (and lo for health-checks).
|
|
# Outside hosts can't even see the listener.
|
|
interface = [
|
|
networkCfg.bridgeName
|
|
"lo"
|
|
];
|
|
bind-interfaces = true;
|
|
port = 53;
|
|
# Authoritative for the hive domain via the `address` rules below —
|
|
# must not fall back to the host's /etc/hosts. dnsmasq reads
|
|
# /etc/hosts by default, and `gateway.localHostsEntry` populates it
|
|
# with 127.0.0.1 for every hive name (host-side dev convenience,
|
|
# see default.nix). Since moving dnsmasq onto the host, that
|
|
# file is now the *same* /etc/hosts dnsmasq reads for agent queries
|
|
# — its entries win over `address=`, so every agent resolves the
|
|
# hive's own domains back to itself (127.0.0.1 in its own netns)
|
|
# instead of the bridge IP, and can't reach the forge, matrix, or
|
|
# dashboard at all. `no-hosts = true` keeps the authoritative
|
|
# `address=` rules in charge for containers while leaving
|
|
# `networking.hosts` (the actual /etc/hosts entries) untouched for
|
|
# host-side browsing.
|
|
no-hosts = true;
|
|
# Hive authoritative records — answer queries for the hive domain
|
|
# + its sub-domains with the bridge IP, where nginx is reachable
|
|
# from every container netns.
|
|
address = [
|
|
"/${hyperhiveDomain}/${networkCfg.bridgeIp}"
|
|
]
|
|
# Names contributed by the modules that own them
|
|
# (`gateway.localNames`). Same address as everything above — the
|
|
# bridge IP is the gateway's answer for anything it fronts, and a
|
|
# contributing module neither knows nor should know it.
|
|
#
|
|
# `unique` is not tidiness: two modules claiming one name would
|
|
# otherwise emit two `address=` rules for it, and dnsmasq resolves
|
|
# that by precedence rather than by complaining. An assertion in
|
|
# ./default.nix makes the collision loud instead.
|
|
++ map (name: "/${name}/${networkCfg.bridgeIp}") (lib.unique cfg.localNames);
|
|
# DHCP pool covering all usable host addresses on the bridge
|
|
# subnet — bounds computed by hive-network.nix from
|
|
# bridgeIp/bridgePrefixLength. All containers (agents and service
|
|
# containers such as swarm-ci-runner) receive their IPs dynamically.
|
|
dhcp-range = "${networkCfg.dhcpRangeStart},${networkCfg.dhcpRangeEnd},1h";
|
|
dhcp-leasefile = "/var/lib/dnsmasq/dnsmasq.leases";
|
|
# No explicit upstream: non-hive queries follow dnsmasq's
|
|
# resolv.conf default — the host's own `/etc/resolv.conf`, so the
|
|
# hive always uses the host's resolvers and follows them live with
|
|
# no copy to go stale. Deliberately no fallback
|
|
# `server=`: dnsmasq queries
|
|
# all known upstreams in parallel, so a hardcoded public resolver
|
|
# would take a share of *normal* traffic, not just fill in when the
|
|
# host file is empty.
|
|
};
|
|
}
|