docs/architecture/providers/parameterized.md
(parameterized-providers)=
Parameterized providers are a Pulumi feature that allows a user to change a
provider's behaviour at runtime. The user generates an SDK by running
pulumi package add or pulumi package gen-sdk with additional command-line
arguments (args). When using pulumi package add, the package is also added to
the project configuration file (Pulumi.yaml). The provider is passed the arguments and generates an SDK
for the user, which also includes custom provider metadata. When the SDK is used
from a Pulumi program, the provider is "parameterized" with the metadata from
within the generated SDK so it's ready to use.
Therefore, when starting a provider to be parameterized, the parameterization call can take two forms:
pulumi package add command), we need to
boot up a provider and parameterize it using only information from the
command-line invocation. In this case, the parameter is a string array
representing the command-line arguments (args).value). This is intended to allow a provider
to store arbitrary data that may be more efficient or practical at program
execution time, after SDK generation has taken place. This value is
base-64-encoded when embedded in the SDK.(provider-implementation)=
Requirements and conditions for "replacement" parameterization:
:::{note} Currently, we only support "replacement" parameterization where generated SDKs don't reference the provider's original SDK. See Replacement and extension parameterization for discussion of what alternative implementations might be possible in the future. :::
For a provider to support parameterization it must implement the
call. The
will either contain the args passed via the
CLI from pulumi package add or pulumi package gen-sdk; or will be passed the
previous generated metadata binary blob. For any fixed set of parameters, the
"args" call will come first and only once; every subsequent call will be of the
"blob" form. will always be called
before either or
are called.
must return a response with the parameterized
package name and version. The name of the parameterized package must be unique
and will be used as the first part of all resource tokens and used to route
RegisterResourceRequests back to the parameterized provider instance. The
version of the parameterized package can be anything the provider would like and
does not have to align to the version of the base provider. The version does not
have any specific purpose right now - it's purely informational, but is
required to be set and to match the parameterized schema too.
Once has been called (with either CLI args or the binary metadata) that provider instance will only be used with that specific parameterization. It will not be re-parameterized or un-parameterized.
Once parameterized, GetSchema can be called by the engine. The GetSchema request will contain the same name and version information as was returned from in the SubpackageName and SubpackageVersion fields, respectively. The generated schema must have the same name and version as the SubpackageName and SubpackageVersion. GetSchema must be callable after either the "args" or "value" mode of parameterize was called. It's expected that GetSchema doesn't have to be fast and that the engine will cache schemas as required.
Once parameterized, the engine may then resume the usual provider lifecycle operations such as and start interacting with resources.
:caption: The lifecycle of parameterization
sequenceDiagram
participant User
participant Engine
participant Provider
User->>+Engine: pulumi package [add|gen-sdk] [provider] [args...]
Engine->>+Provider: Parameterize(args...)
Note right of Provider: Provider now parameterized
Provider-->>Engine: ParameterizeResponse(Name, Version)
Engine->>Provider: GetSchema(Name, Version)
Provider-->>-Engine: Schema with Parameter Value
Engine->>-User: SDK written to local directory
User->>+Engine: pulumi up
Engine->>+Provider: Parameterize(Name, Version, Value)
Note right of Provider: Provider now parameterized
Provider->>Engine: ParameterizeResponse(Name, Version)
loop Provider Operations
Engine->>Provider: Configure/Create/Update/Delete/etc
Provider-->>-Engine: Response
end
Engine-->>-User: exit
Dynamically bridging Terraform providers. The pulumi-terraform-bridge
library can be used to create a Pulumi provider that wraps an existing
Terraform provider. This is a "static" or "offline" process -- provider
authors write a Go program that incorporates the bridge library and the
Terraform provider's codebase to wrap that specific Terraform provider. The
resulting provider can then be published as a Pulumi plugin, and its
method is used to generate language-specific SDKs, which are also published.
pulumi-terraform-provider is a parameterized provider that translates
Pulumi's gRPC to Terraform's gRPC at runtime, allowing it to integrate with
any Terraform provider regardless of its
implementation. pulumi-terraform-provider takes the name of the Terraform
provider to bridge and employs the existing pulumi-terraform-bridge
mechanisms to manage bridging and schema loading in response to the
Parameterize call. Subsequent calls to and other lifecycle methods
will then operate as if the provider had been statically bridged.
Managing Kubernetes clusters with custom resource definitions
(CRDs).
Kubernetes allows users to define their own resource types outside the
standard set of APIs (Pod, Service, and so on). By default, the Pulumi
Kubernetes provider does not know about these resources, and so cannot expose
them in its schema and by extension offer SDK/code completion for interacting
with them. Parameterization offers the possibility for the provider to accept
a parameter describing a set of CRDs, enabling it to then extend its schema to
expose them to programs and SDK generation.
:::{warning}
In the absence of parameterized providers, it is generally safe to assume that a
resource's package name exactly matches the name of the provider
plugin that provides that package. For example, an aws:s3:Bucket
resource could be expected to be managed by the aws provider plugin, which in
turn would live in a binary named pulumi-resource-aws. In the presence of
parameterized providers, this is not necessarily the case. Dynamic Terraform
providers are a great example of this -- if a user were to dynamically bridge an
AWS Terraform provider, the same aws:s3:Bucket resource might be provided by
the terraform provider plugin (with a parameter of aws:<version> or similar,
for example).
:::
(replacement-extension-parameterization)=
Currently, the only kind of parameterization is replacement parameterization. In this mode, the parameterization of the provider replaces the schema and any additional data the provider uses. Once the provider has been parameterized, it will be used for those parameters only; and not without the parameters or with other parameters.
Future enhancements may include the option for a parameterization to be an "extension" of the original schema. Details are yet to be worked out here, but we expect a number of semantic differences from the replacement parameterization, but this mode would be explicitly opted into by providers, so there are no concerns around backward compatibility.