From f5a990a071734e82affd73e2d370677555b5fbb9 Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Mon, 9 Oct 2023 06:56:22 -0400 Subject: [PATCH] internal/fwserver - Fix `DataSource/Resource Type Not Found` errors when `GetProviderSchema` is not called (#852) * initial fix for provider type name * introduce provider name mutex * add changelog entries * fix changelog to be more user-friendly --- .../unreleased/BUG FIXES-20231009-064344.yaml | 6 ++++ internal/fwserver/server.go | 36 ++++++++++++++++--- internal/fwserver/server_getmetadata.go | 11 ------ internal/fwserver/server_getproviderschema.go | 11 ------ .../server_getproviderschema_test.go | 32 +++++++++++++---- .../server_getproviderschema_test.go | 32 +++++++++++++---- 6 files changed, 90 insertions(+), 38 deletions(-) create mode 100644 .changes/unreleased/BUG FIXES-20231009-064344.yaml diff --git a/.changes/unreleased/BUG FIXES-20231009-064344.yaml b/.changes/unreleased/BUG FIXES-20231009-064344.yaml new file mode 100644 index 000000000..ba53ca350 --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20231009-064344.yaml @@ -0,0 +1,6 @@ +kind: BUG FIXES +body: 'providerserver: Prevented `Data Source Type Not Found` and `Resource Type Not + Found` errors with Terraform 1.6 and later' +time: 2023-10-09T06:43:44.3563-04:00 +custom: + Issue: "853" diff --git a/internal/fwserver/server.go b/internal/fwserver/server.go index 31e75bd6b..261579c68 100644 --- a/internal/fwserver/server.go +++ b/internal/fwserver/server.go @@ -83,10 +83,14 @@ type Server struct { // access from race conditions. providerMetaSchemaMutex sync.Mutex - // providerTypeName is the type name of the provider, if the provider - // implemented the Metadata method. + // providerTypeName is the cached type name of the provider, if the provider + // implemented the Metadata method. Access this field with the Provider.ProviderTypeName() method. providerTypeName string + // providerTypeNameMutex is a mutex to protect concurrent providerTypeName + // access from race conditions. + providerTypeNameMutex sync.Mutex + // resourceSchemas is the cached Resource Schemas for RPCs that need to // convert configuration data from the protocol. If not found, it will be // fetched from the ResourceType.GetSchema() method. @@ -140,6 +144,7 @@ func (s *Server) DataSourceFuncs(ctx context.Context) (map[string]func() datasou return s.dataSourceFuncs, s.dataSourceTypesDiags } + providerTypeName := s.ProviderTypeName(ctx) s.dataSourceFuncs = make(map[string]func() datasource.DataSource) logging.FrameworkTrace(ctx, "Calling provider defined Provider DataSources") @@ -150,7 +155,7 @@ func (s *Server) DataSourceFuncs(ctx context.Context) (map[string]func() datasou dataSource := dataSourceFunc() dataSourceTypeNameReq := datasource.MetadataRequest{ - ProviderTypeName: s.providerTypeName, + ProviderTypeName: providerTypeName, } dataSourceTypeNameResp := datasource.MetadataResponse{} @@ -285,6 +290,28 @@ func (s *Server) DataSourceSchemas(ctx context.Context) (map[string]fwschema.Sch return dataSourceSchemas, diags } +// ProviderTypeName returns the TypeName associated with the Provider. The TypeName is cached on first use. +func (s *Server) ProviderTypeName(ctx context.Context) string { + logging.FrameworkTrace(ctx, "Checking ProviderTypeName lock") + s.providerTypeNameMutex.Lock() + defer s.providerTypeNameMutex.Unlock() + + if s.providerTypeName != "" { + return s.providerTypeName + } + + metadataReq := provider.MetadataRequest{} + metadataResp := provider.MetadataResponse{} + + logging.FrameworkTrace(ctx, "Calling provider defined Provider Metadata") + s.Provider.Metadata(ctx, metadataReq, &metadataResp) + logging.FrameworkTrace(ctx, "Called provider defined Provider Metadata") + + s.providerTypeName = metadataResp.TypeName + + return s.providerTypeName +} + // ProviderSchema returns the Schema associated with the Provider. The Schema // and Diagnostics are cached on first use. func (s *Server) ProviderSchema(ctx context.Context) (fwschema.Schema, diag.Diagnostics) { @@ -374,6 +401,7 @@ func (s *Server) ResourceFuncs(ctx context.Context) (map[string]func() resource. return s.resourceFuncs, s.resourceTypesDiags } + providerTypeName := s.ProviderTypeName(ctx) s.resourceFuncs = make(map[string]func() resource.Resource) logging.FrameworkTrace(ctx, "Calling provider defined Provider Resources") @@ -384,7 +412,7 @@ func (s *Server) ResourceFuncs(ctx context.Context) (map[string]func() resource. res := resourceFunc() resourceTypeNameReq := resource.MetadataRequest{ - ProviderTypeName: s.providerTypeName, + ProviderTypeName: providerTypeName, } resourceTypeNameResp := resource.MetadataResponse{} diff --git a/internal/fwserver/server_getmetadata.go b/internal/fwserver/server_getmetadata.go index a4abd895c..703fccd40 100644 --- a/internal/fwserver/server_getmetadata.go +++ b/internal/fwserver/server_getmetadata.go @@ -7,8 +7,6 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/logging" - "github.com/hashicorp/terraform-plugin-framework/provider" ) // GetMetadataRequest is the framework server request for the @@ -44,15 +42,6 @@ func (s *Server) GetMetadata(ctx context.Context, req *GetMetadataRequest, resp resp.Resources = []ResourceMetadata{} resp.ServerCapabilities = s.ServerCapabilities() - metadataReq := provider.MetadataRequest{} - metadataResp := provider.MetadataResponse{} - - logging.FrameworkTrace(ctx, "Calling provider defined Provider Metadata") - s.Provider.Metadata(ctx, metadataReq, &metadataResp) - logging.FrameworkTrace(ctx, "Called provider defined Provider Metadata") - - s.providerTypeName = metadataResp.TypeName - datasourceMetadatas, diags := s.DataSourceMetadatas(ctx) resp.Diagnostics.Append(diags...) diff --git a/internal/fwserver/server_getproviderschema.go b/internal/fwserver/server_getproviderschema.go index e4e7d645f..b2acc82dd 100644 --- a/internal/fwserver/server_getproviderschema.go +++ b/internal/fwserver/server_getproviderschema.go @@ -8,8 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" - "github.com/hashicorp/terraform-plugin-framework/internal/logging" - "github.com/hashicorp/terraform-plugin-framework/provider" ) // GetProviderSchemaRequest is the framework server request for the @@ -31,15 +29,6 @@ type GetProviderSchemaResponse struct { func (s *Server) GetProviderSchema(ctx context.Context, req *GetProviderSchemaRequest, resp *GetProviderSchemaResponse) { resp.ServerCapabilities = s.ServerCapabilities() - metadataReq := provider.MetadataRequest{} - metadataResp := provider.MetadataResponse{} - - logging.FrameworkTrace(ctx, "Calling provider defined Provider Metadata") - s.Provider.Metadata(ctx, metadataReq, &metadataResp) - logging.FrameworkTrace(ctx, "Called provider defined Provider Metadata") - - s.providerTypeName = metadataResp.TypeName - providerSchema, diags := s.ProviderSchema(ctx) resp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_getproviderschema_test.go b/internal/proto5server/server_getproviderschema_test.go index 877552fd2..2c2f15cb8 100644 --- a/internal/proto5server/server_getproviderschema_test.go +++ b/internal/proto5server/server_getproviderschema_test.go @@ -527,32 +527,37 @@ func TestServerGetProviderSchema_logging(t *testing.T) { expectedEntries := []map[string]interface{}{ { "@level": "trace", - "@message": "Calling provider defined Provider Metadata", + "@message": "Checking ProviderSchema lock", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Called provider defined Provider Metadata", + "@message": "Calling provider defined Provider Schema", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Checking ProviderSchema lock", + "@message": "Called provider defined Provider Schema", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Calling provider defined Provider Schema", + "@message": "Checking ResourceTypes lock", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Called provider defined Provider Schema", + "@message": "Checking ProviderTypeName lock", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Checking ResourceTypes lock", + "@message": "Calling provider defined Provider Metadata", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Called provider defined Provider Metadata", "@module": "sdk.framework", }, { @@ -570,6 +575,21 @@ func TestServerGetProviderSchema_logging(t *testing.T) { "@message": "Checking DataSourceTypes lock", "@module": "sdk.framework", }, + { + "@level": "trace", + "@message": "Checking ProviderTypeName lock", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Calling provider defined Provider Metadata", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Called provider defined Provider Metadata", + "@module": "sdk.framework", + }, { "@level": "trace", "@message": "Calling provider defined Provider DataSources", diff --git a/internal/proto6server/server_getproviderschema_test.go b/internal/proto6server/server_getproviderschema_test.go index d5cb9c8bc..989d339ad 100644 --- a/internal/proto6server/server_getproviderschema_test.go +++ b/internal/proto6server/server_getproviderschema_test.go @@ -527,32 +527,37 @@ func TestServerGetProviderSchema_logging(t *testing.T) { expectedEntries := []map[string]interface{}{ { "@level": "trace", - "@message": "Calling provider defined Provider Metadata", + "@message": "Checking ProviderSchema lock", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Called provider defined Provider Metadata", + "@message": "Calling provider defined Provider Schema", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Checking ProviderSchema lock", + "@message": "Called provider defined Provider Schema", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Calling provider defined Provider Schema", + "@message": "Checking ResourceTypes lock", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Called provider defined Provider Schema", + "@message": "Checking ProviderTypeName lock", "@module": "sdk.framework", }, { "@level": "trace", - "@message": "Checking ResourceTypes lock", + "@message": "Calling provider defined Provider Metadata", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Called provider defined Provider Metadata", "@module": "sdk.framework", }, { @@ -570,6 +575,21 @@ func TestServerGetProviderSchema_logging(t *testing.T) { "@message": "Checking DataSourceTypes lock", "@module": "sdk.framework", }, + { + "@level": "trace", + "@message": "Checking ProviderTypeName lock", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Calling provider defined Provider Metadata", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Called provider defined Provider Metadata", + "@module": "sdk.framework", + }, { "@level": "trace", "@message": "Calling provider defined Provider DataSources",