diff --git a/.changes/unreleased/NOTES-20240129-084840.yaml b/.changes/unreleased/NOTES-20240129-084840.yaml new file mode 100644 index 0000000000..ed8deb16f8 --- /dev/null +++ b/.changes/unreleased/NOTES-20240129-084840.yaml @@ -0,0 +1,8 @@ +kind: NOTES +body: 'helper/schema: While this Go module will not receive support for moving + resource state across resource types, the provider server is updated to handle + the new operation, which will be required to prevent errors when updating + terraform-plugin-framework or terraform-plugin-mux in the future.' +time: 2024-01-29T08:48:40.990566-05:00 +custom: + Issue: "1307" diff --git a/helper/schema/grpc_provider.go b/helper/schema/grpc_provider.go index 4ba774a1f2..52661c9b16 100644 --- a/helper/schema/grpc_provider.go +++ b/helper/schema/grpc_provider.go @@ -28,6 +28,9 @@ const ( newExtraKey = "_new_extra_shim" ) +// Verify provider server interface implementation. +var _ tfprotov5.ProviderServer = (*GRPCProviderServer)(nil) + func NewGRPCProviderServer(p *Provider) *GRPCProviderServer { return &GRPCProviderServer{ provider: p, @@ -1208,6 +1211,42 @@ func (s *GRPCProviderServer) ImportResourceState(ctx context.Context, req *tfpro return resp, nil } +func (s *GRPCProviderServer) MoveResourceState(ctx context.Context, req *tfprotov5.MoveResourceStateRequest) (*tfprotov5.MoveResourceStateResponse, error) { + if req == nil { + return nil, fmt.Errorf("MoveResourceState request is nil") + } + + ctx = logging.InitContext(ctx) + + logging.HelperSchemaTrace(ctx, "Returning error for MoveResourceState") + + resp := &tfprotov5.MoveResourceStateResponse{} + + _, ok := s.provider.ResourcesMap[req.TargetTypeName] + + if !ok { + resp.Diagnostics = []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Unknown Resource Type", + Detail: fmt.Sprintf("The %q resource type is not supported by this provider.", req.TargetTypeName), + }, + } + + return resp, nil + } + + resp.Diagnostics = []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Move Resource State Not Supported", + Detail: fmt.Sprintf("The %q resource type does not support moving resource state across resource types.", req.TargetTypeName), + }, + } + + return resp, nil +} + func (s *GRPCProviderServer) ReadDataSource(ctx context.Context, req *tfprotov5.ReadDataSourceRequest) (*tfprotov5.ReadDataSourceResponse, error) { ctx = logging.InitContext(ctx) resp := &tfprotov5.ReadDataSourceResponse{} diff --git a/helper/schema/grpc_provider_test.go b/helper/schema/grpc_provider_test.go index 537d8fa1c8..39b4b078a1 100644 --- a/helper/schema/grpc_provider_test.go +++ b/helper/schema/grpc_provider_test.go @@ -24,9 +24,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -// The GRPCProviderServer will directly implement the go protobuf server -var _ tfprotov5.ProviderServer = (*GRPCProviderServer)(nil) - func TestGRPCProviderServerConfigureProvider(t *testing.T) { t.Parallel() @@ -2209,6 +2206,74 @@ func TestGRPCProviderServerGetMetadata(t *testing.T) { } } +func TestGRPCProviderServerMoveResourceState(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + server *GRPCProviderServer + request *tfprotov5.MoveResourceStateRequest + expected *tfprotov5.MoveResourceStateResponse + }{ + "nil": { + server: NewGRPCProviderServer(&Provider{}), + request: nil, + expected: nil, + }, + "request-TargetTypeName-missing": { + server: NewGRPCProviderServer(&Provider{}), + request: &tfprotov5.MoveResourceStateRequest{ + TargetTypeName: "test_resource", + }, + expected: &tfprotov5.MoveResourceStateResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Unknown Resource Type", + Detail: "The \"test_resource\" resource type is not supported by this provider.", + }, + }, + }, + }, + "request-TargetTypeName": { + server: NewGRPCProviderServer(&Provider{ + ResourcesMap: map[string]*Resource{ + "test_resource": {}, + }, + }), + request: &tfprotov5.MoveResourceStateRequest{ + TargetTypeName: "test_resource", + }, + expected: &tfprotov5.MoveResourceStateResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Move Resource State Not Supported", + Detail: "The \"test_resource\" resource type does not support moving resource state across resource types.", + }, + }, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + resp, err := testCase.server.MoveResourceState(context.Background(), testCase.request) + + if testCase.request != nil && err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if diff := cmp.Diff(resp, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestUpgradeState_jsonState(t *testing.T) { r := &Resource{ SchemaVersion: 2,