Skip to main content Skip to content

Provisioning overview

How ZopDay provisions clusters, datastores, networking, Helm components, and VMs; one state machine, idempotent steps.

6 min read Last updated: 

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 with a 5-step flow (Resource Type, Account & Region, Network, Configuration, Review) and the resource picker showing Kubernetes Cluster, MySQL Database, PostgreSQL Database, and Redis Cache options

Provision Infrastructure wizard; step 1 picks the resource type (cluster, datastore, cache).

What the provisioner creates

FamilyWhat it createsProviders
ClustersEKS / GKE / AKS control plane + workers + cluster IAM + default platform Helm componentsAWS · GCP · Azure
DatastoresRDS / Cloud SQL / Azure DB (Postgres + MySQL); ElastiCache / Memorystore / Azure Cache for RedisAWS · GCP · Azure
NetworkingVPC, 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 componentsHelm catalog (configs/components.yaml) installed via Helm SDK on a registered spaceAny registered space
VMsProduction-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:

kindUsed for
provisioningInfra creation + BYO datastore adoption
remediationAuto-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

Terminal window
draft → queued → running → completed
failed → retry (resumes from last successful step)
cancelled → terminal

Each 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:

ModeWhat it does
Create (default)Provision new infrastructure end-to-end. Standard path.
AdoptIngest 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.
RetryResume 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:

Terminal window
stepValidate → stepCreateNetwork → stepCreateIAM → stepCreateCluster
→ stepBootstrapComponents → stepRegisterSpace → stepFinalize

For VMs:

Terminal window
stepValidate → stepCreateNetwork → stepCreateIAM → stepCreateLaunchTemplate
→ stepCreateVMs → [LB sub-steps when LB attached]
→ stepRegisterSpace → stepFinalize

The 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:

Terminal window
POST /provisioning-jobs Create
GET /provisioning-jobs List with filters
GET /provisioning-jobs/{id} Get one
PATCH /provisioning-jobs/{id} Partial update (also used for VM op discriminator)
DELETE /provisioning-jobs/{id} Cancel + cleanup
POST /provisioning-jobs/{jobID}/retry Retry from last failed step

Job-scoped database CRUD:

Terminal window
GET /provisioning-jobs/{jobID}/databases
POST /provisioning-jobs/{jobID}/databases
GET /provisioning-jobs/{jobID}/databases/{dbID}
DELETE /provisioning-jobs/{jobID}/databases/{dbID}

Connections (for service connections + database connections):

Terminal window
GET /provisioning-jobs/{jobID}/connections
POST /provisioning-jobs/{jobID}/connections
DELETE /provisioning-jobs/{jobID}/connections/{connID}
GET /provisioning-jobs/{jobID}/databases/{dbID}/connections
POST /provisioning-jobs/{jobID}/databases/{dbID}/connections
DELETE /provisioning-jobs/{jobID}/databases/{dbID}/connections/{connID}

Helm component catalog:

Terminal window
GET /catalog/components List available Helm components
POST /provisioning-jobs/install-component Install one onto a registered space

VM operations (post-provisioning, ride the existing PATCH route with vmOp discriminator):

Terminal window
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 prefixCovers
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
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001 · zero-trust· 30% average cloud cost cut· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001 · zero-trust· 30% average cloud cost cut· 4 platforms · 1 console·