diff --git a/.changelog/294.txt b/.changelog/294.txt deleted file mode 100644 index 42599c81f..000000000 --- a/.changelog/294.txt +++ /dev/null @@ -1,11 +0,0 @@ -```release-note:note -tfsdk: The `NewProtocol6Server()` function has been deprecated in preference of `NewProtocol6ProviderServer()` and `NewProtocol6ProviderServerWithError()` functions, which will simplify muxing and testing implementations. The `NewProtocol6Server()` function will be removed in an upcoming minor release before v1.0.0. -``` - -```release-note:enhancement -tfsdk: Added `NewProtocol6ProviderServer()` function, which can be directly used with terraform-plugin-go and terraform-plugin-mux. -``` - -```release-note:enhancement -tfsdk: Added `NewProtocol6ProviderServerWithError()` function, which can be directly used with terraform-plugin-sdk acceptance testing. -``` diff --git a/.changelog/296.txt b/.changelog/296.txt deleted file mode 100644 index 06604caee..000000000 --- a/.changelog/296.txt +++ /dev/null @@ -1,7 +0,0 @@ -```release-note:note -tfsdk: The `ServeOpts` type `Name` field has been deprecated in preference of the `Address` field. The `Name` field will be removed prior to version 1.0.0. -``` - -```release-note:enhancement -tfsdk: Added `ServeOpts` type `Address` field, which should contain the full provider address in hostname/namespace/type format. -``` diff --git a/.changelog/pending.txt b/.changelog/pending.txt new file mode 100644 index 000000000..081604c49 --- /dev/null +++ b/.changelog/pending.txt @@ -0,0 +1,19 @@ +```release-note:note +tfsdk: The `NewProtocol6Server()` function has been deprecated in preference of `providerserver.NewProtocol6()` and `providerserver.NewProtocol6WithError()` functions, which will simplify muxing and testing implementations. The `tfsdk.NewProtocol6Server()` function will be removed in the next minor version. +``` + +```release-note:note +tfsdk: The `Serve()` function has been deprecated in preference of the `providerserver.Serve()` function. The `tfsdk.Serve()` function will be removed in the next minor version. +``` + +```release-note:note +tfsdk: The `ServeOpts` type has been deprecated in preference of the `providerserver.ServeOpts` type. When migrating, the `Name` field has been replaced with `Address`. The `tfsdk.ServeOpts` type will be removed in the next minor version. +``` + +```release-note:note +tfsdk: The previously unexported `server` type has been temporarily exported to aid in the migration to the new `providerserver` package. It is not intended for provider developer usage and will be moved into an internal package in the next minor version. +``` + +```release-note:feature +Introduced `providerserver` package, which contains all functions and types necessary for serving a provider in production or acceptance testing. +``` diff --git a/providerserver/provider_test.go b/providerserver/provider_test.go new file mode 100644 index 000000000..7272bde52 --- /dev/null +++ b/providerserver/provider_test.go @@ -0,0 +1,31 @@ +package providerserver + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +var _ tfsdk.Provider = &testProvider{} + +// Provider type for testing package functionality. +// +// This is separate from tfsdk.testServeProvider to avoid changing that. +type testProvider struct{} + +func (t *testProvider) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil +} + +func (t *testProvider) Configure(_ context.Context, _ tfsdk.ConfigureProviderRequest, _ *tfsdk.ConfigureProviderResponse) { + // intentionally empty +} + +func (t *testProvider) GetDataSources(_ context.Context) (map[string]tfsdk.DataSourceType, diag.Diagnostics) { + return map[string]tfsdk.DataSourceType{}, nil +} + +func (t *testProvider) GetResources(_ context.Context) (map[string]tfsdk.ResourceType, diag.Diagnostics) { + return map[string]tfsdk.ResourceType{}, nil +} diff --git a/providerserver/providerserver.go b/providerserver/providerserver.go new file mode 100644 index 000000000..2603a75e3 --- /dev/null +++ b/providerserver/providerserver.go @@ -0,0 +1,60 @@ +package providerserver + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server" +) + +// NewProtocol6 returns a protocol version 6 ProviderServer implementation +// based on the given Provider and suitable for usage with the +// github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server.Serve() +// function and various terraform-plugin-mux functions. +func NewProtocol6(p tfsdk.Provider) func() tfprotov6.ProviderServer { + return func() tfprotov6.ProviderServer { + return &tfsdk.Server{ + Provider: p, + } + } +} + +// NewProtocol6WithError returns a protocol version 6 ProviderServer +// implementation based on the given Provider and suitable for usage with +// github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.TestCase.ProtoV6ProviderFactories. +// +// The error return is not currently used, but it may be in the future. +func NewProtocol6WithError(p tfsdk.Provider) func() (tfprotov6.ProviderServer, error) { + return func() (tfprotov6.ProviderServer, error) { + return &tfsdk.Server{ + Provider: p, + }, nil + } +} + +// Serve serves a provider, blocking until the context is canceled. +func Serve(ctx context.Context, providerFunc func() tfsdk.Provider, opts ServeOpts) error { + err := opts.validate(ctx) + + if err != nil { + return fmt.Errorf("unable to validate ServeOpts: %w", err) + } + + var tf6serverOpts []tf6server.ServeOpt + + if opts.Debug { + tf6serverOpts = append(tf6serverOpts, tf6server.WithManagedDebug()) + } + + return tf6server.Serve( + opts.Address, + func() tfprotov6.ProviderServer { + return &tfsdk.Server{ + Provider: providerFunc(), + } + }, + tf6serverOpts..., + ) +} diff --git a/providerserver/providerserver_test.go b/providerserver/providerserver_test.go new file mode 100644 index 000000000..14a479fd4 --- /dev/null +++ b/providerserver/providerserver_test.go @@ -0,0 +1,39 @@ +package providerserver + +import ( + "context" + "testing" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" +) + +func TestNewProtocol6(t *testing.T) { + provider := &testProvider{} + + providerServerFunc := NewProtocol6(provider) + providerServer := providerServerFunc() + + // Simple verification + _, err := providerServer.GetProviderSchema(context.Background(), &tfprotov6.GetProviderSchemaRequest{}) + + if err != nil { + t.Fatalf("unexpected error calling ProviderServer: %s", err) + } +} + +func TestNewProtocol6WithError(t *testing.T) { + provider := &testProvider{} + + providerServer, err := NewProtocol6WithError(provider)() + + if err != nil { + t.Fatalf("unexpected error creating ProviderServer: %s", err) + } + + // Simple verification + _, err = providerServer.GetProviderSchema(context.Background(), &tfprotov6.GetProviderSchemaRequest{}) + + if err != nil { + t.Fatalf("unexpected error calling ProviderServer: %s", err) + } +} diff --git a/providerserver/serve_opts.go b/providerserver/serve_opts.go new file mode 100644 index 000000000..0bff12275 --- /dev/null +++ b/providerserver/serve_opts.go @@ -0,0 +1,65 @@ +package providerserver + +import ( + "context" + "fmt" + "strings" +) + +// ServeOpts are options for serving the provider. +type ServeOpts struct { + // Address is the full address of the provider. Full address form has three + // parts separated by forward slashes (/): Hostname, namespace, and + // provider type ("name"). + // + // For example: registry.terraform.io/hashicorp/random. + Address string + + // Debug runs the provider in a mode acceptable for debugging and testing + // processes, such as delve, by managing the process lifecycle. Information + // needed for Terraform CLI to connect to the provider is output to stdout. + // os.Interrupt (Ctrl-c) can be used to stop the provider. + Debug bool +} + +// Validate a given provider address. This is only used for the Address field +// to preserve backwards compatibility for the Name field. +// +// This logic is manually implemented over importing +// github.com/hashicorp/terraform-registry-address as its functionality such as +// ParseAndInferProviderSourceString and ParseRawProviderSourceString allow +// shorter address formats, which would then require post-validation anyways. +func (opts ServeOpts) validateAddress(_ context.Context) error { + addressParts := strings.Split(opts.Address, "/") + formatErr := fmt.Errorf("expected hostname/namespace/type format, got: %s", opts.Address) + + if len(addressParts) != 3 { + return formatErr + } + + if addressParts[0] == "" || addressParts[1] == "" || addressParts[2] == "" { + return formatErr + } + + return nil +} + +// Validation checks for provider defined ServeOpts. +// +// Current checks which return errors: +// +// - If Address is not set +// - Address is a valid full provider address +func (opts ServeOpts) validate(ctx context.Context) error { + if opts.Address == "" { + return fmt.Errorf("Address must be provided") + } + + err := opts.validateAddress(ctx) + + if err != nil { + return fmt.Errorf("unable to validate Address: %w", err) + } + + return nil +} diff --git a/providerserver/serve_opts_test.go b/providerserver/serve_opts_test.go new file mode 100644 index 000000000..47e590620 --- /dev/null +++ b/providerserver/serve_opts_test.go @@ -0,0 +1,114 @@ +package providerserver + +import ( + "context" + "fmt" + "strings" + "testing" +) + +func TestServeOptsValidate(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + serveOpts ServeOpts + expectedError error + }{ + "Address": { + serveOpts: ServeOpts{ + Address: "registry.terraform.io/hashicorp/testing", + }, + }, + "Address-missing": { + serveOpts: ServeOpts{}, + expectedError: fmt.Errorf("Address must be provided"), + }, + "Address-invalid-missing-hostname-and-namespace": { + serveOpts: ServeOpts{ + Address: "testing", + }, + expectedError: fmt.Errorf("unable to validate Address: expected hostname/namespace/type format, got: testing"), + }, + "Address-invalid-missing-hostname": { + serveOpts: ServeOpts{ + Address: "hashicorp/testing", + }, + expectedError: fmt.Errorf("unable to validate Address: expected hostname/namespace/type format, got: hashicorp/testing"), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + err := testCase.serveOpts.validate(context.Background()) + + if err != nil { + if testCase.expectedError == nil { + t.Fatalf("expected no error, got: %s", err) + } + + if !strings.Contains(err.Error(), testCase.expectedError.Error()) { + t.Fatalf("expected error %q, got: %s", testCase.expectedError, err) + } + } + + if err == nil && testCase.expectedError != nil { + t.Fatalf("got no error, expected: %s", testCase.expectedError) + } + }) + } +} + +func TestServeOptsValidateAddress(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + serveOpts ServeOpts + expectedError error + }{ + "valid": { + serveOpts: ServeOpts{ + Address: "registry.terraform.io/hashicorp/testing", + }, + }, + "invalid-missing-hostname-and-namepsace": { + serveOpts: ServeOpts{ + Address: "testing", + }, + expectedError: fmt.Errorf("expected hostname/namespace/type format, got: testing"), + }, + "invalid-missing-hostname": { + serveOpts: ServeOpts{ + Address: "hashicorp/testing", + }, + expectedError: fmt.Errorf("expected hostname/namespace/type format, got: hashicorp/testing"), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + err := testCase.serveOpts.validateAddress(context.Background()) + + if err != nil { + if testCase.expectedError == nil { + t.Fatalf("expected no error, got: %s", err) + } + + if !strings.Contains(err.Error(), testCase.expectedError.Error()) { + t.Fatalf("expected error %q, got: %s", testCase.expectedError, err) + } + } + + if err == nil && testCase.expectedError != nil { + t.Fatalf("got no error, expected: %s", testCase.expectedError) + } + }) + } +} diff --git a/tfsdk/serve.go b/tfsdk/serve.go index 72d0a9835..b6f21e53c 100644 --- a/tfsdk/serve.go +++ b/tfsdk/serve.go @@ -15,10 +15,15 @@ import ( "github.com/hashicorp/terraform-plugin-go/tftypes" ) -var _ tfprotov6.ProviderServer = &server{} +var _ tfprotov6.ProviderServer = &Server{} -type server struct { - p Provider +// Provider server implementation. +// +// Depecated: This type is temporarily exported in this package and is not +// intended for provider developer usage. This will be moved to an internal +// package in the next minor version. +type Server struct { + Provider Provider contextCancels []context.CancelFunc contextCancelsMu sync.Mutex } @@ -26,39 +31,18 @@ type server struct { // NewProtocol6Server returns a tfprotov6.ProviderServer implementation based // on the passed Provider implementation. // -// Deprecated: Use NewProtocol6ProviderServer instead. This will be removed -// in an upcoming minor version before v1.0.0. +// Deprecated: Use providerserver.NewProtocol6 instead. This will be removed in +// the next minor version. func NewProtocol6Server(p Provider) tfprotov6.ProviderServer { - return &server{ - p: p, - } -} - -// Returns a protocol version 6 ProviderServer implementation based on the -// given Provider and suitable for usage with the terraform-plugin-go -// tf6server.Serve() function and various terraform-plugin-mux functions. -func NewProtocol6ProviderServer(p Provider) func() tfprotov6.ProviderServer { - return func() tfprotov6.ProviderServer { - return &server{ - p: p, - } - } -} - -// Returns a protocol version 6 ProviderServer implementation based on the -// given Provider and suitable for usage with the terraform-plugin-sdk -// acceptance testing helper/resource.TestCase.ProtoV6ProviderFactories. -// -// The error return is not currently used, but it may be in the future. -func NewProtocol6ProviderServerWithError(p Provider) func() (tfprotov6.ProviderServer, error) { - return func() (tfprotov6.ProviderServer, error) { - return &server{ - p: p, - }, nil + return &Server{ + Provider: p, } } // Serve serves a provider, blocking until the context is canceled. +// +// Deprecated: Use providerserver.Serve() instead. This will be removed in the +// next minor version. func Serve(ctx context.Context, providerFunc func() Provider, opts ServeOpts) error { err := opts.validate(ctx) @@ -73,13 +57,13 @@ func Serve(ctx context.Context, providerFunc func() Provider, opts ServeOpts) er } return tf6server.Serve(opts.address(ctx), func() tfprotov6.ProviderServer { - return &server{ - p: providerFunc(), + return &Server{ + Provider: providerFunc(), } }, tf6serverOpts...) } -func (s *server) registerContext(in context.Context) context.Context { +func (s *Server) registerContext(in context.Context) context.Context { ctx, cancel := context.WithCancel(in) s.contextCancelsMu.Lock() defer s.contextCancelsMu.Unlock() @@ -87,7 +71,7 @@ func (s *server) registerContext(in context.Context) context.Context { return ctx } -func (s *server) cancelRegisteredContexts(_ context.Context) { +func (s *Server) cancelRegisteredContexts(_ context.Context) { s.contextCancelsMu.Lock() defer s.contextCancelsMu.Unlock() for _, cancel := range s.contextCancels { @@ -96,11 +80,11 @@ func (s *server) cancelRegisteredContexts(_ context.Context) { s.contextCancels = nil } -func (s *server) getResourceType(ctx context.Context, typ string) (ResourceType, diag.Diagnostics) { +func (s *Server) getResourceType(ctx context.Context, typ string) (ResourceType, diag.Diagnostics) { // TODO: Cache GetResources call in GetProviderSchema and reference cache instead // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/299 logging.FrameworkDebug(ctx, "Calling provider defined Provider GetResources") - resourceTypes, diags := s.p.GetResources(ctx) + resourceTypes, diags := s.Provider.GetResources(ctx) logging.FrameworkDebug(ctx, "Called provider defined Provider GetResources") if diags.HasError() { return nil, diags @@ -116,11 +100,11 @@ func (s *server) getResourceType(ctx context.Context, typ string) (ResourceType, return resourceType, diags } -func (s *server) getDataSourceType(ctx context.Context, typ string) (DataSourceType, diag.Diagnostics) { +func (s *Server) getDataSourceType(ctx context.Context, typ string) (DataSourceType, diag.Diagnostics) { // TODO: Cache GetDataSources call in GetProviderSchema and reference cache instead // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/299 logging.FrameworkDebug(ctx, "Calling provider defined Provider GetDataSources") - dataSourceTypes, diags := s.p.GetDataSources(ctx) + dataSourceTypes, diags := s.Provider.GetDataSources(ctx) logging.FrameworkDebug(ctx, "Called provider defined Provider GetDataSources") if diags.HasError() { return nil, diags @@ -155,7 +139,7 @@ func (r getProviderSchemaResponse) toTfprotov6() *tfprotov6.GetProviderSchemaRes } } -func (s *server) GetProviderSchema(ctx context.Context, _ *tfprotov6.GetProviderSchemaRequest) (*tfprotov6.GetProviderSchemaResponse, error) { +func (s *Server) GetProviderSchema(ctx context.Context, _ *tfprotov6.GetProviderSchemaRequest) (*tfprotov6.GetProviderSchemaResponse, error) { ctx = s.registerContext(ctx) resp := new(getProviderSchemaResponse) @@ -164,9 +148,9 @@ func (s *server) GetProviderSchema(ctx context.Context, _ *tfprotov6.GetProvider return resp.toTfprotov6(), nil } -func (s *server) getProviderSchema(ctx context.Context, resp *getProviderSchemaResponse) { +func (s *Server) getProviderSchema(ctx context.Context, resp *getProviderSchemaResponse) { logging.FrameworkDebug(ctx, "Calling provider defined Provider GetSchema") - providerSchema, diags := s.p.GetSchema(ctx) + providerSchema, diags := s.Provider.GetSchema(ctx) logging.FrameworkDebug(ctx, "Called provider defined Provider GetSchema") resp.Diagnostics.Append(diags...) if diags.HasError() { @@ -189,7 +173,7 @@ func (s *server) getProviderSchema(ctx context.Context, resp *getProviderSchemaR // if we have a provider_meta schema, get it var providerMeta6Schema *tfprotov6.Schema - if pm, ok := s.p.(ProviderWithProviderMeta); ok { + if pm, ok := s.Provider.(ProviderWithProviderMeta); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithProviderMeta") logging.FrameworkDebug(ctx, "Calling provider defined Provider GetMetaSchema") providerMetaSchema, diags := pm.GetMetaSchema(ctx) @@ -214,7 +198,7 @@ func (s *server) getProviderSchema(ctx context.Context, resp *getProviderSchemaR // TODO: Cache GetDataSources call // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/299 logging.FrameworkDebug(ctx, "Calling provider defined Provider GetResources") - resourceSchemas, diags := s.p.GetResources(ctx) + resourceSchemas, diags := s.Provider.GetResources(ctx) logging.FrameworkDebug(ctx, "Called provider defined Provider GetResources") resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -245,7 +229,7 @@ func (s *server) getProviderSchema(ctx context.Context, resp *getProviderSchemaR // TODO: Cache GetDataSources call // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/299 logging.FrameworkDebug(ctx, "Calling provider defined Provider GetDataSources") - dataSourceSchemas, diags := s.p.GetDataSources(ctx) + dataSourceSchemas, diags := s.Provider.GetDataSources(ctx) logging.FrameworkDebug(ctx, "Calling provider defined Provider GetDataSources") resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -294,7 +278,7 @@ func (r validateProviderConfigResponse) toTfprotov6() *tfprotov6.ValidateProvide } } -func (s *server) ValidateProviderConfig(ctx context.Context, req *tfprotov6.ValidateProviderConfigRequest) (*tfprotov6.ValidateProviderConfigResponse, error) { +func (s *Server) ValidateProviderConfig(ctx context.Context, req *tfprotov6.ValidateProviderConfigRequest) (*tfprotov6.ValidateProviderConfigResponse, error) { ctx = s.registerContext(ctx) resp := &validateProviderConfigResponse{ // This RPC allows a modified configuration to be returned. This was @@ -313,9 +297,9 @@ func (s *server) ValidateProviderConfig(ctx context.Context, req *tfprotov6.Vali return resp.toTfprotov6(), nil } -func (s *server) validateProviderConfig(ctx context.Context, req *tfprotov6.ValidateProviderConfigRequest, resp *validateProviderConfigResponse) { +func (s *Server) validateProviderConfig(ctx context.Context, req *tfprotov6.ValidateProviderConfigRequest, resp *validateProviderConfigResponse) { logging.FrameworkDebug(ctx, "Calling provider defined Provider GetSchema") - schema, diags := s.p.GetSchema(ctx) + schema, diags := s.Provider.GetSchema(ctx) logging.FrameworkDebug(ctx, "Called provider defined Provider GetSchema") resp.Diagnostics.Append(diags...) @@ -341,7 +325,7 @@ func (s *server) validateProviderConfig(ctx context.Context, req *tfprotov6.Vali }, } - if provider, ok := s.p.(ProviderWithConfigValidators); ok { + if provider, ok := s.Provider.(ProviderWithConfigValidators); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithConfigValidators") for _, configValidator := range provider.ConfigValidators(ctx) { vpcRes := &ValidateProviderConfigResponse{ @@ -368,7 +352,7 @@ func (s *server) validateProviderConfig(ctx context.Context, req *tfprotov6.Vali } } - if provider, ok := s.p.(ProviderWithValidateConfig); ok { + if provider, ok := s.Provider.(ProviderWithValidateConfig); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithValidateConfig") vpcRes := &ValidateProviderConfigResponse{ Diagnostics: resp.Diagnostics, @@ -407,7 +391,7 @@ func (r configureProviderResponse) toTfprotov6() *tfprotov6.ConfigureProviderRes } } -func (s *server) ConfigureProvider(ctx context.Context, req *tfprotov6.ConfigureProviderRequest) (*tfprotov6.ConfigureProviderResponse, error) { +func (s *Server) ConfigureProvider(ctx context.Context, req *tfprotov6.ConfigureProviderRequest) (*tfprotov6.ConfigureProviderResponse, error) { ctx = s.registerContext(ctx) resp := &configureProviderResponse{} @@ -416,9 +400,9 @@ func (s *server) ConfigureProvider(ctx context.Context, req *tfprotov6.Configure return resp.toTfprotov6(), nil } -func (s *server) configureProvider(ctx context.Context, req *tfprotov6.ConfigureProviderRequest, resp *configureProviderResponse) { +func (s *Server) configureProvider(ctx context.Context, req *tfprotov6.ConfigureProviderRequest, resp *configureProviderResponse) { logging.FrameworkDebug(ctx, "Calling provider defined Provider GetSchema") - schema, diags := s.p.GetSchema(ctx) + schema, diags := s.Provider.GetSchema(ctx) logging.FrameworkDebug(ctx, "Called provider defined Provider GetSchema") resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -441,12 +425,12 @@ func (s *server) configureProvider(ctx context.Context, req *tfprotov6.Configure } res := &ConfigureProviderResponse{} logging.FrameworkDebug(ctx, "Calling provider defined Provider Configure") - s.p.Configure(ctx, r, res) + s.Provider.Configure(ctx, r, res) logging.FrameworkDebug(ctx, "Called provider defined Provider Configure") resp.Diagnostics.Append(res.Diagnostics...) } -func (s *server) StopProvider(ctx context.Context, _ *tfprotov6.StopProviderRequest) (*tfprotov6.StopProviderResponse, error) { +func (s *Server) StopProvider(ctx context.Context, _ *tfprotov6.StopProviderRequest) (*tfprotov6.StopProviderResponse, error) { s.cancelRegisteredContexts(ctx) return &tfprotov6.StopProviderResponse{}, nil @@ -463,7 +447,7 @@ func (r validateResourceConfigResponse) toTfprotov6() *tfprotov6.ValidateResourc } } -func (s *server) ValidateResourceConfig(ctx context.Context, req *tfprotov6.ValidateResourceConfigRequest) (*tfprotov6.ValidateResourceConfigResponse, error) { +func (s *Server) ValidateResourceConfig(ctx context.Context, req *tfprotov6.ValidateResourceConfigRequest) (*tfprotov6.ValidateResourceConfigResponse, error) { ctx = s.registerContext(ctx) resp := &validateResourceConfigResponse{} @@ -472,7 +456,7 @@ func (s *server) ValidateResourceConfig(ctx context.Context, req *tfprotov6.Vali return resp.toTfprotov6(), nil } -func (s *server) validateResourceConfig(ctx context.Context, req *tfprotov6.ValidateResourceConfigRequest, resp *validateResourceConfigResponse) { +func (s *Server) validateResourceConfig(ctx context.Context, req *tfprotov6.ValidateResourceConfigRequest, resp *validateResourceConfigResponse) { // Get the type of resource, so we can get its schema and create an // instance resourceType, diags := s.getResourceType(ctx, req.TypeName) @@ -496,7 +480,7 @@ func (s *server) validateResourceConfig(ctx context.Context, req *tfprotov6.Vali // Create the resource instance, so we can call its methods and handle // the request logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resource, diags := resourceType.NewResource(ctx, s.p) + resource, diags := resourceType.NewResource(ctx, s.Provider) logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") resp.Diagnostics.Append(diags...) @@ -591,7 +575,7 @@ func (r upgradeResourceStateResponse) toTfprotov6() *tfprotov6.UpgradeResourceSt } } -func (s *server) UpgradeResourceState(ctx context.Context, req *tfprotov6.UpgradeResourceStateRequest) (*tfprotov6.UpgradeResourceStateResponse, error) { +func (s *Server) UpgradeResourceState(ctx context.Context, req *tfprotov6.UpgradeResourceStateRequest) (*tfprotov6.UpgradeResourceStateResponse, error) { ctx = s.registerContext(ctx) resp := &upgradeResourceStateResponse{} @@ -600,7 +584,7 @@ func (s *server) UpgradeResourceState(ctx context.Context, req *tfprotov6.Upgrad return resp.toTfprotov6(), nil } -func (s *server) upgradeResourceState(ctx context.Context, req *tfprotov6.UpgradeResourceStateRequest, resp *upgradeResourceStateResponse) { +func (s *Server) upgradeResourceState(ctx context.Context, req *tfprotov6.UpgradeResourceStateRequest, resp *upgradeResourceStateResponse) { if req == nil { return } @@ -684,7 +668,7 @@ func (s *server) upgradeResourceState(ctx context.Context, req *tfprotov6.Upgrad } logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resource, diags := resourceType.NewResource(ctx, s.p) + resource, diags := resourceType.NewResource(ctx, s.Provider) logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") resp.Diagnostics.Append(diags...) @@ -821,7 +805,7 @@ func (r readResourceResponse) toTfprotov6() *tfprotov6.ReadResourceResponse { } } -func (s *server) ReadResource(ctx context.Context, req *tfprotov6.ReadResourceRequest) (*tfprotov6.ReadResourceResponse, error) { +func (s *Server) ReadResource(ctx context.Context, req *tfprotov6.ReadResourceRequest) (*tfprotov6.ReadResourceResponse, error) { ctx = s.registerContext(ctx) resp := &readResourceResponse{} @@ -830,7 +814,7 @@ func (s *server) ReadResource(ctx context.Context, req *tfprotov6.ReadResourceRe return resp.toTfprotov6(), nil } -func (s *server) readResource(ctx context.Context, req *tfprotov6.ReadResourceRequest, resp *readResourceResponse) { +func (s *Server) readResource(ctx context.Context, req *tfprotov6.ReadResourceRequest, resp *readResourceResponse) { resourceType, diags := s.getResourceType(ctx, req.TypeName) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -844,7 +828,7 @@ func (s *server) readResource(ctx context.Context, req *tfprotov6.ReadResourceRe return } logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resource, diags := resourceType.NewResource(ctx, s.p) + resource, diags := resourceType.NewResource(ctx, s.Provider) logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -864,7 +848,7 @@ func (s *server) readResource(ctx context.Context, req *tfprotov6.ReadResourceRe Schema: resourceSchema, }, } - if pm, ok := s.p.(ProviderWithProviderMeta); ok { + if pm, ok := s.Provider.(ProviderWithProviderMeta); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithProviderMeta") logging.FrameworkDebug(ctx, "Calling provider defined Provider GetMetaSchema") pmSchema, diags := pm.GetMetaSchema(ctx) @@ -967,7 +951,7 @@ func (r planResourceChangeResponse) toTfprotov6() *tfprotov6.PlanResourceChangeR } } -func (s *server) PlanResourceChange(ctx context.Context, req *tfprotov6.PlanResourceChangeRequest) (*tfprotov6.PlanResourceChangeResponse, error) { +func (s *Server) PlanResourceChange(ctx context.Context, req *tfprotov6.PlanResourceChangeRequest) (*tfprotov6.PlanResourceChangeResponse, error) { ctx = s.registerContext(ctx) resp := &planResourceChangeResponse{} @@ -976,7 +960,7 @@ func (s *server) PlanResourceChange(ctx context.Context, req *tfprotov6.PlanReso return resp.toTfprotov6(), nil } -func (s *server) planResourceChange(ctx context.Context, req *tfprotov6.PlanResourceChangeRequest, resp *planResourceChangeResponse) { +func (s *Server) planResourceChange(ctx context.Context, req *tfprotov6.PlanResourceChangeRequest, resp *planResourceChangeResponse) { // get the type of resource, so we can get its schema and create an // instance resourceType, diags := s.getResourceType(ctx, req.TypeName) @@ -1027,7 +1011,7 @@ func (s *server) planResourceChange(ctx context.Context, req *tfprotov6.PlanReso // create the resource instance, so we can call its methods and handle // the request logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resource, diags := resourceType.NewResource(ctx, s.p) + resource, diags := resourceType.NewResource(ctx, s.Provider) logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -1120,7 +1104,7 @@ func (s *server) planResourceChange(ctx context.Context, req *tfprotov6.PlanReso Raw: plan, }, } - if pm, ok := s.p.(ProviderWithProviderMeta); ok { + if pm, ok := s.Provider.(ProviderWithProviderMeta); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithProviderMeta") logging.FrameworkDebug(ctx, "Calling provider defined Provider GetMetaSchema") pmSchema, diags := pm.GetMetaSchema(ctx) @@ -1191,7 +1175,7 @@ func (s *server) planResourceChange(ctx context.Context, req *tfprotov6.PlanReso Raw: plan, }, } - if pm, ok := s.p.(ProviderWithProviderMeta); ok { + if pm, ok := s.Provider.(ProviderWithProviderMeta); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithProviderMeta") logging.FrameworkDebug(ctx, "Calling provider defined Provider GetMetaSchema") pmSchema, diags := pm.GetMetaSchema(ctx) @@ -1291,7 +1275,7 @@ func normaliseRequiresReplace(ctx context.Context, rs []*tftypes.AttributePath) return ret[:j] } -func (s *server) ApplyResourceChange(ctx context.Context, req *tfprotov6.ApplyResourceChangeRequest) (*tfprotov6.ApplyResourceChangeResponse, error) { +func (s *Server) ApplyResourceChange(ctx context.Context, req *tfprotov6.ApplyResourceChangeRequest) (*tfprotov6.ApplyResourceChangeResponse, error) { ctx = s.registerContext(ctx) resp := &applyResourceChangeResponse{ // default to the prior state, so the state won't change unless @@ -1304,7 +1288,7 @@ func (s *server) ApplyResourceChange(ctx context.Context, req *tfprotov6.ApplyRe return resp.toTfprotov6(), nil } -func (s *server) applyResourceChange(ctx context.Context, req *tfprotov6.ApplyResourceChangeRequest, resp *applyResourceChangeResponse) { +func (s *Server) applyResourceChange(ctx context.Context, req *tfprotov6.ApplyResourceChangeRequest, resp *applyResourceChangeResponse) { // get the type of resource, so we can get its schema and create an // instance resourceType, diags := s.getResourceType(ctx, req.TypeName) @@ -1326,7 +1310,7 @@ func (s *server) applyResourceChange(ctx context.Context, req *tfprotov6.ApplyRe // create the resource instance, so we can call its methods and handle // the request logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resource, diags := resourceType.NewResource(ctx, s.p) + resource, diags := resourceType.NewResource(ctx, s.Provider) logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -1399,7 +1383,7 @@ func (s *server) applyResourceChange(ctx context.Context, req *tfprotov6.ApplyRe Raw: plan, }, } - if pm, ok := s.p.(ProviderWithProviderMeta); ok { + if pm, ok := s.Provider.(ProviderWithProviderMeta); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithProviderMeta") logging.FrameworkDebug(ctx, "Calling provider defined Provider GetMetaSchema") pmSchema, diags := pm.GetMetaSchema(ctx) @@ -1461,7 +1445,7 @@ func (s *server) applyResourceChange(ctx context.Context, req *tfprotov6.ApplyRe Raw: priorState, }, } - if pm, ok := s.p.(ProviderWithProviderMeta); ok { + if pm, ok := s.Provider.(ProviderWithProviderMeta); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithProviderMeta") logging.FrameworkDebug(ctx, "Calling provider defined Provider GetMetaSchema") pmSchema, diags := pm.GetMetaSchema(ctx) @@ -1515,7 +1499,7 @@ func (s *server) applyResourceChange(ctx context.Context, req *tfprotov6.ApplyRe Raw: priorState, }, } - if pm, ok := s.p.(ProviderWithProviderMeta); ok { + if pm, ok := s.Provider.(ProviderWithProviderMeta); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithProviderMeta") logging.FrameworkDebug(ctx, "Calling provider defined Provider GetMetaSchema") pmSchema, diags := pm.GetMetaSchema(ctx) @@ -1586,7 +1570,7 @@ func (r validateDataResourceConfigResponse) toTfprotov6() *tfprotov6.ValidateDat } } -func (s *server) ValidateDataResourceConfig(ctx context.Context, req *tfprotov6.ValidateDataResourceConfigRequest) (*tfprotov6.ValidateDataResourceConfigResponse, error) { +func (s *Server) ValidateDataResourceConfig(ctx context.Context, req *tfprotov6.ValidateDataResourceConfigRequest) (*tfprotov6.ValidateDataResourceConfigResponse, error) { ctx = s.registerContext(ctx) resp := &validateDataResourceConfigResponse{} @@ -1595,7 +1579,7 @@ func (s *server) ValidateDataResourceConfig(ctx context.Context, req *tfprotov6. return resp.toTfprotov6(), nil } -func (s *server) validateDataResourceConfig(ctx context.Context, req *tfprotov6.ValidateDataResourceConfigRequest, resp *validateDataResourceConfigResponse) { +func (s *Server) validateDataResourceConfig(ctx context.Context, req *tfprotov6.ValidateDataResourceConfigRequest, resp *validateDataResourceConfigResponse) { // Get the type of data source, so we can get its schema and create an // instance @@ -1620,7 +1604,7 @@ func (s *server) validateDataResourceConfig(ctx context.Context, req *tfprotov6. // Create the data source instance, so we can call its methods and handle // the request logging.FrameworkDebug(ctx, "Calling provider defined DataSourceType NewDataSource") - dataSource, diags := dataSourceType.NewDataSource(ctx, s.p) + dataSource, diags := dataSourceType.NewDataSource(ctx, s.Provider) logging.FrameworkDebug(ctx, "Called provider defined DataSourceType NewDataSource") resp.Diagnostics.Append(diags...) @@ -1714,7 +1698,7 @@ func (r readDataSourceResponse) toTfprotov6() *tfprotov6.ReadDataSourceResponse } } -func (s *server) ReadDataSource(ctx context.Context, req *tfprotov6.ReadDataSourceRequest) (*tfprotov6.ReadDataSourceResponse, error) { +func (s *Server) ReadDataSource(ctx context.Context, req *tfprotov6.ReadDataSourceRequest) (*tfprotov6.ReadDataSourceResponse, error) { ctx = s.registerContext(ctx) resp := &readDataSourceResponse{} @@ -1723,7 +1707,7 @@ func (s *server) ReadDataSource(ctx context.Context, req *tfprotov6.ReadDataSour return resp.toTfprotov6(), nil } -func (s *server) readDataSource(ctx context.Context, req *tfprotov6.ReadDataSourceRequest, resp *readDataSourceResponse) { +func (s *Server) readDataSource(ctx context.Context, req *tfprotov6.ReadDataSourceRequest, resp *readDataSourceResponse) { dataSourceType, diags := s.getDataSourceType(ctx, req.TypeName) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -1737,7 +1721,7 @@ func (s *server) readDataSource(ctx context.Context, req *tfprotov6.ReadDataSour return } logging.FrameworkDebug(ctx, "Calling provider defined DataSourceType NewDataSource") - dataSource, diags := dataSourceType.NewDataSource(ctx, s.p) + dataSource, diags := dataSourceType.NewDataSource(ctx, s.Provider) logging.FrameworkDebug(ctx, "Called provider defined DataSourceType NewDataSource") resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -1757,7 +1741,7 @@ func (s *server) readDataSource(ctx context.Context, req *tfprotov6.ReadDataSour Schema: dataSourceSchema, }, } - if pm, ok := s.p.(ProviderWithProviderMeta); ok { + if pm, ok := s.Provider.(ProviderWithProviderMeta); ok { logging.FrameworkTrace(ctx, "Provider implements ProviderWithProviderMeta") logging.FrameworkDebug(ctx, "Calling provider defined Provider GetMetaSchema") pmSchema, diags := pm.GetMetaSchema(ctx) diff --git a/tfsdk/serve_import.go b/tfsdk/serve_import.go index dea835107..ebe543d00 100644 --- a/tfsdk/serve_import.go +++ b/tfsdk/serve_import.go @@ -64,7 +64,7 @@ func (r importResourceStateResponse) toTfprotov6(ctx context.Context) *tfprotov6 return resp } -func (s *server) importResourceState(ctx context.Context, req *tfprotov6.ImportResourceStateRequest, resp *importResourceStateResponse) { +func (s *Server) importResourceState(ctx context.Context, req *tfprotov6.ImportResourceStateRequest, resp *importResourceStateResponse) { resourceType, diags := s.getResourceType(ctx, req.TypeName) resp.Diagnostics.Append(diags...) @@ -82,7 +82,7 @@ func (s *server) importResourceState(ctx context.Context, req *tfprotov6.ImportR } logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resource, diags := resourceType.NewResource(ctx, s.p) + resource, diags := resourceType.NewResource(ctx, s.Provider) logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") resp.Diagnostics.Append(diags...) @@ -148,7 +148,7 @@ func (s *server) importResourceState(ctx context.Context, req *tfprotov6.ImportR } // ImportResourceState satisfies the tfprotov6.ProviderServer interface. -func (s *server) ImportResourceState(ctx context.Context, req *tfprotov6.ImportResourceStateRequest) (*tfprotov6.ImportResourceStateResponse, error) { +func (s *Server) ImportResourceState(ctx context.Context, req *tfprotov6.ImportResourceStateRequest) (*tfprotov6.ImportResourceStateResponse, error) { ctx = s.registerContext(ctx) resp := &importResourceStateResponse{} diff --git a/tfsdk/serve_import_test.go b/tfsdk/serve_import_test.go index 0e43bec4d..78e91f40b 100644 --- a/tfsdk/serve_import_test.go +++ b/tfsdk/serve_import_test.go @@ -181,8 +181,8 @@ func TestServerImportResourceState(t *testing.T) { s := &testServeProvider{ importStateFunc: tc.impl, } - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } got, err := testServer.ImportResourceState(context.Background(), tc.req) diff --git a/tfsdk/serve_opts.go b/tfsdk/serve_opts.go index f39ce40fc..cfdf30aca 100644 --- a/tfsdk/serve_opts.go +++ b/tfsdk/serve_opts.go @@ -7,6 +7,9 @@ import ( ) // ServeOpts are options for serving the provider. +// +// Deprecated: Use providerserver.ServeOpts instead. This will be removed in +// the next minor version. type ServeOpts struct { // Address is the full address of the provider. Full address form has three // parts separated by forward slashes (/): Hostname, namespace, and diff --git a/tfsdk/serve_test.go b/tfsdk/serve_test.go index b62b15622..ded6c5aeb 100644 --- a/tfsdk/serve_test.go +++ b/tfsdk/serve_test.go @@ -16,37 +16,6 @@ import ( "github.com/hashicorp/terraform-plugin-go/tftypes" ) -func TestNewProtocol6ProviderServer(t *testing.T) { - provider := &testServeProvider{} - - providerServerFunc := NewProtocol6ProviderServer(provider) - providerServer := providerServerFunc() - - // Simple verification - _, err := providerServer.GetProviderSchema(context.Background(), &tfprotov6.GetProviderSchemaRequest{}) - - if err != nil { - t.Fatalf("unexpected error calling ProviderServer: %s", err) - } -} - -func TestNewProtocol6ProviderServerWithError(t *testing.T) { - provider := &testServeProvider{} - - providerServer, err := NewProtocol6ProviderServerWithError(provider)() - - if err != nil { - t.Fatalf("unexpected error creating ProviderServer: %s", err) - } - - // Simple verification - _, err = providerServer.GetProviderSchema(context.Background(), &tfprotov6.GetProviderSchemaRequest{}) - - if err != nil { - t.Fatalf("unexpected error calling ProviderServer: %s", err) - } -} - func TestServerCancelInFlightContexts(t *testing.T) { t.Parallel() @@ -56,7 +25,7 @@ func TestServerCancelInFlightContexts(t *testing.T) { // first, let's create a bunch of goroutines wg := new(sync.WaitGroup) - s := &server{} + s := &Server{} testCtx := context.Background() for i := 0; i < 10; i++ { wg.Add(1) @@ -295,8 +264,8 @@ func TestServerGetProviderSchema(t *testing.T) { t.Parallel() s := new(testServeProvider) - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } got, err := testServer.GetProviderSchema(context.Background(), new(tfprotov6.GetProviderSchemaRequest)) if err != nil { @@ -334,8 +303,8 @@ func TestServerGetProviderSchemaWithProviderMeta(t *testing.T) { t.Parallel() s := new(testServeProviderWithMetaSchema) - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } got, err := testServer.GetProviderSchema(context.Background(), new(tfprotov6.GetProviderSchemaRequest)) if err != nil { @@ -816,8 +785,8 @@ func TestServerValidateProviderConfig(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - testServer := &server{ - p: tc.provider, + testServer := &Server{ + Provider: tc.provider, } dv, err := tfprotov6.NewDynamicValue(tc.providerType, tc.config) @@ -1173,8 +1142,8 @@ func TestServerConfigureProvider(t *testing.T) { t.Parallel() s := new(testServeProvider) - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } dv, err := tfprotov6.NewDynamicValue(testServeProviderProviderType, tc.config) if err != nil { @@ -1414,8 +1383,8 @@ func TestServerValidateResourceConfig(t *testing.T) { s := &testServeProvider{ validateResourceConfigImpl: tc.impl, } - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } dv, err := tfprotov6.NewDynamicValue(tc.resourceType, tc.config) @@ -1720,8 +1689,8 @@ func TestServerUpgradeResourceState(t *testing.T) { ctx := context.Background() testProvider := &testServeProvider{} - testServer := &server{ - p: testProvider, + testServer := &Server{ + Provider: testProvider, } got, err := testServer.UpgradeResourceState(ctx, testCase.request) @@ -2141,13 +2110,13 @@ func TestServerReadResource(t *testing.T) { s := &testServeProvider{ readResourceImpl: tc.impl, } - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } var pmSchema Schema if tc.providerMeta.Type() != nil { sWithMeta := &testServeProviderWithMetaSchema{s} - testServer.p = sWithMeta + testServer.Provider = sWithMeta schema, diags := sWithMeta.GetMetaSchema(context.Background()) if len(diags) > 0 { t.Errorf("Unexpected diags: %+v", diags) @@ -4217,8 +4186,8 @@ func TestServerPlanResourceChange(t *testing.T) { s := &testServeProvider{ modifyPlanFunc: tc.modifyPlanFunc, } - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } priorStateDV, err := tfprotov6.NewDynamicValue(tc.resourceType, tc.priorState) @@ -5777,13 +5746,13 @@ func TestServerApplyResourceChange(t *testing.T) { updateFunc: tc.update, deleteFunc: tc.destroy, } - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } var pmSchema Schema if tc.providerMeta.Type() != nil { sWithMeta := &testServeProviderWithMetaSchema{s} - testServer.p = sWithMeta + testServer.Provider = sWithMeta schema, diags := sWithMeta.GetMetaSchema(context.Background()) if len(diags) > 0 { t.Errorf("Unexpected diags: %+v", diags) @@ -6107,8 +6076,8 @@ func TestServerValidateDataResourceConfig(t *testing.T) { s := &testServeProvider{ validateDataSourceConfigImpl: tc.impl, } - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } dv, err := tfprotov6.NewDynamicValue(tc.dataSourceType, tc.config) @@ -6299,13 +6268,13 @@ func TestServerReadDataSource(t *testing.T) { s := &testServeProvider{ readDataSourceImpl: tc.impl, } - testServer := &server{ - p: s, + testServer := &Server{ + Provider: s, } var pmSchema Schema if tc.providerMeta.Type() != nil { sWithMeta := &testServeProviderWithMetaSchema{s} - testServer.p = sWithMeta + testServer.Provider = sWithMeta schema, diags := sWithMeta.GetMetaSchema(context.Background()) if len(diags) > 0 { t.Errorf("Unexpected diags: %+v", diags)