From 0779feb23abb9e99a30064a6a120f01d03c14a42 Mon Sep 17 00:00:00 2001 From: Loki Date: Wed, 14 Oct 2026 13:35:01 +0800 Subject: [PATCH] feat(status): include the default budget carrel.winlab.tw shows what each member gets and that project groups get a budget of their own. GET /status now returns quota.member and quota.project from DefaultQuota, so the page never hardcodes them. Co-Authored-By: Claude Opus 5.5 --- internal/carrel/status.go | 15 ++++++++++++++- internal/carrel/status_test.go | 4 ++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/internal/carrel/status.go b/internal/carrel/status.go index e233e6d..b73d364 100644 --- a/internal/carrel/status.go +++ b/internal/carrel/status.go @@ -14,7 +14,9 @@ import ( // share. A tenant is named only when its slug is already public: it is // active and serves at least one ready *..winlab.tw domain. Every // other tenant with machines is summed into "others" without a name. -// Machine names, addresses, keys and domains are never listed. +// Machine names, addresses, keys and domains are never listed. "quota" is +// the default budget: every member gets one, and every project group gets +// another of its own on top of its members' budgets. func (e *Execution) PublicStatus() D { c := e.Capacity(nil, true) physical := obj(c["physical"]) @@ -55,11 +57,22 @@ func (e *Execution) PublicStatus() D { "disk_gib": D{"total": disk["total"], "used": disk["used"]}, }, "allocated": c["allocatable"], + "quota": D{"member": budget(DefaultQuota), "project": budget(DefaultQuota)}, "tenants": tenants, "others": others, } } +// budget is the part of a quota the status page shows. +func budget(q D) D { + return D{ + "machines": num(q["machines"]), + "vcpu": num(q["vcpu"]), + "memory_gib": num(q["memory_mb"]) / 1024, + "disk_gib": num(q["disk_gb"]), + } +} + // publicSlug reports whether a tenant's slug is already published by one of // its domains. func publicSlug(domains []D) bool { diff --git a/internal/carrel/status_test.go b/internal/carrel/status_test.go index 78b014e..cf3a426 100644 --- a/internal/carrel/status_test.go +++ b/internal/carrel/status_test.go @@ -46,6 +46,10 @@ func TestPublicStatusNamesOnlyTenantsWithAPublicDomain(t *testing.T) { if num(others["tenants"]) != 2 || num(others["machines"]) != 2 || num(others["vcpu"]) != 4 { t.Fatalf("unexpected others: %s", raw) } + member := obj(obj(body["quota"])["member"]) + if num(member["machines"]) != 8 || num(member["vcpu"]) != 8 || num(member["memory_gib"]) != 16 || num(member["disk_gib"]) != 100 || obj(obj(body["quota"])["project"])["vcpu"] == nil { + t.Fatalf("unexpected quota: %s", raw) + } node := obj(body["node"]) if num(obj(node["cpu"])["logical_cpus"]) != 32 || num(obj(node["memory_gib"])["total"]) != 192 { t.Fatalf("unexpected node: %s", raw)