feat(control-plane): real Cloudflare Containers driver for tenant lifecycle#7975
Conversation
…ecycle (#7851) Implements createContainer/destroyContainer/containerExists for real: one Container Durable Object per tenant+product, running each product's existing self-host Docker image unmodified (ORB: root Dockerfile; AMS: packages/loopover-miner/Dockerfile). "Provisioned" is tracked as an explicit flag in the paired DO's own durable storage rather than derived from Cloudflare's transient container run-state -- necessary because AMS's image is a one-shot CLI tool (#7182's own cron-wake design) that's expected to sit in a "stopped"-shaped run state almost all the time by design, which would otherwise be indistinguishable from "never provisioned." Composed onto the existing driver via withRealContainerDriver (same pattern as #7653's withRealDatabaseDriver), so #7852 (secret injection) can still ship independently. Adds both container images + Durable Object bindings to control-plane's wrangler.jsonc; both build successfully via wrangler deploy --dry-run.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
1 similar comment
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7975 +/- ##
==========================================
- Coverage 91.89% 91.40% -0.50%
==========================================
Files 738 739 +1
Lines 75706 75837 +131
Branches 23011 23016 +5
==========================================
- Hits 69573 69321 -252
- Misses 5041 5470 +429
+ Partials 1092 1046 -46
Flags with carried forward coverage won't be shown. Click here to find out more.
|
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-22 01:14:18 UTC
Review summary Nits — 5 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
Summary
Closes #7851
createContainer/destroyContainer/containerExistsfor real: one Cloudflare Container Durable Object pertenant+product, keyed by${product}:${tenant.name}(a single binding is fixed to one Docker image, so ORB and AMS each get their own binding/class).Dockerfile(the same self-host image already used elsewhere,PORT=8787); AMS getspackages/loopover-miner/Dockerfile(its existing CLI/batch image — confirmed via Cloudflare Cron Trigger wake scheduling for hosted AMS containers #7182's own text that AMS runs one-shot subcommands via a per-invocation entrypoint override, not HTTP, so nodefaultPort/HTTP surface is needed for this piece).running/stopped/stopped_with_code/etc). That distinction is load-bearing for AMS specifically: its image is a one-shot CLI tool expected to sit in a "stopped"-shaped run state almost all the time by design (Cloudflare Cron Trigger wake scheduling for hosted AMS containers #7182's "sleeping, zero-cost container" model) — indistinguishable from "never provisioned" using run-state alone. An explicit flag is unambiguous for either product.withRealContainerDriver(same composition pattern Real Postgres/Hyperdrive driver for control-plane's provisionDatabase/deprovisionDatabase #7653 established withwithRealDatabaseDriver), so Real secret-injection driver for control-plane's injectSecrets/revokeSecrets via the generalized broker #7852 (secret injection, still not landed) can still ship independently without this file changing again.createTenantProvisioningDrivergains an optional second parameter for container bindings — kept separate from the string-keyedenvparameter since real Durable Object namespace bindings only exist inside a Workers runtime, not as env strings;worker.tspasses them explicitly.Scope
type(scope): short summaryConventional Commit format.Validation
git diff --checknpm run typecheck(root)npm run control-plane:test— 94/94 passing (node --test).npm run control-plane:coverage— 100% line/branch/function coverage on every file this PR touches or adds; the only residual gap (settlement-backend-driver.ts) is pre-existing and untouched by this PR.npm run cf:typecheck(Workers-runtime typecheck including the two new Container subclasses).npx wrangler deploy --dry-run— both real Docker images actually build successfully (ORB's rootDockerfileand AMS'spackages/loopover-miner/Dockerfile, both from the repo-root build context), and both Durable Object bindings resolve correctly.npm audit --audit-level=moderate— pre-existing ambient advisories only (confirmed unrelated: this PR's only new dependency,@cloudflare/containers, introduces nothing new; rootpackage-lock.jsonis untouched by this diff).containerExiststrue/false, product-scoped instance keys, an unconfigured product's error, and the composition helper forwarding every non-container step to the base driver unchanged.Safety
Notes
Follow-up infra work on top of #7180 (provisioning core, now 3/5 pieces done: #7524, #7653, #7851) and #7654 (the Worker deployment this extends, rather than a second redundant one). Unlocks #7181 (webhook routing) and #7182 (cron wake scheduling) as the next real candidates, both of which need a real container to route/wake — that now exists. Only #7852 (secret injection) is left to fully close out #7180.