Terraform
Provider
Providers are Terraform plugins that define resources and data sources for practitioners to use. You serve your providers with a provider server so they can interact with Terraform.
This page explains how to migrate a provider server, definition, and schema from SDKv2 to the plugin Framework.
Serving the Provider
You must update your provider's main.go
file to serve Framework providers. Refer to Provider Servers in the Framework documentation for details.
Tip
To iteratively migrate individual resources and data sources, refer to muxing for the main.go
implementation instead. The latter provider definition and provider schema sections are still applicable when muxing.
SDKv2
In SDKv2, the provider package's main
function serves the provider by calling plugin.Serve
.
The following code shows a basic implementation for serving an SDKv2 provider.
func main() {
plugin.Serve(
&plugin.ServeOpts{
ProviderFunc: provider.New,
ProviderAddr: "registry.terraform.io/<namespace>/<provider_name>",
},
)
}
Framework
In the Framework, you serve your provider by calling providerserver.Serve
in your provider package's main
function.
Refer to Provider Servers in the Framework documentation for details.
The following code shows an equivalent implementation for serving a provider in the Framework.
func main() {
err := providerserver.Serve(
context.Background(),
provider.New,
providerserver.ServeOpts{
Address: "registry.terraform.io/<namespace>/<provider_name>",
},
)
if err != nil {
log.Fatal(err)
}
}
Provider Definition
Providers built with SDKv2 use a schema.Provider
struct to define their behavior, while Framework providers use a
type that implements the provider.Provider
interface, which you must define. Refer to Providers in the Framework documentation for details.
SDKv2
The ProviderFunc
field on
plugin.ServeOpts
requires a pointer to schema.Provider
. This is typically satisfied by calling a function that
returns a pointer to schema.Provider
.
The ResourcesMap
and DataSourcesMap
fields each contain a map of strings to functions that each return a pointer
to a schema.Resource
struct.
The following example shows a basic implementation of an SDKv2 provider.
func New() *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{},
ConfigureContextFunc: configureContextFunc(),
ResourcesMap: map[string]*schema.Resource{
"resource_example": resourceExample(),
},
DataSourcesMap: map[string]*schema.Resource{
"dataSource_example": dataSourceExample(),
},
/* ... */
}
}
Framework
In the Framework, the second argument to your provider.Serve
function requires a function that returns a type
satisfying the provider.Provider
interface.
The following code shows a typical implementation. In this implementation, the Resources
method returns a slice
of functions that return types that implement the resource.Resource
interface. The DataSources
method returns a
slice of functions that return types that implement the datasource.DataSource
interface.
Refer to the Resources and
Data Sources pages in this guide to implement these functions for your
provider.
type exampleCloudProvider struct {
}
func New() provider.Provider {
return &exampleCloudProvider{}
}
func (p *exampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "examplecloud"
}
func (p *exampleCloudProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{}
}
func (p *exampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
}
func (p *exampleCloudProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource {
func() resource.Resource {
return resourceExample{}
},
}
}
func (p *exampleCloudProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource {
func() datasource.DataSource {
return dataSourceExample{}
},
}
}
Migration Notes
Remember the following differences between SDKv2 and the Framework when completing the migration.
- In SDKv2, your provider's
New
function returns aschema.Provider
struct. In the Framework,New
returns a type that you define which satisfies theprovider.Provider
interface. - In SDKv2,
Schema
is a field onschema.Provider
that containsmap[string]*schema.Schema
, which maps attribute names toschema.Schema
structs. In the Framework,Schema
is a method you define on your provider'sprovider.Provider
interface that returns your provider'sschema.Schema
struct. - In SDKv2,
ConfigureContextFunc
is a field onschema.Provider
containing a function that configures the provider. In the Framework,Configure
is a function you define on your provider that configures your provider. - In SDKv2,
ResourcesMap
is a field onschema.Provider
containingmap[string]*schema.Resource
, which maps resource names toschema.Resource
structs. In the Framework,Resources
is a method you define on your provider that returns[]func() resource.Resource
, which creates resource types that you define, which satisfy theresource.Resource
interface. - In SDKv2,
DataSourcesMap
is a field onschema.Provider
containingmap[string]*schema.Resource
, which maps data source names toschema.Resource
structs (data sources and resources both useschema.Resource
). In the Framework,DataSources
is a method you define on your provider that returns[]func() datasource.DataSource
, which creates data source types that you define, which satisfy thedatasource.DataSource
interface.
Example
SDKv2
The following example shows how to set up a provider schema, configuration, resources, and data sources using SDKv2.
func New() (*schema.Provider, error) {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"attribute": {
/* ... */
},
},
ConfigureContextFunc: configureProvider,
ResourcesMap: map[string]*schema.Resource{
"exampleResource": exampleResource(),
/* ... */
},
DataSourcesMap: map[string]*schema.Resource{
"exampleDataSource": exampleDataSource(),
/* ... */
},
}, nil
}
Framework
The following shows the same section of provider code after the migration.
var _ provider.Provider = (*exampleProvider)(nil)
func New() provider.Provider {
return &exampleProvider{}
}
func (p *exampleProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
func() resource.Resource {
return &exampleResource{}
},
/* ... */
}
}
func (p *exampleProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
func() datasource.DataSource {
return &exampleDataSource{}
},
/* ... */
}
}
func (p *exampleProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"attribute": schema.SingleNestedBlock{
/* ... */
},
},
}
}
func (p *exampleProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "example"
}
func (p *exampleProvider) Configure(_ context.Context, _ provider.ConfigureRequest, resp *provider.ConfigureResponse) {
/* ... */
}
Provider Schema
A provider schema defines the attributes and behaviors of the provider itself. For example, a provider that connects to a third-party API may define attributes for the base URL or a required authentication token.
SDKv2
In SDKv2, you implement a provider Schema by populating the Schema
field on the schema.Provider
struct. The Schema
field contains a map[string]*schema.Schema
. Each map entry represents the name of the attribute and pointer to a
schema.Schema
struct that defines that attribute's behavior.
The following example defines the provider schema in the Schema
field within the schema.Provider
struct.
func New() *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
/* ... */
},
Framework
In the Framework, the Schema
method returns the provider schema. The Schema
method is part of the
provider.Provider
interface that your provider must implement. Schema
returns a struct containing fields for
Attributes
and Blocks
. These Attributes
and Blocks
contain map[string]schema.Attribute
and
map[string]schema.Block
, respectively. Refer to Providers - Schema in the
Framework documentation for details.
The following code shows the Schema
method, which returns the provider schema.
func (p *ExampleCloudProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
/* ... */
}
}
Refer to the Attributes and Blocks pages in this migration guide to learn how to migrate those fields to the Framework.
Migration Notes
Remember the following differences between SDKv2 and the Framework when completing the migration.
- In SDKv2,
schema.Schema
is a struct that defines attributes and behaviors (e.g.,Type
,Optional
). In the Frameworkschema.Schema
is a struct that includes attributes and blocks.
Example
This example shows how to use a nested block and a nested attribute for the SDKv2 and Framework examples, respectively. Refer to the Blocks with Computed Fields page in this guide for more details.
SDKv2
The following example shows the configuration of the example_attribute
attribute for the provider's example_block
configuration block.
Schema: map[string]*schema.Schema{
"example_block": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"example_attribute": {
Type: schema.TypeString,
Optional: true,
ValidateDiagFunc: validation.ToDiagFunc(validation.IsURLWithScheme(SupportedProxySchemesStr())),
ConflictsWith: []string{"example_block.0.another_attribute"},
},
/* ... */
Framework
The following shows the same section of provider code after the migration.
This code implements the example_attribute
attribute for the example_Block
block with the Framework.
func (p *exampleProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
/*...*/
Blocks: map[string]schema.Block{
"example_block": schema.ListNestedBlock{
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"example_attribute": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
attribute_validator.UrlWithScheme(supportedProxySchemesStr()...),
stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("another_attribute")),
},
},
},
Validators: []validator.List{
listvalidator.SizeAtMost(1),
},