add a per-agent nix builds mode, host or none, carried like privateUsers
This commit is contained in:
parent
b9484e62a0
commit
5485151ba6
1 changed files with 618 additions and 58 deletions
|
|
@ -16,15 +16,15 @@
|
|||
# - a link planted at `root` in the template refuses the next start through
|
||||
# the limits drop-in's `ExecStartPre=` check (whose build has a GC root),
|
||||
# leaves the link's target untouched, and the start goes through once the
|
||||
# link is gone.
|
||||
#
|
||||
# link is gone;
|
||||
# - an agent whose config sets `services.hyperhive.agent.user.privateUsers`
|
||||
# (hive-c0re sends the flag from the closure record; the test sends it)
|
||||
# starts in its own
|
||||
# user namespace with state it already had, owned by uid 1000 on disk: the
|
||||
# data moves once to `dataOwner`, the agent user reads and writes it as
|
||||
# itself, the other agent's conf (no flag sent) is untouched, and a second
|
||||
# `WriteNspawnFlags` moves nothing.
|
||||
# starts in its own user namespace with state it already had, owned by uid
|
||||
# 1000 on disk: the data moves once to `dataOwner`, the agent user reads and
|
||||
# writes it as itself, the other agent's conf (no flag sent) is untouched,
|
||||
# and a second `WriteNspawnFlags` moves nothing;
|
||||
# - an agent set to `services.hyperhive.agent.nixBuilds = "none"` has no
|
||||
# nix-daemon socket and cannot build; a request naming no mode keeps that.
|
||||
#
|
||||
# The agent's journal forwarder itself (an OTLP push to the hive's collector) is
|
||||
# not booted here; the module-eval suite covers its wiring.
|
||||
|
|
@ -277,6 +277,9 @@ pkgs.testers.runNixOSTest {
|
|||
assert host.succeed(f"cat {WORK}/kept.txt").strip() == "kept"
|
||||
as_agent("hello")
|
||||
as_agent("tree --version")
|
||||
# The default mode: the host daemon's socket is there and answers.
|
||||
assert "socket" in in_ct("ls /nix/var/nix/daemon-socket").split()
|
||||
as_agent(f"nix-store --store daemon -q --hash {HELLO}")
|
||||
|
||||
with subtest("the switch ran once"):
|
||||
salvages = [d for d in salvage_dirs() if d.startswith("salvaged-rootfs-")]
|
||||
|
|
@ -335,10 +338,14 @@ pkgs.testers.runNixOSTest {
|
|||
"binds": NS_BINDS,
|
||||
"isolation": {"bridge": "${bridge}", "gateway_ip": "${gateway}"},
|
||||
"private_users": True,
|
||||
"nix_builds": "none",
|
||||
}
|
||||
priv_request(host, write)
|
||||
ns_conf = host.succeed(f"cat /etc/nixos-containers/{NS}.conf")
|
||||
assert "PRIVATE_USERS=pick" in ns_conf, ns_conf
|
||||
assert "--tmpfs=/nix/var/nix/daemon-socket" in ns_conf, ns_conf
|
||||
# The other agent's conf has no such flag: the control for the line above.
|
||||
assert "daemon-socket" not in conf(), conf()
|
||||
assert "--private-users-ownership=map" in ns_conf, ns_conf
|
||||
# Every bind, the read-only config included, is mounted owneridmap.
|
||||
assert ns_conf.count(":owneridmap") == len(NS_BINDS), ns_conf
|
||||
|
|
@ -379,12 +386,27 @@ pkgs.testers.runNixOSTest {
|
|||
host.succeed("stat -c %u:%g ${nsSocketDir}/web.sock | grep -x ${dataOwner}:${dataOwner}")
|
||||
host.succeed(f"nixos-container run {NS} -- cat /proc/self/uid_map | grep -v ' 4294967295$'")
|
||||
|
||||
def no_daemon():
|
||||
# The start script's bind is under the tmpfs: no socket in the
|
||||
# directory, and a build cannot connect. The store path is still
|
||||
# readable, and the first agent's directory (checked above) has the
|
||||
# socket where this one has none.
|
||||
host.fail(f"nixos-container run {NS} -- test -S /nix/var/nix/daemon-socket/socket")
|
||||
assert as_ns("ls -A /nix/var/nix/daemon-socket") == ""
|
||||
host.fail(f"nixos-container run {NS} -- runuser -l {NS_AGENT} -c 'nix-store --store daemon -q --hash {HELLO}'")
|
||||
as_ns(f"test -r {HELLO}/bin/hello")
|
||||
no_daemon()
|
||||
|
||||
# The move runs once: a file a host process leaves owned by 1000 after it
|
||||
# is not chowned by the next request, and the agent restarts.
|
||||
host.succeed(f"nixos-container stop {NS}")
|
||||
host.succeed(f"echo late > {NS_DIR}/state/late.txt && chown 1000:1000 {NS_DIR}/state/late.txt")
|
||||
priv_request(host, write)
|
||||
# A request that names no nix-builds mode, as one with no readable
|
||||
# record is, keeps the choice the last write made.
|
||||
priv_request(host, {k: v for k, v in write.items() if k != "nix_builds"})
|
||||
host.succeed(f"stat -c %u:%g {NS_DIR}/state/late.txt | grep -x 1000:1000")
|
||||
assert "--tmpfs=/nix/var/nix/daemon-socket" in host.succeed(f"cat /etc/nixos-containers/{NS}.conf")
|
||||
boot_ns()
|
||||
no_daemon()
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue