Skip to content

Consider exposing Resource "add-on" interfaces as stand-alone interfaces #1159

Open
@gdavison

Description

@gdavison

Use-cases

In addition to the core resource.Resource interface, the Plugin Framework defines many "add-on" interfaces to extend functionality, such as

In all cases, these "add-on" interfaces follow the pattern

type ResourceWithSomethingExtra interface {
	Resource

	DoSomethingExtra(context.Context, SomethingExtraRequest, *SomethingExtraResponse)
}

Because these interfaces include resource.Resource, the interface types exported by the resource package cannot be used directly to create composable types or in testing.

For example, the AWS provider uses various embedded composable types for resource functionality, e.g. the resource type aws_apprunner_default_auto_scaling_configuration_version is defined as https://github.com/hashicorp/terraform-provider-aws/blob/4e1c9eee98e542dd211fef196e0017799eaf02ef/internal/service/apprunner/default_auto_scaling_configuration_version.go#L31-L35

type defaultAutoScalingConfigurationVersionResource struct {
        framework.ResourceWithConfigure
        framework.WithNoOpDelete
        framework.WithImportByID
}

Where framework.WithImportByID is defined as https://github.com/hashicorp/terraform-provider-aws/blob/4e1c9eee98e542dd211fef196e0017799eaf02ef/internal/framework/with_import_by_id.go#L16

type WithImportByID struct{}

func (w *WithImportByID) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
	resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), request, response)
}

As framework.WithImportByID is intended for embedding in other types, it only implements the ImportState function from resource.ResourceWithImportState.

When referencing full resource type implementations, such as determining if a resource type supports importing, checking if it implements resource.ResourceWithImportState works. However, when testing or otherwise referencing the embeddable struct, there is no way to validate that the interface is implemented without defining our own interface, such as

type importStater interface {
	ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse)
}

Proposal

Consider exporting additional interfaces that define only the "add-on" behaviour and composing the existing "add-on" interfaces from those. For example

type WithImportState interface {
	// ImportState is called when the provider must import the state of a
	// resource instance. This method must return enough state so the Read
	// method can properly refresh the full resource.
	//
	// If setting an attribute with the import identifier, it is recommended
	// to use the ImportStatePassthroughID() call in this method.
	/ImportState(context.Context, ImportStateRequest, *ImportStateResponse)
}

type ResourceWithImportState interface {
	Resource

	WithImportState
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions