Terraform
Providers
Providers are Terraform plugins that define resources and data sources for practitioners to use. Providers are wrapped by a provider server for interacting with Terraform.
Implement Provider Interface
Any type that fills the tfsdk.Provider interface can be a provider. The provider interface has four required methods: GetSchema
, Configure
, GetResources
, and GetDataSources
. We recommend that you define a struct
type to fill this interface.
An example provider implementation with a field storing an example API client:
// Ensure the implementation satisfies the tfsdk.Provider interface.
var _ tfsdk.Provider = &exampleProvider{}
// exampleProvider implements the tfsdk.Provider interface. This implementation
// will be passed to data sources and resources as the tfsdk.Provider parameter
// in each NewDataSource and NewResource method call respectively.
type exampleProvider struct{
// Typically fields including API clients or configuration necessary for
// resource and data source operations. For example:
Client exampleApiClient
// version is an example field that can be set with an actual provider
// version on release, "dev" when the provider is built and ran locally,
// and "test" when running acceptance testing.
Version string
}
// GetSchema satisfies the tfsdk.Provider interface for exampleProvider.
func (p *exampleProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
Attributes: map[string]tfsdk.Attribute{
// Provider specific implementation.
},
}, nil
}
// Configure satisfies the tfsdk.Provider interface for exampleProvider.
func (p *exampleProvider) Configure(ctx context.Context, req tfsdk.ConfigureProviderRequest, resp *tfsdk.ConfigureProviderResponse) {
// Provider specific implementation.
}
// GetDataSources satisfies the tfsdk.Provider interface for exampleProvider.
func (p *exampleProvider) GetDataSources(ctx context.Context) (map[string]tfsdk.DataSourceType, diag.Diagnostics) {
return map[string]tfsdk.DataSourceType{
// Provider specific implementation
}, nil
}
// GetResources satisfies the tfsdk.Provider interface for exampleProvider.
func (p *exampleProvider) GetResources(ctx context.Context) (map[string]tfsdk.ResourceType, diag.Diagnostics) {
return map[string]tfsdk.ResourceType{
// Provider specific implementation
}, nil
}
Conventionally, many providers also create a helper function named New
which can simplify provider server implementations.
func New(version string) func() tfsdk.Provider {
return func() tfsdk.Provider {
return &exampleProvider{
Version: version,
}
}
}
GetSchema
GetSchema
returns a
schema that describes the provider's
configuration block. This configuration block is used to offer practitioners
the opportunity to supply values to the provider and configure its behavior,
rather than needing to include those values in every resource and data source.
It is usually used to gather credentials, endpoints, and the other data used to
authenticate with the API, but it is not limited to those uses.
provider "example" {
endpoint = "https://example.test/"
api_token = "v3rYs3cr3tt0k3n"
}
Even if the provider does not want to accept practitioner configuration, it must return an empty schema.
The schema is meant to be immutable. It should not change at runtime, and should consistently return the same value.
Configure
Configure
handles and stores the
values the practitioner entered in the provider's configuration block. This
can mean creating the API client, storing the data on the type that
implements the provider interface, or otherwise handling the values. This is
the only time those values will be made available to the provider, so they
need to be persisted if the provider will need to reference them from within
a resource or data source. This is why we recommend using a struct
to represent the provider, as it can hold multiple values in a strongly-typed
way.
Unknown Values
Not all values are guaranteed to be
known when Configure
is called.
For example, if a practitioner interpolates a resource's unknown value into the block,
that value may show up as unknown depending on how the graph executes:
resource "example_foo" "bar" {
id = 123
}
provider "example" {
endpoint = "https://example.test/"
api_token = example_foo.bar.name
}
In the example above, example_foo.bar.name
is a read-only field on
example_foo.bar
that won't be set until after example_foo.bar
has been
applied. So the Configure
method for the provider may report that the value
is unknown. You can choose how your provider handles this. If
some resources or data sources can be used without knowing that value, it may
be worthwhile to emit a warning and
check whether the value is set in resources and data sources before attempting
to use it. If resources and data sources can't provide any functionality
without knowing that value, it's often better to return an
error, which will halt the apply.
GetResources
GetResources
returns a map of resource
types. The keys of the
map entries must be the name of the resource as it would appear in the
configuration, including the provider prefix.
The list of resources is meant to be immutable. It should not change at runtime, and should consistently return the same values.
GetDataSources
GetDataSources
returns a map of data
source types. The
keys of the map entries must be the name of the data source as it would appear
in the configuration, including the provider prefix.
The list of data sources is meant to be immutable. It should not change at runtime, and should consistently return the same values.
Further Provider Capabilities
- Validation helps practitioners understand the required syntax, types, and acceptable values for your provider.