Skip to content

Commit

Permalink
tfprotov5+tfprotov6: Require EphemeralResourceServer in `ProviderSe…
Browse files Browse the repository at this point in the history
…rver` (#465)

* tfprotov5+tfprotov6: Require `EphemeralResourceServer` in `ProviderServer`

* add changelogs
  • Loading branch information
austinvalle authored Jan 22, 2025
1 parent afd18f1 commit 7ff6ef6
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 240 deletions.
7 changes: 7 additions & 0 deletions .changes/unreleased/BREAKING CHANGES-20250121-173556.yaml
Original file line number Diff line number Diff line change
@@ -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"
6 changes: 6 additions & 0 deletions .changes/unreleased/BREAKING CHANGES-20250121-174509.yaml
Original file line number Diff line number Diff line change
@@ -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"
7 changes: 7 additions & 0 deletions .changes/unreleased/NOTES-20250121-173653.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kind: NOTES
body: 'all: To prevent compilation errors, ensure your Go module is updated to at least
[email protected], [email protected], terraform-plugin-sdk/[email protected],
and [email protected] before upgrading this dependency.'
time: 2025-01-21T17:36:53.645571-05:00
custom:
Issue: "442"
20 changes: 4 additions & 16 deletions tfprotov5/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
108 changes: 4 additions & 104 deletions tfprotov5/tf5server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1013,38 +1013,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
Expand All @@ -1066,38 +1041,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
Expand Down Expand Up @@ -1125,36 +1075,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
Expand All @@ -1176,36 +1101,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
Expand Down
20 changes: 4 additions & 16 deletions tfprotov6/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
108 changes: 4 additions & 104 deletions tfprotov6/tf6server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1013,38 +1013,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
Expand All @@ -1066,39 +1041,14 @@ 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)
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.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
Expand Down Expand Up @@ -1126,36 +1076,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
Expand All @@ -1177,36 +1102,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
Expand Down

0 comments on commit 7ff6ef6

Please sign in to comment.