remove the hive's local build of agent closures
A rebuild or create downloads the closure the swarm built and applies it; with none to deploy it fails and changes nothing. hive-priv takes a store path instead of an internal/meta commit and builds nothing.
This commit is contained in:
parent
70538fb209
commit
4590b04cac
5 changed files with 632 additions and 1351 deletions
|
|
@ -41,13 +41,12 @@ let
|
|||
};
|
||||
|
||||
# Privsep splits ownership across users, so git/libgit2's dubious-
|
||||
# ownership guard trips on legitimate cross-user reads: hive-priv (root)
|
||||
# fetches the hive-core-owned meta/applied repos via nix, and hive-c0re
|
||||
# (hive-core) fetches the agent-owned proposed-config repos. Both
|
||||
# processes are trusted and can already read the files; this gitconfig
|
||||
# only satisfies the ownership guard. libgit2 honours the literal `*`
|
||||
# (mid-path globs aren't supported, so per-agent repos can't be listed);
|
||||
# in practice these processes only ever touch hyperhive's own repos.
|
||||
# ownership guard trips on legitimate cross-user reads: hive-c0re
|
||||
# (hive-core) fetches the agent-owned proposed-config repos. The process is
|
||||
# trusted and can already read the files; this gitconfig only satisfies the
|
||||
# ownership guard. libgit2 honours the literal `*` (mid-path globs aren't
|
||||
# supported, so per-agent repos can't be listed); in practice this process
|
||||
# only ever touches hyperhive's own repos.
|
||||
#
|
||||
# The forge sections (`forgeGit.config`) answer for the `git+http` forge
|
||||
# fetches nix makes: the agent config inputs and `internal/meta`. hive-c0re's
|
||||
|
|
|
|||
|
|
@ -41,11 +41,9 @@ let
|
|||
);
|
||||
in
|
||||
{
|
||||
# nix (the prebuild `nix build`, flake-check, and meta eval) writes
|
||||
# its fetcher/eval cache under $HOME/.cache. As a system user
|
||||
# git writes its config and caches under $HOME. As a system user
|
||||
# hive-core has no home, so HOME defaults to the unwritable
|
||||
# /var/empty and Lix fails to initialise its cache. Point HOME at
|
||||
# the writable StateDirectory.
|
||||
# /var/empty. Point HOME at the writable StateDirectory.
|
||||
HOME = "/var/lib/hyperhive";
|
||||
HYPERHIVE_GIT = "${pkgs.git}/bin/git";
|
||||
# Never let git block on an interactive credential prompt. hive-core is a
|
||||
|
|
|
|||
|
|
@ -290,11 +290,11 @@
|
|||
default = 1;
|
||||
example = 2;
|
||||
description = ''
|
||||
Number of nix-heavy job-queue nodes (container prebuilds,
|
||||
Number of closure-fetching job-queue nodes (container prebuilds,
|
||||
profile swaps, first-spawn creates, meta lock bumps) hive-c0re
|
||||
runs concurrently. The default of 1 serializes all heavy nix
|
||||
work; raise it on hosts with the cores/RAM to build several
|
||||
agent toplevels at once. Per-agent correctness is independent
|
||||
runs concurrently. The default of 1 serializes all of them;
|
||||
raise it on hosts with the bandwidth and disk to take several
|
||||
agents at once. Per-agent correctness is independent
|
||||
of this count — each agent's container-affecting operations are
|
||||
serialized by its lifecycle lease regardless.
|
||||
'';
|
||||
|
|
|
|||
|
|
@ -9,22 +9,6 @@
|
|||
}:
|
||||
let
|
||||
controllerCfg = config.services.hyperhive.deploy.hive-controller;
|
||||
|
||||
forgeGit = import ./lib/hive-forge-git.nix {
|
||||
inherit pkgs;
|
||||
forgeDomain = config.services.hyperhive.swarm.forge.domain;
|
||||
};
|
||||
|
||||
# Same gitconfig as the c0re unit (see ./hive-c0re) apart from its stalled-
|
||||
# transfer limit: hive-priv (root) runs nix, which fetches the hive-core-owned
|
||||
# meta/applied repos (libgit2 refuses cross-user reads without
|
||||
# safe.directory) and, from a fresh HOME, the forge inputs of `internal/meta`
|
||||
# (the forge sections).
|
||||
safeDirGitconfig = pkgs.writeText "hyperhive-safe-gitconfig" ''
|
||||
[safe]
|
||||
directory = *
|
||||
${forgeGit.config}
|
||||
'';
|
||||
in
|
||||
{
|
||||
config = lib.mkIf config.services.hyperhive.deploy.hive-controller.enable {
|
||||
|
|
@ -77,41 +61,25 @@ in
|
|||
# findutils already in the default unit PATH. Without `nixos-container`
|
||||
# on PATH every container op fails ENOENT, which `build_all` silently
|
||||
# swallows into an empty list ("no managed containers").
|
||||
#
|
||||
# `nix` itself shells out by bare name too: `git` whenever it has to
|
||||
# fetch/re-resolve a git-source flake input (an agent.nix with a
|
||||
# `git+https://…` input, or a stale flake.lock whose node URL no longer
|
||||
# matches the flake's declared input → nix re-resolves at eval), and
|
||||
# `ssh` to dispatch to remote builders (`nix.buildMachines` /
|
||||
# `ssh-ng://`). Without these on PATH `nixos-container update` dies with
|
||||
# `executing "git": No such file or directory` / `Could not find
|
||||
# executable 'ssh'` — the agent build fails before it starts.
|
||||
path = [
|
||||
pkgs.nixos-container
|
||||
pkgs.nix # nix, nix-env, nix-instantiate — create + update
|
||||
pkgs.gitMinimal # git — nix fetches/re-resolves git-source flake inputs
|
||||
forgeGit.credentialHelper # git-credential-hive-forge — the forge's `git+http` inputs
|
||||
pkgs.openssh # ssh — nix dispatches builds to remote builders
|
||||
pkgs.util-linux # umount (nsenter is hardcoded in the script)
|
||||
pkgs.e2fsprogs # chattr
|
||||
pkgs.btrfs-progs # btrfs subvolume create/delete — Ensure/DeleteAgentSubvolume
|
||||
];
|
||||
environment = {
|
||||
# `nixos-container update/create` runs `nix`, which writes its
|
||||
# fetcher/eval cache under $HOME/.cache. With ProtectHome and no
|
||||
# explicit HOME this lands on the unwritable /var/empty and Lix
|
||||
# errors out. Point HOME at the StateDirectory below (persistent,
|
||||
# so the cache survives across rebuilds).
|
||||
# nix (`nix-env`, `nix-store`) writes its cache under $HOME/.cache.
|
||||
# With ProtectHome and no explicit HOME this lands on the unwritable
|
||||
# /var/empty and Lix errors out. Point HOME at the StateDirectory
|
||||
# below (persistent, so the cache survives across restarts).
|
||||
HOME = "/var/lib/hive-priv";
|
||||
# hive-priv runs as root. Root nix defaults to store=auto which
|
||||
# resolves to the LOCAL store — bypassing the host daemon, its
|
||||
# remote builders, and prebuilt derivation outputs. Force daemon
|
||||
# routing so nixos-container update and the nix prebuild see the
|
||||
# same store and substituters as every other build context.
|
||||
# routing so the closure `RealiseClosure` downloads is in the same
|
||||
# store the container is then pointed at.
|
||||
NIX_REMOTE = "daemon";
|
||||
# The forge origin `internal/meta` is built from when a request names
|
||||
# one of its commits. Fixed here; no request chooses it.
|
||||
HIVE_PRIV_FORGE_URL = "http://${config.services.hyperhive.swarm.forge.domain}";
|
||||
};
|
||||
serviceConfig = {
|
||||
ExecStart = "${controllerCfg.package}/bin/hive-priv";
|
||||
|
|
@ -159,11 +127,6 @@ in
|
|||
# Point the working directory at the writable StateDirectory so nix
|
||||
# drops its temp symlink there instead.
|
||||
WorkingDirectory = "/var/lib/hive-priv";
|
||||
# nix (run here as root for `nixos-container update --flake
|
||||
# /var/lib/hyperhive/meta#<agent>`) fetches the hive-core-owned
|
||||
# meta/applied repos; libgit2 refuses them without safe.directory.
|
||||
# See safeDirGitconfig above.
|
||||
ExecStartPre = "+-${pkgs.coreutils}/bin/cp ${safeDirGitconfig} /var/lib/hive-priv/.gitconfig";
|
||||
# Kernel surfaces neither hive-priv nor its children use: no
|
||||
# personality(2), no real-time scheduling, no /dev/kmsg or
|
||||
# /proc/kmsg, no explicit module loading (kernel-initiated autoload
|
||||
|
|
|
|||
|
|
@ -234,13 +234,12 @@ let
|
|||
&& env shared.controllerAlone == { };
|
||||
}
|
||||
{
|
||||
# nix fetches the forge inputs with `git`, so the credential helper and
|
||||
# the https-to-http rewrite are git config in both processes that build:
|
||||
# hive-c0re (prebuilds) and hive-priv (builds as root, from its own
|
||||
# HOME). The controller's unit is the control that the lookup tells a
|
||||
# unit with the helper from one without; the URL hive-priv builds
|
||||
# `internal/meta` from is the one hive-c0re reads the forge at.
|
||||
name = "hive-c0re and hive-priv answer the forge's git fetches and rewrite its https inputs to http";
|
||||
# hive-c0re carries the credential helper and the https-to-http rewrite as
|
||||
# git config. hive-priv builds nothing and fetches nothing from the forge,
|
||||
# so it carries neither and has no forge URL. The hive-c0re arm is the
|
||||
# control that the lookups find a helper and a forge URL where there is
|
||||
# one, so the absences on hive-priv and the controller are real.
|
||||
name = "hive-c0re answers the forge's git fetches and rewrites its https inputs to http; hive-priv has neither";
|
||||
ok =
|
||||
let
|
||||
forge = allLocal.services.hyperhive.swarm.forge.domain;
|
||||
|
|
@ -256,7 +255,7 @@ let
|
|||
env = unit: allLocal.systemd.services.${unit}.environment;
|
||||
in
|
||||
helperOn "hive-c0re"
|
||||
&& helperOn "hive-priv"
|
||||
&& !(helperOn "hive-priv")
|
||||
# The helper answers from the file hive-c0re publishes the hive's own
|
||||
# token to. The first arm is the control for the second: the lookup
|
||||
# finds the helper's text, so the absent `core` strings are really absent.
|
||||
|
|
@ -267,8 +266,8 @@ let
|
|||
&& !(helperOn "swarm-controller")
|
||||
&& lib.hasInfix "[credential \"http://${forge}\"]\nhelper =\nhelper = hive-forge" git.config
|
||||
&& lib.hasInfix "[url \"http://${forge}/\"]\ninsteadOf = https://${forge}/" git.config
|
||||
&& (env "hive-priv").HIVE_PRIV_FORGE_URL == "http://${forge}"
|
||||
&& (env "hive-priv").HIVE_PRIV_FORGE_URL == (env "hive-c0re").HIVE_FORGE_URL;
|
||||
&& (env "hive-c0re") ? HIVE_FORGE_URL
|
||||
&& !((env "hive-priv") ? HIVE_PRIV_FORGE_URL);
|
||||
}
|
||||
{
|
||||
# `hyperhive_rev` defaults to none on the controller, so a settings JSON
|
||||
|
|
|
|||
Loading…
Reference in a new issue