Watch
0
0
Fork
You've already forked hyperhive
0

vm tests: fail on a missing log port, give up early on a broken hive

This commit is contained in:
atlas 2026-11-13 07:39:08 +01:00 • committed by mara
commit df02ff89aa
2 changed files with 36 additions and 4 deletions

View file

@ -843,7 +843,9 @@ pkgs.testers.runNixOSTest {
unmetered = [line for line in lines if "hive-egress-would-drop-unmetered IN=" in line] unmetered = [line for line in lines if "hive-egress-would-drop-unmetered IN=" in line]
assert 1 <= len(metered) <= 30, f"100 new flows: {len(metered)} per-source lines" assert 1 <= len(metered) <= 30, f"100 new flows: {len(metered)} per-source lines"
assert 1 <= len(unmetered) <= 80, f"100 new flows: {len(unmetered)} unmetered lines" assert 1 <= len(unmetered) <= 80, f"100 new flows: {len(unmetered)} unmetered lines"
ports = [re.search(r"DPT=(\d+) ", line).group(1) for line in lines] dpts = [re.search(r"DPT=(\d+) ", line) for line in lines]
assert all(dpts), f"a logged line has no destination port: {lines}"
ports = [found.group(1) for found in dpts if found]
assert len(ports) == len(set(ports)), "a flow was logged twice" assert len(ports) == len(set(ports)), "a flow was logged twice"
out = proxy.succeed("nft list chain inet hive_egress forward") out = proxy.succeed("nft list chain inet hive_egress forward")
found = re.search(r'oifname != "eth1" counter packets (\d+) bytes \d+$', out, re.M) found = re.search(r'oifname != "eth1" counter packets (\d+) bytes \d+$', out, re.M)

View file

@ -304,6 +304,7 @@ pkgs.testers.runNixOSTest (
testScript = '' testScript = ''
import json import json
import shlex import shlex
import time
API = "http://localhost" API = "http://localhost"
SOCKET = "${controllerSocket}" SOCKET = "${controllerSocket}"
@ -354,6 +355,37 @@ pkgs.testers.runNixOSTest (
diagnose(m, unit, container) diagnose(m, unit, container)
raise raise
HIVE_UNITS = ["hive-priv.socket", "hive-priv.service", "hive-c0re"]
def hive_fault():
# Why the hive cannot reach the state the swarm waits for, or None. The
# privileged helper is socket-activated: its socket is active while it
# is usable, and failed once the helper's start limit is hit. The status
# sweep runs every minute and fails once or twice while the swarm queue
# comes up, so only three failures within three minutes count.
if hive.execute("systemctl is-active --quiet hive-priv.socket && ! systemctl is-failed --quiet hive-priv.service")[0] != 0:
return "hive-priv is not up on the hive"
swept = hive.succeed("journalctl -u hive-c0re --since '3 min ago' --no-pager -o cat | grep -c 'agent status: sweep failed' || true").strip()
if int(swept) >= 3:
return f"hive-c0re's agent-status sweep failed {swept} times in the last 3 minutes"
return None
def settle_hive_agents(command, timeout):
# settle on the swarm machine, but give up as soon as the hive is broken
# and dump both machines.
deadline = time.monotonic() + timeout
fault = None
while time.monotonic() < deadline:
if swarm.execute(command)[0] == 0:
return
fault = hive_fault()
if fault:
break
time.sleep(10)
diagnose(hive, HIVE_UNITS)
diagnose(swarm, ["swarm-controller"])
raise Exception(fault or f"the agents did not settle within {timeout}s")
def store_sealed(timeout): def store_sealed(timeout):
# `bao status` exits 2 when it reaches a sealed store and 1 for any # `bao status` exits 2 when it reaches a sealed store and 1 for any
# address, CA or client-certificate problem. # address, CA or client-certificate problem.
@ -627,13 +659,11 @@ pkgs.testers.runNixOSTest (
create_agent({"name": "iris", "hive": HIVE, "archetype": ARCHETYPE}) create_agent({"name": "iris", "hive": HIVE, "archetype": ARCHETYPE})
with subtest("assert 4: the agents are deployed on the hive, from the cache on heavyduty, and need a login"): with subtest("assert 4: the agents are deployed on the hive, from the cache on heavyduty, and need a login"):
settle( settle_hive_agents(
swarm,
f"curl --fail --silent --unix-socket {SOCKET} {API}/api/agents/status " f"curl --fail --silent --unix-socket {SOCKET} {API}/api/agents/status "
"| jq -e '[.[] | select(.hive == \"" + HIVE + "\" and .freshness == \"fresh\" and .needs_login == true)" "| jq -e '[.[] | select(.hive == \"" + HIVE + "\" and .freshness == \"fresh\" and .needs_login == true)"
" | .name] | map(select(. == \"iris\" or . == \"spawn\")) | unique | length == 2'", " | .name] | map(select(. == \"iris\" or . == \"spawn\")) | unique | length == 2'",
3600, 3600,
["swarm-controller"],
) )
# The closures came over the VPN from the cache: the hive's nix # The closures came over the VPN from the cache: the hive's nix
# names it as its only extra substituter and holds the toplevels now. # names it as its only extra substituter and holds the toplevels now.