Give the backups plugin a settings page, and show where a snapshot is

The plugin shipped five settings and no page for any of them. The core settings
catalog is a hardcoded list a plugin cannot extend, so backups_shareroot and the
collection interval were reachable only through the API or a flask shell on the
server - which is not a configurable setting in any useful sense, and it is how
today went: the setting simply was not there to set.

The page is contributed the ADR-010 way rather than by editing core - a card
from get_settings_cards plus a route in the plugin's own routes.js, both of
which disappear when the plugin is disabled. Filed under Machines, next to
Machine Types, because that is where the assets these back up live.

It also states the two things the settings do not say for themselves: that
health is judged on when a backup was last CONFIRMED rather than when it last
changed, and that retention prunes database revisions only - files on the share
stay, so enabling it on a share-backed kind leaves orphaned snapshot
directories.

Snapshot paths are now shown as full UNC text in both places: a Snapshot row on
the Marker Contents card, and the existing path on the history page, which
gains a copy button. Deliberately NOT a link - browsers refuse to navigate from
an https page to file://, so a clickable path looks actionable and silently
does nothing, which is worse than no link. Copy, then paste into Explorer.

The path comes off the revision, never composed from the configured share root:
a snapshot written before the layout changed still lives where it was put.
This commit is contained in:
cproudlock
2026-08-25 14:53:04 -04:00
parent ee208808f4
commit 500f7d6ad6
8 changed files with 287 additions and 3 deletions

View File

@@ -1381,3 +1381,38 @@ def test_buildinfo_kwargs_do_not_disturb_the_live_ntlars_card(bk_app, bk_plugin)
partmarkertypes=None, revisionid=revision.backuprevisionid,
sourcehostname=revision.sourcehostname)
assert 'sectioncount' in card
def test_the_card_shows_the_snapshot_path_it_was_actually_written_to(bk_app, bk_plugin):
"""Plain text, and from the REVISION - not composed from the setting.
A snapshot written before the share layout changed still lives where it was
put, so the stored path is the only honest answer. It is not a link: a
browser refuses to navigate from https to file://, so a clickable path
would look actionable and do nothing.
"""
from plugins.backups.services import partmarkerinfo
from plugins.backups.models import BackupRevision
with bk_app.app_context():
result = bk_plugin.apply_collector_payload({
'machinenumber': '3204', 'backupkind': 'partmarker',
'contenthash': 'c3' * 32,
'sharepath': r'\\host\share\partmarker\3204\20260825-144500',
'sourcehostname': 'FBYTNCX3',
'manifest': _markermanifest(['A.PAT'])})
_db.session.commit()
revision = _db.session.get(BackupRevision, result['backuprevisionid'])
card = partmarkerinfo.build(revision.payload, revision.assetid,
revisionid=revision.backuprevisionid,
sharepath=revision.sharepath)
snapshot = [f for f in card['fields'] if f['label'] == 'Snapshot']
assert snapshot and snapshot[0]['value'] == revision.sharepath
assert snapshot[0]['mono'] is True
def test_the_card_omits_the_snapshot_row_when_no_path_is_passed(bk_app, bk_plugin):
from plugins.backups.services import partmarkerinfo
card = partmarkerinfo.build(_markermanifest(['A.PAT']), 1)
assert 'Snapshot' not in [f['label'] for f in card['fields']]