From 19729fb6b4636321bb951c92e16606a7c4b6d308 Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Tue, 21 Jan 2025 17:29:55 -0500 Subject: [PATCH 1/2] tfprotov5+tfprotov6: Require `EphemeralResourceServer` in `ProviderServer` --- tfprotov5/provider.go | 20 ++----- tfprotov5/tf5server/server.go | 108 ++-------------------------------- tfprotov6/provider.go | 20 ++----- tfprotov6/tf6server/server.go | 108 ++-------------------------------- 4 files changed, 16 insertions(+), 240 deletions(-) diff --git a/tfprotov5/provider.go b/tfprotov5/provider.go index 41e850bf6..19fea3b8f 100644 --- a/tfprotov5/provider.go +++ b/tfprotov5/provider.go @@ -54,24 +54,12 @@ type ProviderServer interface { // terraform-plugin-go, so they are their own interface that is composed // into ProviderServer. FunctionServer -} - -// ProviderServerWithEphemeralResources is a temporary interface for servers -// to implement Ephemeral Resource RPC handling with: -// -// - ValidateEphemeralResourceConfig -// - OpenEphemeralResource -// - RenewEphemeralResource -// - CloseEphemeralResource -// -// Deprecated: The EphemeralResourceServer methods will be moved into the -// ProviderServer interface and this interface will be removed in a future -// version. -type ProviderServerWithEphemeralResources interface { - ProviderServer // EphemeralResourceServer is an interface encapsulating all the ephemeral - // resource-related RPC requests. + // resource-related RPC requests. ProviderServer implementations must + // implement them, but they are a handy interface for defining what an + // ephemeral resource is to terraform-plugin-go, so they're their own + // interface that is composed into ProviderServer. EphemeralResourceServer } diff --git a/tfprotov5/tf5server/server.go b/tfprotov5/tf5server/server.go index e40d49ceb..e1334e70a 100644 --- a/tfprotov5/tf5server/server.go +++ b/tfprotov5/tf5server/server.go @@ -1012,38 +1012,13 @@ func (s *server) ValidateEphemeralResourceConfig(ctx context.Context, protoReq * logging.ProtocolTrace(ctx, "Received request") defer logging.ProtocolTrace(ctx, "Served request") - // TODO: Remove this check and error in preference of - // s.downstream.ValidateEphemeralResourceConfig below once ProviderServer interface - // implements the EphemeralResourceServer RPC methods. - // nolint:staticcheck - ephemeralResourceProviderServer, ok := s.downstream.(tfprotov5.ProviderServerWithEphemeralResources) - if !ok { - logging.ProtocolError(ctx, "ProviderServer does not implement ValidateEphemeralResourceConfig") - - protoResp := &tfplugin5.ValidateEphemeralResourceConfig_Response{ - Diagnostics: []*tfplugin5.Diagnostic{ - { - Severity: tfplugin5.Diagnostic_ERROR, - Summary: "Provider Validate Ephemeral Resource Config Not Implemented", - Detail: "A ValidateEphemeralResourceConfig call was received by the provider, however the provider does not implement the call. " + - "Either upgrade the provider to a version that implements ephemeral resource support or this is a bug in Terraform that should be reported to the Terraform maintainers.", - }, - }, - } - - return protoResp, nil - } - req := fromproto.ValidateEphemeralResourceConfigRequest(protoReq) logging.ProtocolData(ctx, s.protocolDataDir, rpc, "Request", "Config", req.Config) ctx = tf5serverlogging.DownstreamRequest(ctx) - // TODO: Update this to call downstream once optional interface is removed - // resp, err := s.downstream.ValidateEphemeralResourceConfig(ctx, req) - resp, err := ephemeralResourceProviderServer.ValidateEphemeralResourceConfig(ctx, req) - + resp, err := s.downstream.ValidateEphemeralResourceConfig(ctx, req) if err != nil { logging.ProtocolError(ctx, "Error from downstream", map[string]any{logging.KeyError: err}) return nil, err @@ -1065,38 +1040,13 @@ func (s *server) OpenEphemeralResource(ctx context.Context, protoReq *tfplugin5. logging.ProtocolTrace(ctx, "Received request") defer logging.ProtocolTrace(ctx, "Served request") - // TODO: Remove this check and error in preference of - // s.downstream.OpenEphemeralResource below once ProviderServer interface - // implements the EphemeralResourceServer RPC methods. - // nolint:staticcheck - ephemeralResourceProviderServer, ok := s.downstream.(tfprotov5.ProviderServerWithEphemeralResources) - if !ok { - logging.ProtocolError(ctx, "ProviderServer does not implement OpenEphemeralResource") - - protoResp := &tfplugin5.OpenEphemeralResource_Response{ - Diagnostics: []*tfplugin5.Diagnostic{ - { - Severity: tfplugin5.Diagnostic_ERROR, - Summary: "Provider Open Ephemeral Resource Not Implemented", - Detail: "A OpenEphemeralResource call was received by the provider, however the provider does not implement the call. " + - "Either upgrade the provider to a version that implements ephemeral resource support or this is a bug in Terraform that should be reported to the Terraform maintainers.", - }, - }, - } - - return protoResp, nil - } - req := fromproto.OpenEphemeralResourceRequest(protoReq) tf5serverlogging.OpenEphemeralResourceClientCapabilities(ctx, req.ClientCapabilities) logging.ProtocolData(ctx, s.protocolDataDir, rpc, "Request", "Config", req.Config) ctx = tf5serverlogging.DownstreamRequest(ctx) - // TODO: Update this to call downstream once optional interface is removed - // resp, err := s.downstream.OpenEphemeralResource(ctx, req) - resp, err := ephemeralResourceProviderServer.OpenEphemeralResource(ctx, req) - + resp, err := s.downstream.OpenEphemeralResource(ctx, req) if err != nil { logging.ProtocolError(ctx, "Error from downstream", map[string]any{logging.KeyError: err}) return nil, err @@ -1124,36 +1074,11 @@ func (s *server) RenewEphemeralResource(ctx context.Context, protoReq *tfplugin5 logging.ProtocolTrace(ctx, "Received request") defer logging.ProtocolTrace(ctx, "Served request") - // TODO: Remove this check and error in preference of - // s.downstream.RenewEphemeralResource below once ProviderServer interface - // implements the EphemeralResourceServer RPC methods. - // nolint:staticcheck - ephemeralResourceProviderServer, ok := s.downstream.(tfprotov5.ProviderServerWithEphemeralResources) - if !ok { - logging.ProtocolError(ctx, "ProviderServer does not implement RenewEphemeralResource") - - protoResp := &tfplugin5.RenewEphemeralResource_Response{ - Diagnostics: []*tfplugin5.Diagnostic{ - { - Severity: tfplugin5.Diagnostic_ERROR, - Summary: "Provider Renew Ephemeral Resource Not Implemented", - Detail: "A RenewEphemeralResource call was received by the provider, however the provider does not implement the call. " + - "Either upgrade the provider to a version that implements ephemeral resource support or this is a bug in Terraform that should be reported to the Terraform maintainers.", - }, - }, - } - - return protoResp, nil - } - req := fromproto.RenewEphemeralResourceRequest(protoReq) ctx = tf5serverlogging.DownstreamRequest(ctx) - // TODO: Update this to call downstream once optional interface is removed - // resp, err := s.downstream.RenewEphemeralResource(ctx, req) - resp, err := ephemeralResourceProviderServer.RenewEphemeralResource(ctx, req) - + resp, err := s.downstream.RenewEphemeralResource(ctx, req) if err != nil { logging.ProtocolError(ctx, "Error from downstream", map[string]any{logging.KeyError: err}) return nil, err @@ -1175,36 +1100,11 @@ func (s *server) CloseEphemeralResource(ctx context.Context, protoReq *tfplugin5 logging.ProtocolTrace(ctx, "Received request") defer logging.ProtocolTrace(ctx, "Served request") - // TODO: Remove this check and error in preference of - // s.downstream.CloseEphemeralResource below once ProviderServer interface - // implements the EphemeralResourceServer RPC methods. - // nolint:staticcheck - ephemeralResourceProviderServer, ok := s.downstream.(tfprotov5.ProviderServerWithEphemeralResources) - if !ok { - logging.ProtocolError(ctx, "ProviderServer does not implement CloseEphemeralResource") - - protoResp := &tfplugin5.CloseEphemeralResource_Response{ - Diagnostics: []*tfplugin5.Diagnostic{ - { - Severity: tfplugin5.Diagnostic_ERROR, - Summary: "Provider Close Ephemeral Resource Not Implemented", - Detail: "A CloseEphemeralResource call was received by the provider, however the provider does not implement the call. " + - "Either upgrade the provider to a version that implements ephemeral resource support or this is a bug in Terraform that should be reported to the Terraform maintainers.", - }, - }, - } - - return protoResp, nil - } - req := fromproto.CloseEphemeralResourceRequest(protoReq) ctx = tf5serverlogging.DownstreamRequest(ctx) - // TODO: Update this to call downstream once optional interface is removed - // resp, err := s.downstream.CloseEphemeralResource(ctx, req) - resp, err := ephemeralResourceProviderServer.CloseEphemeralResource(ctx, req) - + resp, err := s.downstream.CloseEphemeralResource(ctx, req) if err != nil { logging.ProtocolError(ctx, "Error from downstream", map[string]any{logging.KeyError: err}) return nil, err diff --git a/tfprotov6/provider.go b/tfprotov6/provider.go index e6892bade..6776a9d0b 100644 --- a/tfprotov6/provider.go +++ b/tfprotov6/provider.go @@ -54,24 +54,12 @@ type ProviderServer interface { // terraform-plugin-go, so they are their own interface that is composed // into ProviderServer. FunctionServer -} - -// ProviderServerWithEphemeralResources is a temporary interface for servers -// to implement Ephemeral Resource RPC handling with: -// -// - ValidateEphemeralResourceConfig -// - OpenEphemeralResource -// - RenewEphemeralResource -// - CloseEphemeralResource -// -// Deprecated: The EphemeralResourceServer methods will be moved into the -// ProviderServer interface and this interface will be removed in a future -// version. -type ProviderServerWithEphemeralResources interface { - ProviderServer // EphemeralResourceServer is an interface encapsulating all the ephemeral - // resource-related RPC requests. + // resource-related RPC requests. ProviderServer implementations must + // implement them, but they are a handy interface for defining what an + // ephemeral resource is to terraform-plugin-go, so they're their own + // interface that is composed into ProviderServer. EphemeralResourceServer } diff --git a/tfprotov6/tf6server/server.go b/tfprotov6/tf6server/server.go index 2f06cc2c5..cb5a751d8 100644 --- a/tfprotov6/tf6server/server.go +++ b/tfprotov6/tf6server/server.go @@ -1012,38 +1012,13 @@ func (s *server) ValidateEphemeralResourceConfig(ctx context.Context, protoReq * logging.ProtocolTrace(ctx, "Received request") defer logging.ProtocolTrace(ctx, "Served request") - // TODO: Remove this check and error in preference of - // s.downstream.ValidateEphemeralResourceConfig below once ProviderServer interface - // implements the EphemeralResourceServer RPC methods. - // nolint:staticcheck - ephemeralResourceProviderServer, ok := s.downstream.(tfprotov6.ProviderServerWithEphemeralResources) - if !ok { - logging.ProtocolError(ctx, "ProviderServer does not implement ValidateEphemeralResourceConfig") - - protoResp := &tfplugin6.ValidateEphemeralResourceConfig_Response{ - Diagnostics: []*tfplugin6.Diagnostic{ - { - Severity: tfplugin6.Diagnostic_ERROR, - Summary: "Provider Validate Ephemeral Resource Config Not Implemented", - Detail: "A ValidateEphemeralResourceConfig call was received by the provider, however the provider does not implement the call. " + - "Either upgrade the provider to a version that implements ephemeral resource support or this is a bug in Terraform that should be reported to the Terraform maintainers.", - }, - }, - } - - return protoResp, nil - } - req := fromproto.ValidateEphemeralResourceConfigRequest(protoReq) logging.ProtocolData(ctx, s.protocolDataDir, rpc, "Request", "Config", req.Config) ctx = tf6serverlogging.DownstreamRequest(ctx) - // TODO: Update this to call downstream once optional interface is removed - // resp, err := s.downstream.ValidateEphemeralResourceConfig(ctx, req) - resp, err := ephemeralResourceProviderServer.ValidateEphemeralResourceConfig(ctx, req) - + resp, err := s.downstream.ValidateEphemeralResourceConfig(ctx, req) if err != nil { logging.ProtocolError(ctx, "Error from downstream", map[string]any{logging.KeyError: err}) return nil, err @@ -1065,28 +1040,6 @@ func (s *server) OpenEphemeralResource(ctx context.Context, protoReq *tfplugin6. logging.ProtocolTrace(ctx, "Received request") defer logging.ProtocolTrace(ctx, "Served request") - // TODO: Remove this check and error in preference of - // s.downstream.OpenEphemeralResource below once ProviderServer interface - // implements the EphemeralResourceServer RPC methods. - // nolint:staticcheck - ephemeralResourceProviderServer, ok := s.downstream.(tfprotov6.ProviderServerWithEphemeralResources) - if !ok { - logging.ProtocolError(ctx, "ProviderServer does not implement OpenEphemeralResource") - - protoResp := &tfplugin6.OpenEphemeralResource_Response{ - Diagnostics: []*tfplugin6.Diagnostic{ - { - Severity: tfplugin6.Diagnostic_ERROR, - Summary: "Provider Open Ephemeral Resource Not Implemented", - Detail: "A OpenEphemeralResource call was received by the provider, however the provider does not implement the call. " + - "Either upgrade the provider to a version that implements ephemeral resource support or this is a bug in Terraform that should be reported to the Terraform maintainers.", - }, - }, - } - - return protoResp, nil - } - req := fromproto.OpenEphemeralResourceRequest(protoReq) tf6serverlogging.OpenEphemeralResourceClientCapabilities(ctx, req.ClientCapabilities) @@ -1094,10 +1047,7 @@ func (s *server) OpenEphemeralResource(ctx context.Context, protoReq *tfplugin6. ctx = tf6serverlogging.DownstreamRequest(ctx) - // TODO: Update this to call downstream once optional interface is removed - // resp, err := s.downstream.OpenEphemeralResource(ctx, req) - resp, err := ephemeralResourceProviderServer.OpenEphemeralResource(ctx, req) - + resp, err := s.downstream.OpenEphemeralResource(ctx, req) if err != nil { logging.ProtocolError(ctx, "Error from downstream", map[string]any{logging.KeyError: err}) return nil, err @@ -1125,36 +1075,11 @@ func (s *server) RenewEphemeralResource(ctx context.Context, protoReq *tfplugin6 logging.ProtocolTrace(ctx, "Received request") defer logging.ProtocolTrace(ctx, "Served request") - // TODO: Remove this check and error in preference of - // s.downstream.RenewEphemeralResource below once ProviderServer interface - // implements the EphemeralResourceServer RPC methods. - // nolint:staticcheck - ephemeralResourceProviderServer, ok := s.downstream.(tfprotov6.ProviderServerWithEphemeralResources) - if !ok { - logging.ProtocolError(ctx, "ProviderServer does not implement RenewEphemeralResource") - - protoResp := &tfplugin6.RenewEphemeralResource_Response{ - Diagnostics: []*tfplugin6.Diagnostic{ - { - Severity: tfplugin6.Diagnostic_ERROR, - Summary: "Provider Renew Ephemeral Resource Not Implemented", - Detail: "A RenewEphemeralResource call was received by the provider, however the provider does not implement the call. " + - "Either upgrade the provider to a version that implements ephemeral resource support or this is a bug in Terraform that should be reported to the Terraform maintainers.", - }, - }, - } - - return protoResp, nil - } - req := fromproto.RenewEphemeralResourceRequest(protoReq) ctx = tf6serverlogging.DownstreamRequest(ctx) - // TODO: Update this to call downstream once optional interface is removed - // resp, err := s.downstream.RenewEphemeralResource(ctx, req) - resp, err := ephemeralResourceProviderServer.RenewEphemeralResource(ctx, req) - + resp, err := s.downstream.RenewEphemeralResource(ctx, req) if err != nil { logging.ProtocolError(ctx, "Error from downstream", map[string]any{logging.KeyError: err}) return nil, err @@ -1176,36 +1101,11 @@ func (s *server) CloseEphemeralResource(ctx context.Context, protoReq *tfplugin6 logging.ProtocolTrace(ctx, "Received request") defer logging.ProtocolTrace(ctx, "Served request") - // TODO: Remove this check and error in preference of - // s.downstream.CloseEphemeralResource below once ProviderServer interface - // implements the EphemeralResourceServer RPC methods. - // nolint:staticcheck - ephemeralResourceProviderServer, ok := s.downstream.(tfprotov6.ProviderServerWithEphemeralResources) - if !ok { - logging.ProtocolError(ctx, "ProviderServer does not implement CloseEphemeralResource") - - protoResp := &tfplugin6.CloseEphemeralResource_Response{ - Diagnostics: []*tfplugin6.Diagnostic{ - { - Severity: tfplugin6.Diagnostic_ERROR, - Summary: "Provider Close Ephemeral Resource Not Implemented", - Detail: "A CloseEphemeralResource call was received by the provider, however the provider does not implement the call. " + - "Either upgrade the provider to a version that implements ephemeral resource support or this is a bug in Terraform that should be reported to the Terraform maintainers.", - }, - }, - } - - return protoResp, nil - } - req := fromproto.CloseEphemeralResourceRequest(protoReq) ctx = tf6serverlogging.DownstreamRequest(ctx) - // TODO: Update this to call downstream once optional interface is removed - // resp, err := s.downstream.CloseEphemeralResource(ctx, req) - resp, err := ephemeralResourceProviderServer.CloseEphemeralResource(ctx, req) - + resp, err := s.downstream.CloseEphemeralResource(ctx, req) if err != nil { logging.ProtocolError(ctx, "Error from downstream", map[string]any{logging.KeyError: err}) return nil, err From 933709cd4c2b68a7f5e5b9932f76d68b41cfe6ed Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Tue, 21 Jan 2025 17:45:48 -0500 Subject: [PATCH 2/2] add changelogs --- .changes/unreleased/BREAKING CHANGES-20250121-173556.yaml | 7 +++++++ .changes/unreleased/BREAKING CHANGES-20250121-174509.yaml | 6 ++++++ .changes/unreleased/NOTES-20250121-173653.yaml | 7 +++++++ 3 files changed, 20 insertions(+) create mode 100644 .changes/unreleased/BREAKING CHANGES-20250121-173556.yaml create mode 100644 .changes/unreleased/BREAKING CHANGES-20250121-174509.yaml create mode 100644 .changes/unreleased/NOTES-20250121-173653.yaml diff --git a/.changes/unreleased/BREAKING CHANGES-20250121-173556.yaml b/.changes/unreleased/BREAKING CHANGES-20250121-173556.yaml new file mode 100644 index 000000000..1bbf8d18e --- /dev/null +++ b/.changes/unreleased/BREAKING CHANGES-20250121-173556.yaml @@ -0,0 +1,7 @@ +kind: BREAKING CHANGES +body: 'tfprotov5+tfprotov6: `EphemeralResourceServer` interface is now required in + `ProviderServer`. Implementations not needing ephemeral resource support can return + errors from the `*EphemeralResource` methods.' +time: 2025-01-21T17:35:56.137392-05:00 +custom: + Issue: "442" diff --git a/.changes/unreleased/BREAKING CHANGES-20250121-174509.yaml b/.changes/unreleased/BREAKING CHANGES-20250121-174509.yaml new file mode 100644 index 000000000..7d3bafc2b --- /dev/null +++ b/.changes/unreleased/BREAKING CHANGES-20250121-174509.yaml @@ -0,0 +1,6 @@ +kind: BREAKING CHANGES +body: 'tfprotov5+tfprotov6: Removed temporary `ProviderServerWithEphemeralResources` + interface type. Use `EphemeralResourceServer` instead.' +time: 2025-01-21T17:45:09.953934-05:00 +custom: + Issue: "442" diff --git a/.changes/unreleased/NOTES-20250121-173653.yaml b/.changes/unreleased/NOTES-20250121-173653.yaml new file mode 100644 index 000000000..9b4620a13 --- /dev/null +++ b/.changes/unreleased/NOTES-20250121-173653.yaml @@ -0,0 +1,7 @@ +kind: NOTES +body: 'all: To prevent compilation errors, ensure your Go module is updated to at least + terraform-plugin-framework@v1.13.0, terraform-plugin-mux@v0.17.0, terraform-plugin-sdk/v2@v2.35.0, + and terraform-plugin-testing@v1.11.0 before upgrading this dependency.' +time: 2025-01-21T17:36:53.645571-05:00 +custom: + Issue: "442"