Skip to content

Commit c97f426

Browse files
scotwellsclaude
andcommitted
docs(quota): edge + single-tenant local quota enforcement RFC (#171)
Adds the RFC covering the two non-management-plane deployments — edge/remote Milo and flat single-tenant local — and correcting the assumption that quota enforcement implies mode==milo. Edge cells enforce quota via the always-on backoff/requeue safety net; a live edge claim watch is a deferred future option. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 89126ef commit c97f426

1 file changed

Lines changed: 254 additions & 0 deletions

File tree

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
---
2+
status: mixed — management-plane quota (shipped) + edge (backoff) & single-tenant (proposed)
3+
---
4+
5+
# Quota Edge Integration: Routing ResourceClaims to Project Control Planes
6+
7+
> The management-plane claim-routing design is **implemented and shipped** (last
8+
> verified 2026-05-26). The edge-cell and flat single-tenant designs below are
9+
> **proposed, not yet implemented**. Fixes
10+
> [#171](https://github.com/datum-cloud/compute/issues/171).
11+
12+
## Table of Contents
13+
14+
- [Summary](#summary)
15+
- [Problem Statement](#problem-statement)
16+
- [Three deployment topologies](#three-deployment-topologies)
17+
- [Design](#design)
18+
- [The live watch runs where claims are co-located](#the-live-watch-runs-where-claims-are-co-located)
19+
- [Claim CRUD routes to the owning ledger](#claim-crud-routes-to-the-owning-ledger)
20+
- [The backoff safety net](#the-backoff-safety-net)
21+
- [Flat single-tenant: co-located quota and fixed-project identity](#flat-single-tenant-co-located-quota-and-fixed-project-identity)
22+
- [Alternatives considered](#alternatives-considered)
23+
- [RBAC dependency](#rbac-dependency)
24+
- [Known limitation: cell-wide unique Instance names](#known-limitation-cell-wide-unique-instance-names)
25+
- [Rollout](#rollout)
26+
- [Risks](#risks)
27+
- [Open questions](#open-questions)
28+
- [Out of Scope](#out-of-scope)
29+
30+
---
31+
32+
## Summary
33+
34+
Datum operators want to enforce quota on the Instances their customers run — and not
35+
only in the central management plane, but wherever compute runs: on **edge cells**
36+
close to users and on **flat single-tenant clusters**. Today quota enforcement works
37+
only in the central management plane. Turn it on anywhere else and one of two bad
38+
things happens: quota silently never evaluates (claims are recorded where the quota
39+
system never reads them, so every Instance runs ungated), or compute-manager crashes
40+
outright ([#171](https://github.com/datum-cloud/compute/issues/171)).
41+
42+
This RFC makes quota enforcement work across all three deployments, so an operator can
43+
stand up a quota-enforced edge cell or single-tenant cluster and have customer
44+
Instances gated on real quota grants. The shipped half routes each Instance's quota
45+
claim to the control plane that owns the project's quota ledger and watches those claims
46+
where the manager already engages them. The proposed half extends enforcement to two
47+
more deployments: **flat single-tenant** clusters, where the ledger is co-located and
48+
watched directly; and **edge cells**, where the ledger is remote and enforcement rides
49+
the always-on backoff reconcile rather than a live watch.
50+
51+
---
52+
53+
## Problem Statement
54+
55+
**What the operator saw.** Enabling quota outside the management plane did nothing
56+
useful, or worse. In the best case every Instance sat waiting on a quota grant that
57+
never came, with no error and no signal — because the claim recording the Instance's
58+
demand was written somewhere the quota system never reads. In the worst case (edge
59+
cells) compute-manager failed to start at all: it tried to watch for quota claims on a
60+
cluster that doesn't host the quota API, and crashed on startup.
61+
62+
Both failures share one root: the system assumed quota claims live on, and are watched
63+
from, whatever cluster the controller happens to run on. That assumption holds only in
64+
the management plane. The design below replaces it with an explicit model of where each
65+
deployment's quota ledger actually lives, and of how each learns that a claim has been
66+
granted.
67+
68+
---
69+
70+
## Three deployment topologies
71+
72+
Quota enforcement spans three deployments, each serving a different customer shape,
73+
keeping its quota ledger in a different place, and learning about grants differently:
74+
75+
| Topology | Serves | Where the quota ledger / ResourceClaims live | How grants are observed |
76+
|---|---|---|---|
77+
| **Management plane** | Datum's central control plane, across many customer projects | Per-project Milo control planes, which the manager already engages | Live direct watch |
78+
| **Edge cell** | Compute close to users; ledger back in a remote Milo | Remote Milo, per-project control planes — **not** on the cell | **Periodic backoff reconcile — no live watch** |
79+
| **Flat single-tenant** | A single customer's own cluster, no central Milo in the path | Co-located on the one cluster | Live direct watch |
80+
81+
The management-plane topology is shipped; the other two are the proposed additions. The
82+
distinction that matters architecturally is whether the claims sit on a cluster the
83+
manager already watches. Where they do (management plane, single-tenant) enforcement can
84+
observe grants live; where they don't (edge) it relies on the backoff floor.
85+
86+
---
87+
88+
## Design
89+
90+
### The live watch runs where claims are co-located
91+
92+
The core decision: **a live claim watch runs only on the clusters the manager already
93+
engages that serve the quota API** — the management plane's per-project provider
94+
clusters, and a flat single-tenant cluster's local API. We do **not** stand up
95+
additional watches against clusters the manager isn't already engaging.
96+
97+
An edge cell's ledger fails that test twice over: its claims are remote, and they are
98+
split across one control plane per project the cell serves. So an edge cell registers no
99+
live claim watch — which is also exactly what stops the crash, since its local cluster
100+
does not serve the quota API and never should have been asked to watch that kind:
101+
102+
> watch claims live ⟺ a cluster the manager already engages serves the quota API
103+
104+
A transient inability to determine this must **fail loud** (refuse to start) rather than
105+
silently resolve to "off," which would masquerade as a healthy deployment.
106+
107+
### Claim CRUD routes to the owning ledger
108+
109+
Creating, reading, and deleting an Instance's claim targets the control plane that owns
110+
the project's quota ledger: the project control plane in the management-plane and edge
111+
topologies, the local cluster in flat single-tenant. Whatever observes a grant must read
112+
from the same ledger the claim was written to — if writes and reads target different
113+
ledgers, claims are created in one place and looked for in another, so grants are never
114+
seen even though everything appears wired.
115+
116+
At the edge this routing is also how enforcement stays live without a watch: each
117+
backoff reconcile creates-or-reads the Instance's remote claim and checks whether it has
118+
been granted.
119+
120+
### The backoff safety net
121+
122+
Enforcement has always had an always-on floor: while an Instance's quota is not yet
123+
granted, its reconcile re-runs on a backing-off schedule and re-checks the claim each
124+
time. This floor is **universal** — every topology falls back to it — and at the **edge
125+
it is the sole liveness mechanism**. Grants there are observed within seconds and
126+
self-heal as the schedule backs off; there is simply no live watch to short-circuit the
127+
wait.
128+
129+
The tradeoff is latency, not correctness. An Instance is never ungated until its quota
130+
is actually granted; the only cost of relying on backoff is how quickly a grant is
131+
*noticed*. That cost is acceptable at the edge, which is why the live edge watch is
132+
deferred (see [Alternatives considered](#alternatives-considered)).
133+
134+
### Flat single-tenant: co-located quota and fixed-project identity
135+
136+
A flat single-tenant deployment co-locates the quota API and compute on one cluster, so
137+
the manager already engages the cluster that holds the claims — the live watch runs
138+
there directly, with no remote hop. It is reached simply by letting the watch run when
139+
the quota API is present locally (the decision above).
140+
141+
The one genuinely new concept is **identity**. In the management-plane and edge
142+
topologies the project that owns a claim is derived from platform namespace-ownership
143+
labels. A flat single-tenant deployment may not run that platform labeling layer, so it
144+
instead names its single project explicitly through configuration, and every claim is
145+
attributed to that project. If local quota is enabled without a configured project, the
146+
deployment refuses to start rather than emit claims the evaluator cannot attribute.
147+
148+
---
149+
150+
## Alternatives considered
151+
152+
- **A live edge watch via a per-project-control-plane forwarder.** Considered and
153+
**deferred**. Because an edge cell's claims are split across one control plane per
154+
project it serves, a live edge watch means establishing and maintaining a watch
155+
against *each* of those control planes — fan-out that grows with the projects a cell
156+
serves. The always-on backoff already delivers grants within seconds, so the machinery
157+
isn't worth it now. Revisit if edge grant latency ever becomes a product concern.
158+
- **A single unified multi-cluster provider spanning the cell and the remote ledger.**
159+
Rejected: folding the remote ledger into the cell's own provider destabilizes the
160+
cell's control path — it breaks the single-cluster assumption the cell's controllers
161+
rely on to run at all.
162+
- **Install the quota API locally on edge cells.** Rejected: an edge cell should not
163+
host the authoritative quota ledger. The ledger lives back in the platform; the edge
164+
reads it, it doesn't own it.
165+
166+
---
167+
168+
## RBAC dependency
169+
170+
Every topology that writes claims to a ledger it does not host depends on permissions
171+
there — but only for the operations it actually performs. None can be granted from this
172+
repository; all are platform-side prerequisites.
173+
174+
- **Edge cell.** The cell creates, reads, and deletes claims in the remote per-project
175+
control planes — it writes each claim and polls its grant on every backoff reconcile.
176+
It needs those create/read/delete grants, but because it runs **no live watch** it
177+
does **not** need list/watch there, and it needs no project-discovery permission.
178+
- **Flat single-tenant.** The manager needs access to the co-located quota API on its
179+
own cluster.
180+
- **Management plane.** The pre-existing provider-cluster watch on project control
181+
planes is unchanged (shipped).
182+
183+
If an edge cell lacks the create/read access it needs, claim creation and grant-polling
184+
fail: the reconcile errors and requeues, and the Instance stays gated until access is
185+
fixed. That is a loud, self-retrying failure — not a silent bypass.
186+
187+
---
188+
189+
## Known limitation: cell-wide unique Instance names
190+
191+
**Deferred — an operator constraint, not a rollout blocker.** In a flat single-tenant
192+
deployment all of a project's quota claims share one space, and a claim's identity is
193+
derived from its Instance's name. Two Instances with the **same name in different
194+
namespaces** therefore collide on a single claim: one can overwrite or block the other,
195+
so quota is attributed to the wrong Instance or a legitimate Instance is wrongly gated.
196+
This cannot happen in the management-plane or edge topologies, where claims are separated
197+
per project control plane and per project namespace.
198+
199+
Until claim identity is qualified by namespace, the operator rule for flat single-tenant
200+
mode is: **Instance names must be unique across the whole cell**, not merely within a
201+
namespace. Qualifying claim identity by namespace is the fix, tracked separately.
202+
203+
---
204+
205+
## Rollout
206+
207+
There is no capability flag to manage; the proposed changes take effect by deployment
208+
shape:
209+
210+
1. **Edge cells stop crashing immediately.** The live watch is simply not registered
211+
where the local cluster doesn't serve the quota API, and enforcement rides the
212+
backoff floor. Confirm the cell's platform-side create/read access to the remote
213+
ledger so that the claims it writes are actually evaluated.
214+
2. **Flat single-tenant** activates when the quota API is present locally and a project
215+
is configured.
216+
3. **Management plane** is unchanged.
217+
218+
---
219+
220+
## Risks
221+
222+
- **Edge grant latency.** With no live edge watch, a grant is observed on the backoff
223+
schedule (seconds, backing off), not instantly. Accepted as the tradeoff of deferring
224+
the edge watch; revisit if latency ever matters to the product.
225+
- **Edge access to the remote ledger.** If a cell lacks create/read on the remote
226+
per-project claims, its Instances stay gated until access is fixed — correct (no
227+
bypass), but it blocks scheduling and surfaces as recurring reconcile errors rather
228+
than a single obvious failure.
229+
- **Flat single-tenant name collision.** Same-named Instances in different namespaces
230+
contend for one claim; see [Known limitation](#known-limitation-cell-wide-unique-instance-names).
231+
232+
---
233+
234+
## Open questions
235+
236+
1. Does the co-located quota evaluator actually grant claims attributed to the configured
237+
flat-tenant project (is that project entitled), or do they stall? Platform-side
238+
behavior, verifiable only in a running deployment.
239+
2. Is the per-project create/read access a cell needs actually in place across the
240+
projects it serves? A rollout verification, not a design question.
241+
3. If edge grant latency ever matters, is a live per-project edge watch worth building?
242+
(The revisit trigger for the deferred alternative above.)
243+
244+
---
245+
246+
## Out of Scope
247+
248+
**WorkloadDeployment quota.** This design covers Instance-level quota claims only.
249+
Whether WorkloadDeployments should also emit claims, and at what resources, is a separate
250+
design.
251+
252+
**Migration of mis-written claims.** Claims recorded on the wrong cluster before the
253+
shipped fix remain there; they are never evaluated and are not cleaned up by the
254+
corrected paths. Removing them is an operational task, not part of this design.

0 commit comments

Comments
 (0)