Skip to content

Epic: Provisioning Providers in the AZD Extension Framework #7465

@wbreza

Description

@wbreza

Epic: Provisioning Providers in the AZD Extension Framework

Problem Statement

Today, azd supports only two built-in provisioning providers ΓÇö Bicep and Terraform ΓÇö hardcoded in pkg/azd/default.go. There is no extensibility mechanism for third-party or first-party extensions to supply custom provisioning providers (e.g., Pulumi, CloudFormation, scripts, CDK, custom IaC tools).

The extension framework already supports two analogous extensibility points (Custom Service Targets and Custom Framework Services) using a proven pattern: proto definition → MessageBroker → ExtensionHost fluent API → server-side gRPC handler → core-side adapter → IoC registration. This epic extends that pattern to provisioning providers.

User Personas

Extension Author (Primary)

Who: A developer building an azd extension that provides an alternative IaC tool (e.g., Pulumi provider, script-based provisioner, CDK bridge).
Goals: Register a custom provisioning provider via the ExtensionHost API, implement a well-defined Go interface, have azd seamlessly call their provider for provision, deploy, destroy, and state commands.
Pain Points: Currently must fork azd or use workarounds. No documented, supported API for custom provisioners.

End User (Secondary)

Who: A developer using azd with azure.yaml who installs an extension providing a custom provisioner.
Goals: Set infra.provider: myprov in azure.yaml, run azd provision, and have the extension's provisioner execute transparently.
Pain Points: Limited to Bicep or Terraform. No way to use other IaC tools through azd.

Platform Team (Tertiary)

Who: Azure teams building first-party extensions for new IaC workflows (e.g., deployment scripts, CDK, ARM template generators).
Goals: Leverage the same extensibility framework used for service targets and framework services.

Architecture

ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé                           azd core process                                  Γöé
Γöé                                                                             Γöé
Γöé  ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ    ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ    ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ  Γöé
Γöé  Γöé Provision     Γöé    Γöé provisioning.Manager Γöé    Γöé IoC Container         Γöé  Γöé
Γöé  Γöé Action        ΓöéΓöÇΓöÇΓöÇ>Γöé                      ΓöéΓöÇΓöÇΓöÇ>Γöé                       Γöé  Γöé
Γöé  Γöé (cmd/)        Γöé    Γöé newProvider()         Γöé    Γöé ResolveNamed("myprov")Γöé  Γöé
Γöé  ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ    Γöé serviceLocator.       Γöé    Γöé    Γöé                  Γöé  Γöé
Γöé                      Γöé   ResolveNamed(key)   Γöé    Γöé    Γû╝                  Γöé  Γöé
Γöé                      ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ    Γöé ExternalProvisioning  Γöé  Γöé
Γöé                                                  Γöé   Provider            Γöé  Γöé
Γöé                                                  ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ  Γöé
Γöé                                                       Γöé                     Γöé
Γöé                      ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ                     Γöé
Γöé                      Γû╝                                                      Γöé
Γöé  ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ                                   Γöé
Γöé  Γöé grpcserver.ProvisioningService       Γöé                                   Γöé
Γöé  Γöé  Stream() handler                    Γöé                                   Γöé
Γöé  Γöé    Γö£ΓöÇ MessageBroker[ProvisioningMsg] Γöé                                   Γöé
Γöé  Γöé    Γö£ΓöÇ On(RegisterProvisioningProvider)Γöé                                   Γöé
Γöé  Γöé    ΓööΓöÇ broker.Run(ctx)                Γöé                                   Γöé
Γöé  ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ                                   Γöé
Γöé                  Γöé gRPC bidirectional stream                                 Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöéΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
                   Γöé
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöéΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé                  Γû╝         Extension process                                Γöé
Γöé  ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ    ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ  Γöé
Γöé  Γöé azdext.ProvisioningManager           Γöé    Γöé MyProvisioningProvider   Γöé  Γöé
Γöé  Γöé  broker: MessageBroker               ΓöéΓöÇΓöÇΓöÇ>Γöé Initialize() / Deploy()  Γöé  Γöé
Γöé  Γöé  Register() / Receive() / Ready()    Γöé    Γöé State() / Destroy()      Γöé  Γöé
Γöé  ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ    ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ  Γöé
Γöé  ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ                                   Γöé
Γöé  Γöé ExtensionHost                        Γöé                                   Γöé
Γöé  Γöé .WithProvisioningProvider("myprov",  Γöé                                   Γöé
Γöé  Γöé     factory).Run(ctx)                Γöé                                   Γöé
Γöé  ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ                                   Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ

Key Design Decisions

  1. Follow established patterns: Use the same MessageBroker, ExtensionHost, and IoC patterns as service targets and framework services ΓÇö NOT the bespoke POC approach from PR WIP: Adds support for provision providers via azd extension framework #5381
  2. Single provider per registration: Unlike service targets (which use ComponentManager for per-service instances), provisioning providers are project-level singletons. One provider per WithProvisioningProvider() call.
  3. Provider name as IoC key: The name from registration becomes the IoC named key, matching azure.yaml's infra.provider value
  4. Progress streaming: Deploy, Preview, and Destroy support in-band progress messages via the MessageBroker
  5. Config pass-through: Options.Config map[string]any allows arbitrary extension-specific config from azure.yaml
  6. Relaxed validation: ParseProvider() must accept any string (not just built-in provider names)

Work Items

Layer 1: Foundation (Must complete first)

Layer 2: Core Components (Can parallelize after Layer 1)

Layer 3: Managers & Adapters (Depends on Layer 2)

Layer 4: Integration (Depends on Layer 3)

Layer 5: Validation (Depends on everything)

Follow-up Items

Dependency Graph

graph TD
    A[#7466 Proto Definition] --> B[#7467 Codegen]
    B --> C[#7468 Envelope]
    B --> D[#7469 Interface]
    B --> E[#7471 AzdClient]
    B --> F[#7473 Core Adapter]
    
    C --> G[#7470 Manager]
    D --> G
    E --> G
    
    C --> H[#7474 gRPC Service]
    F --> H
    I[#7475 Capability] --> H
    
    G --> J[#7472 ExtensionHost]
    
    H --> K[#7477 IoC Wiring]
    I --> L[#7476 Middleware]
    
    J --> M[#7479 Demo Extension]
    K --> M
    L --> M
    N[#7478 Validation] --> M
    
    C --> O[#7480 Unit Tests]
    G --> O
    F --> O
    H --> O
    N --> O
    
    M --> P[#7481 Integration Tests]
    O --> P
Loading

Risks

Risk Impact Mitigation
Proto schema changes after initial implementation High ΓÇö affects all layers Design proto carefully upfront; review with team before implementing
Progress streaming reliability over gRPC Medium ΓÇö could cause hangs Follow proven MessageBroker patterns; add timeouts
IoC registration timing (extension connects after provisioning starts) High ΓÇö provider not found Extension middleware already handles readiness; verify startup ordering
ParseProvider relaxation breaks existing validation Low ΓÇö well-scoped change Keep known provider validation; only relax unknown strings
Large surface area across 7+ new files Medium ΓÇö review burden Split into small, focused PRs aligned with layers above

User Flows

Extension Author: Developing a Custom Provisioning Provider

  1. Create extension project with extension.yaml declaring provisioning-provider capability
  2. Implement azdext.ProvisioningProvider interface (7 methods)
  3. Register via host.WithProvisioningProvider("myprov", factory).Run(ctx)
  4. Provider receives Initialize with project path + options (including Config)
  5. Deploy/Preview/Destroy include progress reporter for streaming status updates
  6. State/Parameters/EnsureEnv are called as needed by azd core

End User: Using a Custom Provisioning Provider

  1. Install extension: azd ext install publisher/myprov-extension
  2. Set in azure.yaml: infra: { provider: myprov, config: { ... } }
  3. Run azd provision ΓÇö azd starts extension, extension registers provider
  4. azd resolves myprov from IoC → ExternalProvisioningProvider
  5. All provisioning commands work transparently through the extension

References

Metadata

Metadata

Assignees

Labels

epicLarge multi-issue initiative

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions