Providers
Relevant source files
The following files were used as context for generating this wiki page:
Providers are the core components in Pulumi that are responsible for understanding API interactions and managing the lifecycle of resources for a specific cloud or service (e.g., AWS, Azure, Kubernetes). They act as a bridge between Pulumi's declarative infrastructure-as-code model and the concrete API calls required to create, read, update, and delete resources in the target environment.
Each provider is a separate plugin that the Pulumi engine communicates with via gRPC. This architecture allows Pulumi to be extended to support any service with a manageable API. Users can interact with providers implicitly by creating resources from a provider's package, or explicitly by instantiating a provider resource and passing it to other resources.
Provider Model Architecture
The interaction between the Pulumi engine and a provider plugin is mediated by a ProviderHost and a Provider interface. The engine loads the necessary provider plugins for a deployment and uses a ProviderHost to manage communication. The provider plugin, in turn, implements the Provider interface to expose resource lifecycle operations.
Sources: pkg/resource/provider/host.go
Core Components
| Component | Description | Source File |
|---|---|---|
Provider | The gRPC server interface that every resource provider plugin must implement. It defines methods for resource lifecycle management like Create, Read, Update, Delete, Check, Diff, and Configure. | pkg/resource/provider/host.go:102-177 |
Host | The gRPC client interface that a provider plugin uses to communicate back to the Pulumi engine. It provides functionalities like logging and obtaining configuration. | pkg/resource/provider/host.go:49-56 |
ProviderResource | The base type for provider resources defined in a Pulumi program (e.g., in Go). It represents an explicit instance of a provider. | sdk/go/pulumi/provider.go:21-24 |
Registry | A deployment-time component that manages provider instances. It handles requests for providers, resolving whether to use a default provider or an explicitly configured one. | pkg/resource/deploy/providers/registry.go:32-40 |
Engine-Provider Interaction
The following diagram illustrates the high-level interaction between the Pulumi Engine and a Provider Plugin.
This diagram shows the Pulumi Engine communicating with a Provider Plugin via a Provider Host, which manages the plugin's lifecycle. The plugin implements the Provider interface and uses a Host client to call back to the engine.
Sources: pkg/resource/provider/host.go
The Provider Interface
The Provider interface is the contract that all resource provider plugins must fulfill. It is defined as a gRPC service and includes methods for every stage of a resource's lifecycle.
Sources: pkg/resource/provider/host.go:102-177
| Method | Description |
|---|---|
Configure | Configures the provider with credentials and other settings. |
CheckConfig | Validates the provider's configuration. |
DiffConfig | Checks for differences in the provider's configuration that would require replacement. |
Check | Validates the inputs for a resource before a create or update operation. |
Diff | Compares the current state of a resource with a new desired state to determine what changes are needed. |
Create | Creates a new physical resource. |
Read | Reads the current state of an existing physical resource. |
Update | Updates an existing physical resource. |
Delete | Deletes a physical resource. |
Invoke | Executes a function (data source) exposed by the provider. |
Construct | Constructs a component resource, which is a logical grouping of other resources. |
GetSchema | Returns the provider's schema. |
Cancel | Cancels any ongoing provider operations. |
Provider Definition in a Pulumi Program
Within a Pulumi program, a provider can be explicitly instantiated. This is useful when you need to manage resources in multiple regions or with different credentials. The Go SDK provides the ProviderResource struct and the NewProvider function for this purpose.
Sources: sdk/go/pulumi/provider.go
ProviderResource Struct
This struct is embedded in all custom provider resources.
// sdk/go/pulumi/provider.go:21-24
type ProviderResource struct {
CustomResourceState
version string
}
NewProvider Function
This function is used to create a new explicit provider instance. It registers a new provider resource with the Pulumi engine.
// sdk/go/pulumi/provider.go:31-48
func NewProvider(ctx *Context, pkg, name string, args Resource, opts ...ResourceOption) (ProviderResource, error) {
// ... implementation ...
err := ctx.RegisterResource(resType, name, args, &res, opts...)
// ...
return res, nil
}
The NewProvider function takes the package name (e.g., "aws"), a resource name for the provider instance, arguments for configuration, and resource options.
Provider Registration and Resolution
For the Pulumi engine to use a provider, the provider package must first register itself with the runtime, and then during a deployment, the engine must be able to resolve resource requests to the correct provider instance.
SDK-Level Registration
When a Pulumi package for a language like Node.js is generated, it includes code to register itself with the Pulumi runtime. This typically involves a constructProvider function that can instantiate the provider.
The following snippet from the Node.js code generator shows how a package registers its provider constructor.
// pkg/codegen/nodejs/gen.go:2308-2317
pulumi.runtime.registerResourcePackage("example", {
version: utilities.getVersion(),
constructProvider: (name: string, type: string, urn: string): pulumi.ProviderResource => {
if (type !== "pulumi:providers:example") {
throw new Error(`unknown provider type ${type}`);
}
return new Provider(name, <any>undefined, { urn });
},
});
This registration allows the Pulumi engine to call constructProvider to create a new provider instance when required.
Sources: pkg/codegen/nodejs/gen.go:2308-2317
Deployment-Time Resolution
During a deployment (pulumi up), the providers.Registry is responsible for managing all provider instances. When a resource is created, the engine asks the registry for the appropriate provider based on the resource's type and any explicit provider specified.
The Registry can resolve a provider reference, which might be a default provider for a package or an explicitly instantiated one.
Key functions in the registry include:
NewRegistry: Creates a new provider registry.GetProvider: Retrieves a provider for a given package, creating a default one if it doesn't exist.ResolveReference: Resolves a provider reference to a specific provider instance.
Sources: pkg/resource/deploy/providers/registry.go:32-72
Provider Resolution Flow
This diagram shows the sequence of events when creating a resource that requires provider resolution.
This sequence shows the engine requesting a provider from the registry, using that provider to validate inputs (Check), and then creating the resource (Create).
Provider Configuration
Providers can be configured at the project level within the Pulumi.yaml file. This is particularly useful for setting a specific version of a provider plugin or specifying a local path for development purposes.
The plugins section in Pulumi.yaml allows for overriding plugin selection.
# tests/integration/explicit_provider/Pulumi.yaml:1-6
name: explicit_provider
runtime: nodejs
description: A test of the ability to override a provider.
plugins:
providers:
- name: random
path: ../provider
In this example, the random provider is configured to be loaded from a local path ../provider instead of being downloaded from the Pulumi Registry.
Sources: sdk/go/common/workspace/project.json:161-189, tests/integration/explicit_provider/Pulumi.yaml:1-6
Conclusion
Providers are fundamental to Pulumi's operation, acting as the essential link between the user's desired state defined in code and the actual state of resources in a cloud environment. They encapsulate the logic for all resource lifecycle operations, from configuration and validation to creation and deletion. The provider model, based on gRPC plugins, is highly extensible, allowing the Pulumi ecosystem to support a vast and growing number of services. Understanding how providers are defined, registered, configured, and resolved is key to comprehending the inner workings of Pulumi.