Skip to content

IaCProvisioningService

Target

This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.

Bounded context BC-25 Provisioning & Reconciliation
Platform / plane Runtime Cloud / Execution
Deployment granularity module of host · host RuntimeCloudHost
Status target · ConnectSoft.Factory.RuntimeCloud.Provisioning
Built from connectsoft-microservice · libraries: connectsoft-extensions-saas-abstractions, connectsoft-extensions-messaging-model, connectsoft-extensions-persistence-model-nhibernate, connectsoft-extensions-scheduler-model-hang-fire
Decisions ADR-0004, ADR-0015
Traceability FR-08 FUX-05 NFR-08 NFR-09 XL-04 XL-10

Purpose and responsibilities

IaCProvisioningService is where the Factory changes infrastructure, and the only place. A deployment specification is desired state: a reference to the IaC program and its version in Git (the repository's InfrastructureModel Pulumi project, ADR-0004), the release it deploys, the strategy, and configuration and secret references resolved at apply time from the Config Platform and the Secret Broker. A provisioning run plans the specification against the target and records the plan (adds, changes, deletes, inputs hash, program version), waits for the promotion's production-class approval when the environment is production, applies with the runner's workload identity, and records the apply receipt (outputs, duration, result) with logs as artifacts. The GitOps reconciler re-plans every environment on a schedule: non-destructive differences outside production are applied where policy allows; anything destructive or in production becomes a reconciliation proposal for an Operator.

It absorbs DeploymentManifestService, DeploymentService and GitOpsSyncService.

Context and boundaries

flowchart LR
    S["IaCProvisioningService"]
    EnvironmentPromotionService["EnvironmentPromotionService"] -->|event| S
    StudioBff["StudioBff"] -->|sync-http| S
    S -->|sync-http| ext_pulumi["ext-pulumi"]
    S -->|grpc| SecretBrokerService["SecretBrokerService"]
    S -->|sync-http| ext_config_platform["ext-config-platform"]
    S -->|grpc| PolicyEngineService["PolicyEngineService"]
    S -->|grpc| RunControlService["RunControlService"]
    S -->|grpc| ArtifactService["ArtifactService"]
    S -. "SpecificationDeclared" .-> E_SpecificationDeclared(("event"))
    S -. "ProvisioningPlanned" .-> E_ProvisioningPlanned(("event"))
    S -. "ProvisioningApplied" .-> E_ProvisioningApplied(("event"))
    S -. "ProvisioningFailed" .-> E_ProvisioningFailed(("event"))
Hold "Alt" / "Option" to enable pan & zoom

The service never edits a program: desired state lives in Git and the specification records which version was acted on. A plan is always recorded before an apply; a re-run is a new run; receipts are immutable and audited.

Domain model

DeploymentSpecification — The desired state of one environment or workload: a reference to the IaC program and its version in Git (the repository's InfrastructureModel project), the release it deploys, strategy, configuration references (Config Platform) and secret references (Secret Broker); every applied version is kept. (catalog entry)

Field Type Required Description
specificationId guid yes
tenantId string yes
projectId string yes
environmentId string yes
kind enum:SpecificationKind yes
programRef string yes repository + path of the Pulumi program
programVersion string yes Commit of the program.
releaseId guid no
strategy string no
configRefs json yes Config Platform keys by reference.
secretRefs json yes Secret references; never values.
version int yes
declaredAt datetime yes

Invariants:

  • Desired state lives in Git; the specification records which version was acted on and never edits the program.
  • Secrets and configuration are references resolved by the runner at apply time from the Secret Broker and the Config Platform.

Events: SpecificationDeclared · Tables: DeploymentSpecifications · Repository: DeploymentSpecificationRepository

ProvisioningRun — One plan-and-apply of a specification version against a target: plan receipt (resources to add, change, delete), the approval when the environment class is production, apply receipt (outputs, duration, result), the promotion that requested it, and the artifacts of logs and state. (catalog entry)

Field Type Required Description
provisioningRunId guid yes
tenantId string yes
projectId string yes
environmentId string yes
specificationId guid yes
specificationVersion int yes
kind enum:ProvisioningKind yes
promotionId guid no
approvalId guid no
planReceipt json no adds, changes, deletes, inputs hash, program version
applyReceipt json no outputs, duration, result, runner version
state enum:ProvisioningState yes
logsRef string no
startedAt datetime yes
completedAt datetime no

Invariants:

  • An apply against a production environment needs the promotion's approval (production class) or, for a baseline or reconciliation, a policy allow with evidence; the plan is recorded before any apply.
  • A plan with deletes in production is never applied automatically by reconciliation; it becomes a reconciliation proposal.
  • Receipts are immutable; a re-run is a new provisioning run.
stateDiagram-v2
    Planned --> AwaitingApproval : ProductionWithoutApproval
    Planned --> Applying : ApprovedOrAllowed
    AwaitingApproval --> Applying : ApprovalGranted
    AwaitingApproval --> Rejected : ApprovalRejectedOrExpired
    Applying --> Applied : RunnerSucceeded
    Applying --> Failed : RunnerFailed
    Planned --> Cancelled : Cancel
Hold "Alt" / "Option" to enable pan & zoom

Events: ProvisioningPlanned, ProvisioningApplied, ProvisioningFailed · Tables: ProvisioningRuns · Repository: ProvisioningRunRepository

erDiagram
    DeploymentSpecification {
        guid specificationId PK
        string tenantId
        string projectId
        string environmentId
        enum_SpecificationKind kind
        string programRef
        string programVersion
        guid releaseId
        string strategy
        json configRefs
        json secretRefs
        int version
        datetime declaredAt
    }
    ProvisioningRun {
        guid provisioningRunId PK
        string tenantId
        string projectId
        string environmentId
        guid specificationId
        int specificationVersion
        enum_ProvisioningKind kind
        guid promotionId
        guid approvalId
        json planReceipt
        json applyReceipt
        enum_ProvisioningState state
        string logsRef
        datetime startedAt
        datetime completedAt
    }
Hold "Alt" / "Option" to enable pan & zoom

Entities and value objects

None modelled

No entities or value objects are modelled for this item yet.

Data model and storage

Store Role Engine / profile Tables
Runtime Cloud store primary azure-sql / nhibernate-sqlserver DeploymentSpecifications, ProvisioningRuns
Artifact content store blob blob / azure-blob —
Table Owner Columns Indexes
dbo.DeploymentSpecifications DeploymentSpecification 13 1
dbo.ProvisioningRuns ProvisioningRun 15 2

Full DDL: appendix.

APIs

Method Path Operation Scope Side effects Idempotency Gateway Summary
GET /factory/provisioning/specifications ListSpecifications factory.provisioning.read read natural GW-03 Desired-state specifications per environment with versions and program references.
GET /factory/provisioning/runs ListProvisioningRuns factory.provisioning.read read natural GW-03 Provisioning runs by environment, kind and state with plan and apply receipts.
GET /factory/provisioning/runs/{provisioningRunId} GetProvisioningRun factory.provisioning.read read natural GW-03 One run with its plan, approval, apply receipt and logs.
POST /factory/provisioning/runs PlanProvisioning factory.provisioning.apply production key-header GW-03 Plan a specification version against an environment (baseline, reconciliation, decommission); production applies wait for the approval (Operator, Platform admin).
POST /factory/provisioning/runs/{provisioningRunId}/cancel CancelProvisioning factory.provisioning.apply shared-write natural GW-03 Cancel a planned run before apply.
gRPC service Method Streaming Visibility Side effects Summary
Provisioning GetCurrentSpecification none internal read The specification version last applied to an environment (promotion, inventory and fleet read it).

Messages

Event Topic Scope / v Aggregate Consumers Summary
SpecificationDeclared provisioning.specifications.v1.specification-declared integration / 1 DeploymentSpecification RuntimeEnvironmentService, StudioBff, AuditService A desired-state version exists for an environment.
ProvisioningPlanned provisioning.runs.v1.provisioning-planned integration / 1 ProvisioningRun StudioBff, AuditService, EnvironmentPromotionService A plan exists (adds, changes, deletes) and may await approval.
ProvisioningApplied provisioning.runs.v1.provisioning-applied integration / 1 ProvisioningRun ExecutionCapacityService, EnvironmentPromotionService, RuntimeEnvironmentService, EnvironmentService, StudioBff, AuditService, DashboardService The desired state was applied; outputs are recorded.
ProvisioningFailed provisioning.runs.v1.provisioning-failed integration / 1 ProvisioningRun EnvironmentPromotionService, RuntimeEnvironmentService, StudioBff, AuditService, AlertRuleService The apply failed; the receipt names the failing resource.

SpecificationDeclared payload:

Field Type Required Description
specificationId guid yes
tenantId string yes
environmentId string yes
kind enum:SpecificationKind yes
version int yes
programVersion string yes

ProvisioningPlanned payload:

Field Type Required Description
provisioningRunId guid yes
tenantId string yes
environmentId string yes
kind enum:ProvisioningKind yes
promotionId guid no
planSummary json yes

ProvisioningApplied payload:

Field Type Required Description
provisioningRunId guid yes
tenantId string yes
projectId string yes
environmentId string yes
kind enum:ProvisioningKind yes
promotionId guid no
specificationVersion int yes
outputs json yes

ProvisioningFailed payload:

Field Type Required Description
provisioningRunId guid yes
tenantId string yes
environmentId string yes
kind enum:ProvisioningKind yes
promotionId guid no
reason string yes
Command Handled by Result events Summary
PlanProvisioning ProvisioningRun ProvisioningPlanned
CancelProvisioning ProvisioningRun —
Event Producer Handler Purpose
PromotionApproved EnvironmentPromotionService ProvisionPromotion A promotion hands over its desired state; the approval is reused for the production apply.
EnvironmentCreated EnvironmentService ProvisionBaseline A new environment gets its baseline specification planned.
ApprovalDecided RunControlService ApplyApproval Baseline and reconciliation applies in production wait for their approval.

Workers and jobs

Worker Trigger Output events Retry Idempotency key Summary
Planner event ProvisioningPlanned exponential provisioningRunId + plan Resolves the program version, configuration and secret references and runs the IaC planner; records the plan receipt; routes to approval when required.
Applier event ProvisioningApplied, ProvisioningFailed none provisioningRunId + apply Runs the IaC apply for approved or allowed runs with the runner's workload identity; records outputs and logs as artifacts; reports applied or failed.
GitOpsReconciler schedule 0 */4 * * * ProvisioningPlanned, ProvisioningApplied fixed environmentId + window Re-plans the declared specification of every environment on a schedule; applies non-destructive differences automatically where policy allows, and turns destructive or production differences into reconciliation proposals.

Actors and grains

None modelled

No grains are modelled for this item yet.

Sagas and long-running flows

None modelled

No sagas are modelled for this item yet.

stateDiagram-v2
    [*] --> Planned
    Planned --> AwaitingApproval: ProductionWithoutApproval
    Planned --> Applying: ApprovedOrAllowed
    AwaitingApproval --> Applying: ApprovalGranted
    AwaitingApproval --> Rejected: ApprovalRejectedOrExpired
    Applying --> Applied: RunnerSucceeded
    Applying --> Failed: RunnerFailed
    Planned --> Cancelled: Cancel
Hold "Alt" / "Option" to enable pan & zoom
sequenceDiagram
    participant E as EnvironmentPromotionService
    participant P as IaCProvisioningService
    participant SB as SecretBrokerService
    participant CP as Config Platform
    participant R as Pulumi runner
    participant I as RuntimeEnvironmentService
    E-)P: PromotionApproved (desired state, approval)
    P->>P: declare specification version, plan
    P->>SB: resolve secret references (lease-bound)
    P->>CP: resolve configuration references
    P->>R: apply (program version, inputs)
    R-->>P: outputs, duration, result
    P-)E: ProvisioningApplied
    P-)I: ProvisioningApplied → observe after apply
Hold "Alt" / "Option" to enable pan & zoom

Options and configuration

Section Key Type Default Reloadable Secret Summary
RuntimeCloud:Provisioning AutoApplyNonDestructive bool true yes no Reconciliation applies adds and changes automatically outside production.
RuntimeCloud:Provisioning ApplyTimeoutMinutes int 45 yes no Runner timeout per apply.

Metrics and observability

Metric Instrument Unit Dimensions Summary
connectsoft.factory.provisioning.runs counter {run} tenant, kind, state Provisioning runs by kind and outcome.
connectsoft.factory.provisioning.apply_duration histogram s kind Apply duration.
connectsoft.factory.provisioning.reconciliation_diffs counter {diff} tenant, destructive Differences found by reconciliation.

Security

Authentication client-credentials
Scopes factory.provisioning.read (Read specifications and runs.); factory.provisioning.apply (Plan, apply and cancel (Operator, Platform admin; promotions through the hand-off).)
Roles Operator, PlatformAdmin, Observer
Tenant isolation row-filter
Data classification confidential
Max side-effect class production
Secrets iac-runner-identity (key-vault, rotate 30 d)

Dependencies

Outbound

Target Kind Purpose Failure mode Required
ext-pulumi sync-http Resource provisioning through the runner. fail-fast yes
SecretBrokerService grpc Secret references resolved at apply time. fail-fast yes
ext-config-platform sync-http Configuration references. degrade yes
PolicyEngineService grpc Deployment-domain decisions for baseline and reconciliation applies. fail-fast yes
RunControlService grpc Approvals for production applies not covered by a promotion. fail-fast yes
ArtifactService grpc Plan and apply logs and state snapshots. fail-fast yes

Inbound

Target Kind Purpose Failure mode Required
EnvironmentPromotionService event Desired-state hand-offs. — yes
StudioBff sync-http Provisioning views and operator actions. — yes

Failure and recovery

Scenario Detection Recovery Data impact RTO (min)
Apply fails mid-way runner result receipt records the partial state; the promotion rolls back; reconciliation proposes the fix; nothing is retried blindly partial infrastructure change 60
Program version not found planner error run Failed with the reference; the specification is corrected in Git none 0

NFR targets

Target Class value (pilot-batch) Override
latency_p95_ms 0 —
availability_pct 99.5 —
throughput_rps 10 —
rpo_minutes 15 —
rto_minutes 240 —
cost_class medium —

Deployment

Granularity module of host · host RuntimeCloudHost
Topologies saas-default, hybrid, on-prem, hybrid-compute
Runtime —; replicas —–—
Ports —

Current implementation

Each repository's pipeline runs its own Pulumi program with Azure DevOps environment approvals; thirteen Pulumi.yaml stacks exist across the estate. No specification registry, receipt or reconciler exists.

Later capabilities

Policy-as-code checks on plans (deny public endpoints, enforce tags) before apply; cost estimates per plan from the FinOps projections; ephemeral preview environments per change proposal.

Decisions and traceability

Family Ids
FR FR-08
FUX FUX-05
NFR NFR-08, NFR-09
XL XL-04, XL-10