Terraform
Resources
Resources are an abstraction that allow Terraform to manage infrastructure objects by defining create, read, update, and delete functionality that maps onto API operations. Resource schemas define what fields a resource has, give Terraform metadata about those fields, and define how the resource behaves. Refer to Resources in the Framework documentation for details.
This page explains how to migrate a resource's schema from SDKv2 to the plugin Framework. We also recommend reviewing these additional guides for resources throughout the migration:
- Create, Read, Update, and Delete functions: The resource defines the logic to manage resources with Terraform.
- Import: The resource defines the logic to add a resource to Terraform's state.
- Plan modification: The resource customizes the Terraform plan for known values or behaviors outside the practitioner's configuration.
- State upgrade: The resource updates Terraform state information in advanced use cases.
SDKv2
In SDKv2, resources are defined by the ResourcesMap
field in the schema.Provider
struct, which maps resource names
(strings) to their schema. Each schema is a schema.Resource
struct that includes:
- A
Schema
field, which defines resource attributes - Fields for resource lifecycle functions such as
Create
andCreateContext
- Fields for functions to implement state upgrade (
StateUpgraders
), import (Importer
), and customize diff (CustomizeDiff
)
The following code shows a basic implementation of resource schema with SDKv2.
func New() *schema.Provider {
return &schema.Provider{
ResourcesMap: map[string]*schema.Resource {
"resource_example": resourceExample(),
/* ... */
},
/* ... */
}
}
SDKv2 defines the schema.Resource
struct as follows.
schema.Resource{
Schema map[string]*Schema
SchemaVersion int
MigrateState StateMigrateFunc
StateUpgraders []StateUpgrader
Create CreateFunc
Read ReadFunc
Update UpdateFunc
Delete DeleteFunc
Exists ExistsFunc
CreateContext CreateContextFunc
ReadContext ReadContextFunc
UpdateContext UpdateContextFunc
DeleteContext DeleteContextFunc
CreateWithoutTimeout CreateContextFunc
ReadWithoutTimeout ReadContextFunc
UpdateWithoutTimeout UpdateContextFunc
DeleteWithoutTimeout DeleteContextFunc
CustomizeDiff CustomizeDiffFunc
Importer *ResourceImporter
DeprecationMessage string
Timeouts *ResourceTimeout
Description string
UseJSONNumber bool
}
Framework
In the Framework, you define your provider's resources by adding them to your provider's GetResources
function.
The GetResources
function on your provider.Provider
returns a map from the resource name (string) to a struct that
implements the ResourceType
interface for each resource your provider supports.
The following code shows how you add a resource to your provider with the Framework.
func (p *provider) GetResources(ctx context.Context) (map[string]provider.ResourceType, diag.Diagnostics) {
return map[string]provider.ResourceType{
"resource_example": resourceTypeExample{},
}, nil
}
The provider.ResourceType
interface requires GetSchema
and NewResource
functions.
The GetSchema
function returns a tfsdk.Schema
struct which defines your resource's attributes. This is the same
struct you use to define provider and data source attributes.
The NewResource
function returns a type that you define. The type implements the resource.Resource
interface,
including the CRUD functions for your resource.
The following code shows how you define a provider.ResourceType
which implements these two functions with the
Framework.
type resourceTypeExample struct{}
func (r resourceTypeExample) GetSchema(context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{}, nil
}
func (r resourceTypeExample) NewResource(_ context.Context, p provider.Provider) (resource.Resource, diag.Diagnostics) {
return &resourceExample{}, nil
}
The tfsdk.Schema
is used for defining the schema for providers, resources and data sources. The Framework defines the
tfsdk.Schema
struct as follows.
type Schema struct {
Attributes map[string]Attribute
Blocks map[string]Block
Version int64
DeprecationMessage string
Description string
MarkdownDescription string
}
Refer to the Resources - CRUD functions page in this guide to learn how to
implement the resource.Resource
interface returned by your resource type's NewResource
function.
Migration Notes
Remember the following differences between SDKv2 and the Framework when completing the migration.
- SDKv2 uses
schema.Resource
structs to define resources. These structs have aSchema
field which holds aschema.Schema
to define the resource's attributes and behavior. In the Framework, you define a type that implements theResourceType
interface, which includes aGetSchema
function that returns your resource's schema. - SDKv2 implements a resource's CRUD operations as functions on the
schema.Resource
. In the Framework, you define a type that implements theResource
interface. The resource interface contains the functions that define your resource's CRUD operations.
Example
The following examples show how to migrate portions of the tls provider.
For a complete example,
clone the terraform-provider-tls
repository and compare the resource_private_key.go
file in
v3.4.0 with
v4.0.1.
SDKv2
In SDKv2, the ResourcesMap
field on the schema.Provider
struct holds a map[string]*schemaResource
. A typical
pattern is to implement a function that returns schema.Resource
.
The following example from the provider.go
file defines a tls_private_key
resource within the provider schema.
func New() (*schema.Provider, error) {
return &schema.Provider {
ResourcesMap: map[string]*schema.Resource {
"tls_private_key": resourcePrivateKey(),
/* ... */
The following example from the resource_private_key.go
file defines the resource schema.
func resourcePrivateKey() *schema.Resource {
return &schema.Resource{
CreateContext: createResourcePrivateKey,
DeleteContext: deleteResourcePrivateKey,
ReadContext: readResourcePrivateKey,
Description: "Creates a PEM /* ... */",
Schema: map[string]*schema.Schema{
"algorithm": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(SupportedAlgorithmsStr(), false)),
Description: "Name of the algorithm to use when generating the private key. " +
"Currently-supported values are `RSA`, `ECDSA` and `ED25519`.",
},
/* ... */
Framework
The following shows the same section of provider code after the migration.
This code defines the tls_private_key
resource by mapping the resource name to the privateKeyResourceType
struct.
func (p *provider) GetResources(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) {
return map[string]provider.ResourceType{
"tls_private_key": &privateKeyResourceType{},
/* ... */
This code defines the GetSchema
and NewResource
functions for the privateKeyResourceType
.
func (rt *privateKeyResourceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
Attributes: map[string]tfsdk.Attribute{
// Required attributes
"algorithm": {
Type: types.StringType,
Required: true,
PlanModifiers: []tfsdk.AttributePlanModifier{
resource.RequiresReplace(),
},
Validators: []tfsdk.AttributeValidator{
attribute_validation.OneOf(supportedAlgorithmsAttrValue()...),
},
Description: "Name of the algorithm to use when generating the private key. " +
fmt.Sprintf("Currently-supported values are: `%s`. ", strings.Join(supportedAlgorithmsStr(), "`, `")),
},
/* ... */
func (rt *privateKeyResourceType) NewResource(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) {
return &privateKeyResource{}, nil
}