Provisioning overview
How ZopDay provisions clusters, datastores, networking, Helm components, and VMs; one state machine, idempotent steps.
ZopDay’s provisioner runs every infrastructure creation through one state machine: provisioning_jobs. Five resource families, three clouds, one ledger. This page covers the shape of the system; the per-family details are on the next pages.

Provision Infrastructure wizard; step 1 picks the resource type (cluster, datastore, cache).
What the provisioner creates
| Family | What it creates | Providers |
|---|---|---|
| Clusters | EKS / GKE / AKS control plane + workers + cluster IAM + default platform Helm components | AWS · GCP · Azure |
| Datastores | RDS / Cloud SQL / Azure DB (Postgres + MySQL); ElastiCache / Memorystore / Azure Cache for Redis | AWS · GCP · Azure |
| Networking | VPC, subnets, NAT, VPC peering (AWS + GCP), GCP Private Service Connect for cross-VPC Cloud SQL, DNS zones (Route 53 / Cloud DNS / Azure DNS) | AWS · GCP · Azure |
| In-cluster components | Helm catalog (configs/components.yaml) installed via Helm SDK on a registered space | Any registered space |
| VMs | Production-shaped multi-service VM environment with NAT outbound, optional cloud LB, no SSH (IAM-gated exec only) | AWS · GCP (Azure VMSS in preview / not yet GA) |
Each family has provider parity on day one (with the noted exceptions). The same job state machine drives all of them.
Two job kinds, one table
provisioning_jobs carries two job kinds:
kind | Used for |
|---|---|
provisioning | Infra creation + BYO datastore adoption |
remediation | Auto-remediation workflows (ZopNight; see Auto-remediation) |
Mixing them in one table lets the state machine, reconciler, and audit log work uniformly. The job’s subject_type / subject_id discriminates what’s being acted on.
Job lifecycle
draft → queued → running → completed ↓ failed → retry (resumes from last successful step) ↓ cancelled → terminalEach step inside the job is idempotent. If a pod restarts mid-step, the reconciler picks up where it left off; the step is re-run, and because steps are idempotent, the cloud API call either fails fast on “already exists” or is a no-op.
The reconciler holds a row-level lock with a TTL that exceeds the worst-case step duration. Lock TTL is per-family; cluster provisioning gets a longer TTL than a Helm install because EKS create takes longer than a helm install.
State carried on InfraConfig
The provisioner uses the job’s config JSON (under InfraConfig) to carry resource-family-specific state across steps. For VMs that means VMs[], VMSecurityGroupID, LoadBalancerID, ScalingGroupID, LaunchTemplateID, ExistingResourceGroup, BootstrapNginxReady, etc.
No new tables per family. Adding a sixth resource type would extend InfraConfig with new fields, not a new schema migration.
Modes
The provisioner supports three modes per job:
| Mode | What it does |
|---|---|
| Create (default) | Provision new infrastructure end-to-end. Standard path. |
| Adopt | Ingest pre-existing customer-managed infrastructure into ZopDay (resource record + connection wiring) without any create-side cloud calls. Currently supported for datastores. Pairs with a credential-update flow that re-stores the secret reference via Config’s StoreDatastoreCredentials RPC. |
| Retry | Resume a failed job from the last successful step. Re-runs whichever step failed. |
For Adopt jobs, teardown is a no-op: ZopDay never owns the lifecycle of adopted resources. Disconnecting an adopted resource only removes ZopDay’s pointer; the underlying datastore stays running.
Pipeline steps
The pipeline is family-specific, but the structure is consistent. For clusters:
stepValidate → stepCreateNetwork → stepCreateIAM → stepCreateCluster → stepBootstrapComponents → stepRegisterSpace → stepFinalizeFor VMs:
stepValidate → stepCreateNetwork → stepCreateIAM → stepCreateLaunchTemplate → stepCreateVMs → [LB sub-steps when LB attached] → stepRegisterSpace → stepFinalizeThe total comes to 7 steps without a load balancer or 11 steps with a load balancer attached.
Steps shared across families (stepCreateNetwork, stepCreateIAM, stepRegisterSpace) live in one implementation and branch on j.ResourceType. Adding a new resource type slots into the same shared steps without forking them.
The cluster and VM pipelines are shown above; the datastore and networking families follow the same shape, with their per-family step lists documented on the Datastores and Networking pages.
Endpoint surface
CRUD on jobs:
POST /provisioning-jobs CreateGET /provisioning-jobs List with filtersGET /provisioning-jobs/{id} Get onePATCH /provisioning-jobs/{id} Partial update (also used for VM op discriminator)DELETE /provisioning-jobs/{id} Cancel + cleanupPOST /provisioning-jobs/{jobID}/retry Retry from last failed stepJob-scoped database CRUD:
GET /provisioning-jobs/{jobID}/databasesPOST /provisioning-jobs/{jobID}/databasesGET /provisioning-jobs/{jobID}/databases/{dbID}DELETE /provisioning-jobs/{jobID}/databases/{dbID}Connections (for service connections + database connections):
GET /provisioning-jobs/{jobID}/connectionsPOST /provisioning-jobs/{jobID}/connectionsDELETE /provisioning-jobs/{jobID}/connections/{connID}
GET /provisioning-jobs/{jobID}/databases/{dbID}/connectionsPOST /provisioning-jobs/{jobID}/databases/{dbID}/connectionsDELETE /provisioning-jobs/{jobID}/databases/{dbID}/connections/{connID}Helm component catalog:
GET /catalog/components List available Helm componentsPOST /provisioning-jobs/install-component Install one onto a registered spaceVM operations (post-provisioning, ride the existing PATCH route with vmOp discriminator):
PATCH /provisioning-jobs/{id}{ "vmOp": "attach_lb" // or "detach_lb"}No new route surface for VM ops; the typed vmOp field on the existing PATCH route handles attach/detach without sprawling the API.
RBAC
Provisioning-related policy categories specific to ZopDay infrastructure:
| Policy prefix | Covers |
|---|---|
space:{view,create,update,delete} | Deployment spaces |
provisioning:{view,create,update,delete} | Provisioning jobs |
service:{view,create,update,delete} | In-cluster Helm components |
deployment:{view,create,update,delete} | Orchestrated through the deployer |
ZopDay also adds an audit-log:view policy for the audit log, granted separately. System roles (Admin, Editor, Viewer) inherit them. Custom roles need explicit grants.
Customer DB safety
ZopDay never mutates customer-managed databases via the provisioner; even when ZopDay created the datastore originally, tier changes and replica scaling stay with the customer’s DBA team. The provisioner’s Pauser registry explicitly excludes rds*, aurora*, cloudsql*, elasticache*, azure-sql, postgres*, mysql* from the pause allowlist.
If you want ZopDay to surface sizing recommendations on a DB without changing it, attach it to an event readiness plan as a monitor-only target. ZopDay computes the recommendation, you implement the change via your normal DB workflow.
Where to look next
- Clusters: EKS / GKE / AKS create flow with hardening defaults
- Datastores: RDS / Cloud SQL / Azure DB / Redis create + adopt
- Networking: VPC, subnets, NAT, peering, DNS
- VMs: production-shape VM environment with NAT outbound + IAM-gated exec
- Components: the Helm component catalog