#5816 "Restoring mode": while a backup goes back in, the scheduler holds, ingest and HTMX answer 503 with Retry-After (agents keep their samples), and every page says what is happening. A safety backup of Steward as it stands is made first, to /data/backups and the bucket. The backup's key is put in place, the restore audited, and Steward exits with code 3 so Swarm, compose or systemd starts it fresh. A failed in-place restore changes nothing and says why on Backups; a full replace that fails after the wipe restarts into first-run setup. #5817 "Settings → Backups: Restore": a Restore button on each sent backup and on the file card. The chosen backup is checked (the same comparison as Check, now a shared partial) and held server-side for an hour under a token; it starts only once the admin types "restore", and an older backup also needs "Replace everything" ticked. A newer backup, or one whose key can't open its secrets, gets no button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{# settings/backups.html — Steward's own backups (#5673): a verdict, the bucket
|
||||
they go to (Fabled Archives over S3) and the daily hour, then the recent
|
||||
runs, each with its own check and a Check button (#5823), and a file to
|
||||
check. Restoring is `steward restore`; see docs/core/backups.md. #}
|
||||
runs, each with its own check and Check and Restore buttons (#5823, #5817),
|
||||
and a file to check or restore. #}
|
||||
{% extends "base.html" %}
|
||||
{% from "_macros.html" import crumbs %}
|
||||
{% from "settings/_tabs.html" import settings_tabs %}
|
||||
@@ -16,6 +16,12 @@
|
||||
{% if verdict.good %}The newest good backup was sent {{ verdict.good|ago }}.{% else %}No backup has been sent yet.{% endif %}
|
||||
{%- endif %}</span></p>
|
||||
|
||||
{% if restore_failed %}
|
||||
<p class="tone-crit" style="margin:-0.5rem 0 1.25rem;">The restore of {{ restore_failed.name }}
|
||||
{%- if restore_failed.since %} {{ restore_failed.since|ago }}{% endif %} failed, and nothing changed:
|
||||
{{ restore_failed.error }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if flash %}
|
||||
<div style="padding:0.75rem 1rem;border-radius:6px;margin-bottom:1.25rem;
|
||||
background:{% if flash.ok %}var(--green-dim){% else %}var(--red-dim){% endif %};
|
||||
@@ -130,11 +136,15 @@
|
||||
<td class="nowrap">{{ r.size|bytes if r.ok else "—" }}</td>
|
||||
<td class="nowrap">{{ r.secs|duration }}</td>
|
||||
<td>{{ "the schedule" if r.by == "schedule" else r.by }}</td>
|
||||
<td>{% if r.ok and r.name %}
|
||||
<td>{% if r.ok and r.name %}<div style="display:flex;gap:0.35rem;">
|
||||
<form method="post" action="/settings/backups/check/">{{ csrf_field() }}
|
||||
<input type="hidden" name="name" value="{{ r.name }}">
|
||||
<button type="submit" class="btn btn-ghost btn-sm" title="Compare {{ r.name }} with what is in place; nothing changes">Check</button>
|
||||
</form>{% endif %}</td>
|
||||
</form>
|
||||
<form method="post" action="/settings/backups/restore/">{{ csrf_field() }}
|
||||
<input type="hidden" name="name" value="{{ r.name }}">
|
||||
<button type="submit" class="btn btn-ghost btn-sm" title="See what restoring {{ r.name }} would change, then confirm">Restore</button>
|
||||
</form></div>{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -144,15 +154,16 @@
|
||||
<p class="tone-dim">None yet.</p>
|
||||
{% endif %}
|
||||
<p class="field-hint" style="margin-top:0.75rem;">Check compares a backup with what is in place: what
|
||||
a restore would bring back, change or remove, area by area. It changes nothing. To bring Steward back
|
||||
from one, see <code>steward restore</code> in the backups guide (docs/core/backups.md).</p>
|
||||
a restore would bring back, change or remove, area by area. It changes nothing. Restore shows the same
|
||||
comparison and asks you to confirm before anything changes.</p>
|
||||
|
||||
<div class="card" style="max-width:640px;margin-top:1.25rem;">
|
||||
<h2 class="section-title" style="margin-bottom:0.5rem;">Check a file</h2>
|
||||
<h2 class="section-title" style="margin-bottom:0.5rem;">Check or restore a file</h2>
|
||||
<form method="post" action="/settings/backups/check/file/" enctype="multipart/form-data"
|
||||
style="display:flex;gap:0.75rem;flex-wrap:wrap;align-items:center;">{{ csrf_field() }}
|
||||
<input type="file" name="file" accept=".tar" required>
|
||||
<button type="submit" class="btn btn-ghost">Check</button>
|
||||
<button type="submit" class="btn btn-ghost" formaction="/settings/backups/restore/file/">Restore</button>
|
||||
</form>
|
||||
<p class="field-hint" style="margin-top:0.5rem;">A <code>steward-<time>.tar</code> downloaded from
|
||||
the bucket, or made with <code>steward backup</code>.</p>
|
||||
|
||||
Reference in New Issue
Block a user