Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tfprotov5+tfprotov6: Require EphemeralResourceServer in ProviderServer #465

Merged
merged 3 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading