Nobody sees free storage space — surface capacity honestly per backend #178

Closed
opened 2026-08-10 00:50:14 +00:00 by Cordy · 1 comment
Owner

Dogfood note (Nikola): nowhere in Cairn do admins or users see free storage space.

What exists today: GET /api/v1/quota and WebDAV RFC 4331 props report usage — but only where the driver implements storage.Usager. posix does; s3 does not (an S3 bucket has no standard capacity notion, so the endpoint honestly answers 501). The dogfood is s3, hence: nothing anywhere. The web UI additionally never displays the number even where it exists — only WebDAV clients show it.

Plan:

  1. UI: a small capacity readout (used / free, progress bar) in the user's view and on the admin info card, fed by /api/v1/quota, shown when the backend reports it, honestly absent (not fake) when it doesn't.
  2. Enforced-quota fallback: when storage.quota.maxTotalBytes or perUserBytes is configured, display usage against that limit even on s3 — the enforcement walk already computes the numbers.
  3. Garage-specific (investigate, maybe reject): Garage tracks bucket quotas (the dogfood bucket has one) but exposes them via its admin API, not the S3 API. Depending on a vendor admin endpoint is against the grain of the hand-rolled generic S3 client — likely verdict is "document that s3 capacity comes from configured quotas, not the store", but the check is cheap.
Dogfood note (Nikola): nowhere in Cairn do admins or users see free storage space. **What exists today:** `GET /api/v1/quota` and WebDAV RFC 4331 props report usage — but only where the driver implements `storage.Usager`. **posix does; s3 does not** (an S3 bucket has no standard capacity notion, so the endpoint honestly answers 501). The dogfood is s3, hence: nothing anywhere. The web UI additionally never *displays* the number even where it exists — only WebDAV clients show it. **Plan:** 1. **UI**: a small capacity readout (used / free, progress bar) in the user's view and on the admin info card, fed by `/api/v1/quota`, shown when the backend reports it, honestly absent (not fake) when it doesn't. 2. **Enforced-quota fallback**: when `storage.quota.maxTotalBytes` or `perUserBytes` is configured, display usage against *that* limit even on s3 — the enforcement walk already computes the numbers. 3. **Garage-specific (investigate, maybe reject)**: Garage tracks bucket quotas (the dogfood bucket has one) but exposes them via its admin API, not the S3 API. Depending on a vendor admin endpoint is against the grain of the hand-rolled generic S3 client — likely verdict is "document that s3 capacity comes from configured quotas, not the store", but the check is cheap.
Author
Owner

Shipped in v0.6.15 (PR #203), live on the dogfood (/api/v1/quota returning 200 in the logs).

  • S3/Garage Usager (internal/storage/s3/usage.go): Used summed on demand over a flat bucket listing, cached ~60s. Object stores have no capacity, so the quota layer supplies Total.
  • Quota caps are admin-editable + persisted: quotaPerUserBytes + quotaInstanceBytes live in the settings store (encrypted state-backend, like retention); the quota decorator reads them live via SetLimits — no restart. Config quotas remain the seed. The decorator is now always constructed so settings-driven caps enforce even with no config seed.
  • Honest per-backend display: for object stores the configured instance allowance is surfaced as Total; POSIX real capacity is only tightened, never inflated. Usage() overlay in quota.go.
  • UI: admin Settings gains per-user + instance limit fields and an instance usage row (storage card); every user sees their own used/remaining in the account menu. GET /api/v1/quota returns instance figures to admins, per-user to everyone.
  • Semantics: 0 = no limit; enabling a cap on an already-over instance blocks new writes (visible "quota exceeded") but never deletes; per-user charges the /home/<user> tree.

Closing — the original "nobody sees free space" gap is resolved, and it grew into full editable quotas per your dogfood direction.

Shipped in **v0.6.15** (PR #203), live on the dogfood (`/api/v1/quota` returning 200 in the logs). - **S3/Garage `Usager`** (`internal/storage/s3/usage.go`): `Used` summed on demand over a flat bucket listing, cached ~60s. Object stores have no capacity, so the quota layer supplies `Total`. - **Quota caps are admin-editable + persisted**: `quotaPerUserBytes` + `quotaInstanceBytes` live in the settings store (encrypted state-backend, like retention); the quota decorator reads them live via `SetLimits` — no restart. Config quotas remain the seed. The decorator is now always constructed so settings-driven caps enforce even with no config seed. - **Honest per-backend display**: for object stores the configured instance allowance is surfaced as `Total`; POSIX real capacity is only tightened, never inflated. `Usage()` overlay in `quota.go`. - **UI**: admin Settings gains per-user + instance limit fields and an instance usage row (storage card); every user sees their own used/remaining in the account menu. `GET /api/v1/quota` returns instance figures to admins, per-user to everyone. - **Semantics**: `0` = no limit; enabling a cap on an already-over instance blocks new writes (visible "quota exceeded") but never deletes; per-user charges the `/home/<user>` tree. Closing — the original "nobody sees free space" gap is resolved, and it grew into full editable quotas per your dogfood direction.
Cordy closed this issue 2026-08-12 04:56:56 +00:00
Sign in to join this conversation.
No labels
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#178
No description provided.