feat(api): enforce CPU/memory/storage quotas (spec §9.3, §22)
Add per-user resource quota enforcement across all four dimensions: max_servers, max_cpu_milli, max_memory_mb, and max_storage_gb. - Migration 0013: add cached_cpu_milli, cached_memory_mb, cached_storage_mb columns to servers table for pure-SQL per-owner aggregation - SeedServer now writes resource cache alongside server row - QuotaCheck replaces QuotaAvailable at claim time, checking all four caps against the owning user's cumulative usage - handlePatchServer checks owner's quota before allowing memory/resource changes on owned servers; unowned servers skip the gate - handleInternalClaim mirrors the full quota check - UpdateServerResources keeps the cache in sync after spec mutations - Reaper zeros resource cache on ReleaseWorld so released resources are not counted against a former owner - quantityToMilli/quantityToMB helpers convert K8s quantities to quota-comparable integers 19 test packages pass.
This commit is contained in:
8 files changed
+211
-23
No files matched your search
@@ -209,6 +209,19 @@ func (f *fakeRepo) ServerByName(_ context.Context, n string) (*ServerRecord, err
|
||||
}
|
||||
func (f *fakeRepo) IsLinked(_ context.Context, u string) (bool, error) { return f.linked[u], nil }
|
||||
func (f *fakeRepo) QuotaAvailable(_ context.Context, u string) (bool, error) { return f.quota[u], nil }
|
||||
|
||||
func (f *fakeRepo) QuotaCheck(_ context.Context, userID string, _ string, _ ResourceSpec) (bool, error) {
|
||||
// For hermetic tests, QuotaCheck delegates to the same QuotaAvailable
|
||||
// store — tests that care about per-dimension checks should use
|
||||
// fakeQuotas with direct inspection.
|
||||
return f.QuotaAvailable(nil, userID)
|
||||
}
|
||||
|
||||
func (f *fakeRepo) UpdateServerResources(_ context.Context, _ string, _, _, _ int) error { return nil }
|
||||
|
||||
func (f *fakeRepo) ServerResources(_ context.Context, _ string) (ResourceSpec, error) {
|
||||
return ResourceSpec{}, nil
|
||||
}
|
||||
func (f *fakeRepo) CreateLinkCode(_ context.Context, code, mcUUID, authSource string, expiresAt time.Time) error {
|
||||
f.linkCodes[code] = fakeLinkCode{mcUUID: mcUUID, authSource: authSource, expiresAt: expiresAt}
|
||||
return nil
|
||||
@@ -532,7 +545,7 @@ func (f *fakeRepo) ServerOwners(_ context.Context) (map[string]string, error) {
|
||||
}
|
||||
return f.owners, nil
|
||||
}
|
||||
func (f *fakeRepo) SeedServer(_ context.Context, name, subdomain string) error {
|
||||
func (f *fakeRepo) SeedServer(_ context.Context, name, subdomain string, _, _, _ int) error {
|
||||
if f.seedErr != nil {
|
||||
return f.seedErr
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user