fix(maintenance): a host that came back late stops reading as failed once it is back (#6105)
Docker02's Sunday job updated and rebooted, then failed only because portal_app was short of its replica past the 30-minute settle. Its maintenance_failed figure stayed 1, and the alert kept firing, until a later job succeeds. A job failed for not coming back into service is checked again each minute and reads 0 once the host is back; a failed or timed-out update still reads 1 until a job succeeds. Also: compose.deploy.yml's syslog comment still said devices are told apart by address under Swarm (stale since #6096). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -134,3 +134,45 @@ def test_hosts_go_one_at_a_time_and_a_failure_stops_the_run():
|
||||
assert flags[seed["hosts"]["b"].name] == 1.0 and flags[seed["hosts"]["a"].name] == 0.0
|
||||
|
||||
asyncio.run(_go())
|
||||
|
||||
|
||||
def test_a_host_that_came_back_late_reads_failed_only_until_it_is_back():
|
||||
"""#6105: a job whose update went through, failed only for not coming back
|
||||
into service within the limit, stops flagging the host once it is back."""
|
||||
app = _app()
|
||||
|
||||
async def _go():
|
||||
from sqlalchemy import text
|
||||
seed = await _seed(app)
|
||||
cadence, models = _ha("cadence"), _ha("models")
|
||||
async with app.db_sessionmaker() as s:
|
||||
async with s.begin():
|
||||
plan = await s.get(models.HostMaintenancePlan, seed["plan_id"])
|
||||
await cadence.start_run(s, plan, datetime.now(timezone.utc), manual=True)
|
||||
await _tick(app)
|
||||
ta, a = seed["tokens"]["a"], seed["hosts"]["a"]
|
||||
(step,) = await _post(app, ta)
|
||||
await _post(app, ta, [{"kind": "maintenance", "id": step["id"], "action": "update",
|
||||
"state": "done", "ok": True, "packages": 2, "reboot_required": False}])
|
||||
|
||||
async def _sql(sql):
|
||||
async with app.db_sessionmaker() as s:
|
||||
async with s.begin():
|
||||
await s.execute(text(sql), {"h": a.id, "p": seed["plan_id"]})
|
||||
|
||||
# The agent goes quiet after its update, and stays so past the limit.
|
||||
await _sql("UPDATE host_agent_registrations SET last_seen_at = now() - interval '1 hour' "
|
||||
"WHERE host_id = :h")
|
||||
await _tick(app)
|
||||
await _sql("UPDATE host_maintenance_runs SET settle_since = now() - interval '31 minutes' "
|
||||
"WHERE plan_id = :p")
|
||||
flags = await _tick(app)
|
||||
state, _, detail = await _run(app, seed["plan_id"])
|
||||
assert state == "failed" and "not back in service within 30 min" in detail
|
||||
assert flags[a.name] == 1.0
|
||||
|
||||
# Posting again, it is back in service: nothing is left failed.
|
||||
await _post(app, ta)
|
||||
assert (await _tick(app))[a.name] == 0.0
|
||||
|
||||
asyncio.run(_go())
|
||||
|
||||
Reference in New Issue
Block a user