Judge a PC's backup by its stalest kind, not its newest
Until part markers, a PC reported exactly one backup kind and "newest revision wins" was the same thing as the truth. A marker bay reports two: ntlars for the machine's DNC settings, partmarker for the controller's patterns. With newest-wins, the daily ntlars post keeps the badge green while the marker backup has been failing for a month. The failure shows only on that marker's asset page, which is not where anyone looks to find out something stopped - and "is this still being checked" is the one question this badge exists to answer. So a host is green only when everything it backs up is current, and the badge names the kind that is not. Freshest revision per kind first, because lastseenat only ever moves on the newest revision of a chain; judging every row would report a healthy, frequently changing config as permanently stale. Known consequence, and the right direction to err: a device retired from a PC leaves its last revision behind, so that host stays stale until the revision is pruned. It complains about a backup that genuinely is not running rather than staying quiet about one. The dashboard card needed no change - it already lists every stale chain independently, so a stale partmarker chain was never hidden there.
This commit is contained in:
@@ -1079,10 +1079,52 @@ def _attach_backup_state(facts, hostnames):
|
||||
rows.sort(key=lambda revision: (revision.lastseenat is not None,
|
||||
revision.lastseenat or _EPOCH),
|
||||
reverse=True)
|
||||
|
||||
# Reduce to the FRESHEST revision per (host, kind), then judge a host by its
|
||||
# STALEST kind.
|
||||
#
|
||||
# Until part markers, a PC reported exactly one kind and "newest wins" was
|
||||
# the same thing as "the truth". A marker bay reports two - ntlars for the
|
||||
# machine's DNC settings and partmarker for the controller's patterns - and
|
||||
# newest-wins then means the daily ntlars post keeps the badge green while
|
||||
# the marker backup has been failing for a month. The failure would show
|
||||
# only on that marker's own asset page, which is not where anyone looks to
|
||||
# find out that something stopped.
|
||||
#
|
||||
# So: a host is healthy when EVERYTHING it backs up is current, and the
|
||||
# badge names the kind that is not. Freshest-per-kind first, because
|
||||
# lastseenat only moves on the newest revision of a chain - an older
|
||||
# revision of the same kind keeps its original value and would otherwise
|
||||
# read as stale for ever.
|
||||
#
|
||||
# KNOWN CONSEQUENCE: a device retired from a PC leaves its last revision
|
||||
# behind, so that host stays stale until the revision is pruned or removed.
|
||||
# That is the honest failure direction - it complains about a backup that
|
||||
# genuinely is not running any more, rather than staying quiet about one.
|
||||
freshest = {}
|
||||
for revision in rows:
|
||||
key = (revision.sourcehostname or '').lower()
|
||||
if key not in facts:
|
||||
continue
|
||||
kindkey = (key, revision.backupkind)
|
||||
if kindkey not in freshest:
|
||||
# rows are already newest-confirmed-first, so the first is freshest.
|
||||
freshest[kindkey] = revision
|
||||
|
||||
stalest = {}
|
||||
for (key, _kind), revision in freshest.items():
|
||||
current = stalest.get(key)
|
||||
if current is None:
|
||||
stalest[key] = revision
|
||||
continue
|
||||
# None (never confirmed) is worse than any date.
|
||||
if revision.lastseenat is None:
|
||||
stalest[key] = revision
|
||||
elif current.lastseenat is not None and revision.lastseenat < current.lastseenat:
|
||||
stalest[key] = revision
|
||||
|
||||
for key, revision in stalest.items():
|
||||
entry = facts.get(key)
|
||||
# First row per host wins.
|
||||
if entry and entry['backuplastseen'] is None:
|
||||
entry['backupkind'] = revision.backupkind
|
||||
entry['backuplastseen'] = (
|
||||
|
||||
Reference in New Issue
Block a user