Architecture¶
dss-provisioner follows Terraform's plan/apply model. You declare desired state in YAML, the engine computes a diff against actual state, and apply executes the changes.
Core loop¶
YAML config ──► plan() ──► Plan (diff) ──► apply() ──► DSS API calls
▲ │
│ ▼
State file ◄──────────────────────────── Updated state
- Load — Parse
dss-provisioner.yamlinto a validatedConfigobject. Ifmodules:are defined, expand them into resources at this stage - Refresh — Read live DSS state for each tracked resource, update the state file
- Plan — Compare desired resources against state, produce a
PlanofResourceChangeitems - Apply — Execute the plan in dependency order, updating state after each resource
Key components¶
Engine (DSSEngine)¶
The engine is the central orchestrator. It holds references to the provider, state, and handler registry. Its two main methods are:
plan()— Compares desired resources against current state. Optionally refreshes state first (default: yes). Runs a validation pass that checksdepends_onreferences andzonereferences before computing the diff. Returns aPlancontaining a list ofResourceChangeitems, each with an action:create,update,delete, orno-op.apply()— Executes a plan. Processes changes in topological order (respectingdepends_onand inferred dependencies). Updates the state file after each successful operation. If a resource fails, the error is raised with a partialApplyResultso you can see what succeeded.
State file¶
The state file (.dss-state.json by default) tracks:
- Lineage — A UUID identifying this state's history, used for stale-plan detection
- Serial — Incremented on every write, used for concurrency detection
- Resources — A map of resource addresses to their last-known attributes
- Digest — SHA256 hash of resource attributes, used to detect plan staleness
State is written atomically (temp file + rename) and a .backup copy is kept.
Handlers¶
Handlers implement CRUD operations for each resource type. The engine delegates to the appropriate handler based on resource type. Handler categories:
- VariablesHandler — Reads and writes DSS project variables (singleton per project)
- ZoneHandler — Creates, updates, reads, and deletes DSS flow zones
- GitLibraryHandler — Creates, updates, reads, and deletes DSS Git library references
- DatasetHandler — Creates, updates, reads, and deletes DSS datasets
- ExposedObjectHandler — Manages project-level exposed object rules (
exposedObjects) - ForeignHandler — Declares/validates cross-project foreign dataset/folder references
- RecipeHandler — Creates, updates, reads, and deletes DSS recipes
- ScenarioHandler — Creates, updates, reads, and deletes DSS scenarios (step-based and Python)
Dependency graph¶
Resources can declare dependencies explicitly via depends_on or implicitly through recipe inputs/outputs. The engine builds a directed acyclic graph and processes resources in topological order during apply.
For cross-project aliases, the planner normalizes recipe refs to DSS full refs (SOURCE_PROJECT.object) while preserving dependency edges from declared aliases to foreign resources.
If dependencies contain a cycle, the engine raises DependencyCycleError.
Engine semantics¶
- One state file manages one DSS project. Plan/apply will error if the state belongs to a different project (
StateProjectMismatchError). planperforms a refresh by default — reads live DSS state and may persist updates. Disable with--no-refreshorrefresh=False.applyexecutes changes in dependency order with no rollback. If apply fails, state reflects what was completed. TheApplyErrorcarries a partialApplyResult.- Saved plans (via
--out) are checked for staleness via lineage, serial, and state digest before apply. - DSS
${…}variables (e.g.${projectKey}) are resolved transparently during plan comparison so they don't cause false drift.
Preview workflow¶
The preview CLI command composes an ephemeral config overlay and then reuses the normal plan/apply engine:
- Resolve current branch (
--branchcan override auto-detection) - Derive preview project key from base project + branch
- Derive preview state path from base
state_path(for isolation) - Rewrite library entries with
repository: selfto the local gitoriginURL and set checkout to the branch - Create (or reuse) the preview DSS project, then run standard
plan()+apply()against it
This keeps the engine unchanged while isolating preview state and project scope.
Partial failure¶
Apply does not support rollback. If a resource fails mid-apply:
- All previously applied resources remain in place and are tracked in state
- The failing resource is not recorded in state
- An
ApplyErroris raised with the partialApplyResultattached - Re-running
plan+applywill retry only the failed and remaining resources