Import
Note: The Plugin Framework is in beta.
Practitioners can use the terraform import
command to let Terraform
begin managing existing infrastructure by importing an existing resource into their Terraform project's state. A
resource's importer function implements the logic to add a resource to Terraform's state. Refer to
Resources - Import in the Framework documentation for details.
This page explains how to migrate import functions from SDKv2 to the plugin Framework.
SDKv2
In SDKv2, the Importer
field on the schema.Resource
defines how the provider imports resources to Terraform's
state. The following example implements resource import with SDKv2.
func resourceExample() *schema.Resource {
return &schema.Resource{
Importer: &schema.ResourceImporter{
StateContext: StateContextFunc,
},
/* ... */
The StateContextFunc
is the function called to import a resource into Terraform state. Any operations that
are needed to import the resource take place within this function and may result in the mutation of the ResourceData
that is passed into the function. The return value is a slice of schema.ResourceData
. This slice might be as simple as returning the ResourceData
that was passed into the function, or it may involve multiple fan out to multiple resources, such as AWS security groups.
Framework
In the Framework, you implement the ResourceWithImportState
interface on your resource.Resource
type to allow
users to import a given resource. This interface requires that your type implement a ImportState
function.
The following code shows how you define an ImportState
function with the Framework.
func (r *resourceExample) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
/* ... */
}
The ImportState
function includes a resource.ImportStateResponse
, which you use to set your resource's state.
Migration Notes
Remember the following differences between SDKv2 and the Framework when completing the migration.
- In both SDKv2 and Framework, there is no access to the configuration, state, or plan during import. The import
functions can only access the value (e.g., the resource's
ID
) supplied to theterraform import
command. - In SDKv2, you implement resource importing by populating the
Importer
field on theschema.Resource
struct. In the Framework, you define anImportState
function on the type which implementsresource.Resource
. This implementation satisfies theresource.ResourceWithImportState
interface.
Example
In the simple use case in which schema.ImportStatePassthroughContext
has been used with SDKv2, migrating to the Framework involves using the resource.ImportStatePassthroughID
function.
SDKv2
func resourceExample() *schema.Resource {
return &schema.Resource{
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
/* ... */
}
}
Framework
func (r *resourceExample) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
The following examples show how to migrate portions of the random provider.
For a complete example, clone the
terraform-provider-random
repository and compare the resource_password.go
file in
v3.3.2
with v3.4.1.
This example also shows one way to handle populating attributes with their default values during import.
SDKv2
The following example from the resource_password.go
file shows the import function for the random_password
resource
with SDKv2.
func resourcePassword() *schema.Resource {
return &schema.Resource{
Importer: &schema.ResourceImporter{
StateContext: importPasswordFunc,
},
/* ... */
}
}
The following example shows the implementation of the importPasswordFunc
function with SDKv2.
func importPasswordFunc(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
for k, v := range passwordSchemaV2() {
if v.Default == nil {
continue
}
if err := d.Set(k, v.Default); err != nil {
return nil, fmt.Errorf("error setting %s: %w", k, err)
}
}
for _, key := range []string{"number", "numeric"} {
if err := d.Set(key, true); err != nil {
return nil, fmt.Errorf("error setting %s: %w", key, err)
}
}
val := d.Id()
d.SetId("none")
if err := d.Set("result", val); err != nil {
return nil, fmt.Errorf("resource password import failed, error setting result: %w", err)
}
if err := d.Set("length", len(val)); err != nil {
return nil, fmt.Errorf("error setting length: %w", err)
}
hash, err := generateHash(val)
if err != nil {
return nil, fmt.Errorf("resource password import failed, generate hash error: %w", err)
}
if err := d.Set("bcrypt_hash", hash); err != nil {
return nil, fmt.Errorf("resource password import failed, error setting bcrypt_hash: %w", err)
}
return []*schema.ResourceData{d}, nil
}
Framework
The following shows the same section of provider code after the migration.
This code implements the ResourceWithImportState
interface on the passwordResource
type by defining an ImportState
function.
func (r *passwordResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
id := req.ID
state := passwordModelV2{
ID: types.StringValue("none"),
Result: types.StringValue(id),
Length: types.Int64Value(int64(len(id))),
Special: types.BoolValue(true),
Upper: types.BoolValue(true),
Lower: types.BoolValue(true),
Numeric: types.BoolValue(true),
MinSpecial: types.Int64Value(0),
MinUpper: types.Int64Value(0),
MinLower: types.Int64Value(0),
MinNumeric: types.Int64Value(0),
}
hash, err := generateHash(id)
if err != nil {
resp.Diagnostics.Append(diagnostics.HashGenerationError(err.Error())...)
}
state.BcryptHash = types.StringValue(hash)
diags := resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}