{# On /admin/db (web/admin.py admin_db; owner, 2026-10-14): VM and bucket health, the VM's history, then where the data lives (racinglines/storage_status.py's snapshot, racinglines/vm_history.py). Sizes and counts only (the bucket holds licensed vendor data), so admin-only. #} {% from "_macros.html" import csrf, empty %}

VM and bucket

Health, the VM's last {{ 14 }} days, and where the data lives. The same snapshot as racinglines db storage and the MCP tool storage_status.

{{ csrf() }}
{% if not snap %}{{ empty("No storage snapshot yet. The first one is being taken now (the bucket listing can take a few minutes); reload in a while.") }} {% else %}

Snapshot {{ snap.taken_at }} ({{ (age / 60)|round|int }} min ago, took {{ snap.seconds }} s){% if age is not none and age >= stale %} · stale, refreshing in the background{% elif refreshing %} · refreshing in the background{% endif %}.

Health

{% for h in health %}{% endfor %}
{{ "✓ ok" if h.state == 'ok' else "✕ down" if h.state == 'bad' else "! check" }}{{ h.check }}{{ h.text }}
{% endif %}

VM over time

{% if vm_charts|selectattr("chart")|list %}
{% for c in vm_charts %}
{{ c.label }}{% if c.chart %} · now {{ "%.0f"|format(c.chart.last) if c.unit else "%.2f"|format(c.chart.last) }}{{ c.unit }} · peak {{ "%.0f"|format(c.chart.max) if c.unit else "%.2f"|format(c.chart.max) }}{{ c.unit }}{% endif %}
{% if c.chart %}{% set g = c.chart %} {% for x, y, t, v in g.dots %}{{ t|fmt_epoch }} · {{ "%.1f"|format(v) }}{{ c.unit }}{% endfor %}
{{ g.start|fmt_epoch }}top {{ "%.0f"|format(g.ymax) }}{{ c.unit }}{{ g.end|fmt_epoch }}
{% else %}

Not enough samples yet.

{% endif %}
{% endfor %}
As a table
{% for c in vm_charts if c.chart %}{% endfor %}
MetricNowPeakFromTo
{{ c.label }}{{ "%.1f"|format(c.chart.last) }}{{ c.unit }}{{ "%.1f"|format(c.chart.max) }}{{ c.unit }}{{ c.chart.start|fmt_epoch }}{{ c.chart.end|fmt_epoch }}
{% else %}

No history yet: the web app samples CPU, memory, load and disk every 5 minutes from its start (data/status/vm_history.jsonl).

{% endif %}
{% if snap %}

VM disk and data folders

{% set d = snap.vm.disk %}

Disk: {{ human(d.free) }} free of {{ human(d.total) }} ({{ human(d.used) }} used, {{ (100 * d.used / d.total)|round|int if d.total else 0 }}%).

{% for r in snap.vm.roots %}

{{ r.path }} · {{ human(r.bytes) }}

{% for f in r.folders|sort(attribute="bytes", reverse=true) %}{% endfor %}
FolderSizeFilesNewest file
{{ f.name }}/{{ human(f.bytes) }}{{ "{:,}".format(f.files) }}{{ f.newest or "" }}

Database dumps in backups/db: {{ r.backups.dumps }} ({{ human(r.backups.bytes) }}){% if r.backups.newest %}, newest {{ r.backups.newest }}{% endif %}.

{% endfor %}

Databases on the VM

{% if snap.databases %} {% for db in snap.databases %}{% endfor %}
DatabaseSize
{{ db.name }}{{ human(db.bytes) }}
{% else %}{{ empty(snap.databases_error or "No database sizes in this snapshot.") }}{% endif %}
{% for b in snap.buckets %}

Bucket gs://{{ b.bucket }}{% if not b.error %} · {{ human(b.bytes) }}, {{ "{:,}".format(b.objects) }} objects{% endif %}

{% if b.error %}

Could not list it from the VM: {{ b.error }}

{% else %}
{% for p in b.prefixes %} {% for c in p.children %}{% endfor %} {% endfor %}
PrefixSizeObjectsNewest object
{{ p.prefix }}{{ human(p.bytes) }}{{ "{:,}".format(p.objects) }}{{ p.newest }}
  {{ c.prefix }}{{ human(c.bytes) }}{{ "{:,}".format(c.objects) }}{{ c.newest }}
{% endif %}
{% endfor %} {% endif %}