feat: Add provisioning provider support to extension framework#7482
feat: Add provisioning provider support to extension framework#7482wbreza wants to merge 5 commits intoAzure:mainfrom
Conversation
Introduces extensibility for custom provisioning providers (e.g., Pulumi, CDK, scripts) via the existing gRPC extension framework, following the same MessageBroker-based patterns used by service targets and framework services. New components: - provisioning.proto: bidirectional streaming RPC with 9 request/response pairs for Initialize, State, Deploy, Preview, Destroy, EnsureEnv, and Parameters operations with progress streaming support - ProvisioningEnvelope: MessageEnvelope implementation for broker integration - ProvisioningManager: extension-side manager with factory-based provider creation and handler dispatch - ProvisioningService: server-side gRPC handler with capability verification and IoC container registration - ExternalProvisioningProvider: core-side adapter implementing provisioning.Provider that delegates to extensions via the broker - ExtensionHost.WithProvisioningProvider(): fluent API for extensions to register custom provisioning providers Wiring changes: - Added ProvisioningProviderCapability to extension registry - Added to listenCapabilities in extension middleware - Registered ProvisioningService in IoC container and gRPC server - Extended AzdClient with Provisioning() accessor - Relaxed ParseProvider() to accept any provider kind string - Added Options.Config field for extension-specific configuration Resolves Azure#7465 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Review fixes: - Add empty provider name validation in registration - Fix swallowed structpb.NewStruct error in config conversion - Extract getProvider() helper to eliminate DRY violation in handlers - Add error context wrapping to all ExternalProvisioningProvider methods - Return empty slices instead of nil from PlannedOutputs/Parameters - Use direct indexing in convertFromProtoParameters - Consolidate Register() lock acquisitions into single scope Demo extension: - Add DemoProvisioningProvider to microsoft.azd.demo extension - Register as 'demo' provider with WithProvisioningProvider() - Add provisioning-provider to extension capabilities Test fixes: - Add ProvisioningProviderCapability to ValidCapabilities list - Update TestListenCapabilities assertion count - Add capability to validation test coverage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR extends the existing azd gRPC extension framework to support extension-provided infrastructure provisioning providers, enabling azd core to resolve custom providers (by name) from IoC and invoke them over a bidirectional brokered stream.
Changes:
- Adds a new
ProvisioningServicegRPC stream + message envelope/manager to register and service provisioning providers from extensions. - Introduces a core-side adapter (
ExternalProvisioningProvider) to bridgeprovisioning.Providercalls to the extension over the broker (including progress streaming). - Relaxes
provisioning.ParseProvider()validation and addsinfra.configpass-through support viaprovisioning.Options.Config.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| cli/azd/grpc/proto/provisioning.proto | Defines the provisioning bidi-stream protocol and shared message types. |
| cli/azd/pkg/azdext/provisioning_envelope.go | Implements MessageEnvelope operations for provisioning messages (including progress). |
| cli/azd/pkg/azdext/provisioning_manager.go | Extension-side manager that registers a provider and dispatches incoming provisioning requests to it. |
| cli/azd/pkg/azdext/provisioning.pb.go | Generated protobuf stubs for provisioning messages. |
| cli/azd/pkg/azdext/provisioning_grpc.pb.go | Generated gRPC client/server stubs for provisioning stream. |
| cli/azd/pkg/azdext/extension_host.go | Adds WithProvisioningProvider() and wires provisioning manager into the host lifecycle. |
| cli/azd/pkg/azdext/azd_client.go | Adds AzdClient.Provisioning() service accessor. |
| cli/azd/internal/grpcserver/provisioning_service.go | Server-side stream handler with capability check + IoC registration of external providers. |
| cli/azd/internal/grpcserver/external_provisioning_provider.go | Core adapter implementing provisioning.Provider over the broker stream. |
| cli/azd/internal/grpcserver/server.go (+ tests) | Registers the new provisioning gRPC service on the server. |
| cli/azd/cmd/container.go | Registers ProvisioningService in IoC. |
| cli/azd/cmd/middleware/extensions.go (+ coverage test) | Adds provisioning-provider to listen capabilities. |
| cli/azd/pkg/extensions/registry.go + validate_registry* | Adds/validates the new ProvisioningProviderCapability. |
| cli/azd/pkg/infra/provisioning/provisioning.go (+ test) | Relaxes provider parsing to accept extension-defined kinds. |
| cli/azd/pkg/infra/provisioning/provider.go | Adds Options.Config map[string]any for extension-specific config. |
| cli/azd/extensions/microsoft.azd.demo/* | Demonstrates registering and implementing a provisioning provider in the demo extension. |
jongio
left a comment
There was a problem hiding this comment.
Solid implementation - the MessageBroker + bidi stream pattern is clean and consistent with how service targets and framework services work. The plumbing (IoC, middleware, server registration, extension host API) is all well done.
My comments focus on forward compatibility (making it easier to extend this surface later) and a couple of UX gaps where extensions won't get the same treatment as built-in providers.
|
|
||
| // --- Conversion helpers --- | ||
|
|
||
| func convertToProtoOptions( |
There was a problem hiding this comment.
The Copilot bot already flagged missing tests for provisioning_service.go. Adding to that: the convertFrom*/convertTo* helpers in this file are pure transforms - ideal for table-driven tests and likely to regress when proto messages evolve.
There was a problem hiding this comment.
Added external_provisioning_provider_test.go with table-driven tests for all 5 conversion functions — 17 test cases covering nil inputs, empty values, populated data, secrets, skipped reasons, and various parameter configurations.
…rt tests Proto changes: - Add hint field to ProvisioningStateOptions for deployment lookup - Add name field to ProvisioningOptions for layer scoping - Add PlannedOutputs request/response messages Core changes: - Wire hint from StateOptions through adapter to extension - Wire Options.Name through convertToProtoOptions - Implement PlannedOutputs end-to-end (proto, envelope, manager, adapter) - Update ParseProvider doc comment to match current behavior - Add TODO comments for progress callback console integration - Add scope comment on preview resource-level changes Testing: - Add table-driven tests for all convert helper functions (17 test cases) Demo extension: - Implement PlannedOutputs in DemoProvisioningProvider Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
Description
Introduces extensibility for custom provisioning providers (e.g., Pulumi, CDK, scripts) via the existing gRPC extension framework, following the same
MessageBroker-based patterns used by service targets and framework services.Epic: #7465
Architecture
New Components
grpc/proto/provisioning.protopkg/azdext/provisioning_envelope.goMessageEnvelopefor broker integrationpkg/azdext/provisioning_manager.goProvisioningProvider+ProvisioningManagerinternal/grpcserver/provisioning_service.gointernal/grpcserver/external_provisioning_provider.goExternalProvisioningProviderbridging core to extensionpkg/azdext/provisioning{.pb,.grpc.pb}.goModified Files
pkg/azdext/extension_host.goWithProvisioningProvider()fluent API +Run()lifecyclepkg/azdext/azd_client.goProvisioning()service client accessorpkg/extensions/registry.goProvisioningProviderCapabilityconstantcmd/middleware/extensions.golistenCapabilitiescmd/container.gointernal/grpcserver/server.gopkg/infra/provisioning/provisioning.goParseProvider()accepts any provider kindpkg/infra/provisioning/provider.goOptions.Configfield for extension configKey Design Decisions
MessageBroker,ExtensionHost,ExtensionError(not POC's bespoke approach from WIP: Adds support for provision providers viaazdextension framework #5381)ComponentManagerfor per-service instances), provisioning providers are project-scopedazure.yaml'sinfra.provider: "myprov"resolves viaResolveNamed("myprov")SendAndWaitWithProgress()Options.Config map[string]any→google.protobuf.Structfor extension-specific configExtension Author Usage
End User Usage
Testing
go build ./...passesgo vet ./...cleangofmt -s -l .cleango test ./internal/grpcserver/...passesgo test ./pkg/infra/provisioning/...passesgo test ./pkg/extensions/...passes