Skip to content
Draft
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
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ toolchain go1.24.4

require (
github.com/google/go-cmp v0.7.0
github.com/hashicorp/terraform-plugin-go v0.29.0
github.com/hashicorp/terraform-plugin-go v0.29.1-0.20251112131031-c841d34ce2f2
github.com/hashicorp/terraform-plugin-log v0.9.0
google.golang.org/grpc v1.75.1
google.golang.org/grpc v1.76.0
)

require (
Expand All @@ -29,6 +29,6 @@ require (
golang.org/x/net v0.43.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
google.golang.org/protobuf v1.36.9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
google.golang.org/protobuf v1.36.10 // indirect
)
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshf
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
github.com/hashicorp/terraform-plugin-go v0.29.1-0.20251112131031-c841d34ce2f2 h1:GxLILx5hl084NZFVBc6rdzKrJ5DL8MYNaQapmXFcOHY=
github.com/hashicorp/terraform-plugin-go v0.29.1-0.20251112131031-c841d34ce2f2/go.mod h1:KHRnT9vExG+r1fLxwOzOP6C6YXiaKHtsCIrky7teDYc=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
Expand Down Expand Up @@ -86,12 +86,12 @@ golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
10 changes: 10 additions & 0 deletions tf5muxserver/diagnostics.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ func ephemeralResourceMissingError(typeName string) *tfprotov5.Diagnostic {
}
}

func generateResourceConfigMissingError(typeName string) *tfprotov5.Diagnostic {
return &tfprotov5.Diagnostic{
Severity: tfprotov5.DiagnosticSeverityError,
Summary: "Generate Resource Config Not Implemented",
Detail: "The combined provider does not implement the requested generate resource config for the resource type. " +
"This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" +
"Missing generate resource config for resource type: " + typeName,
}
}

func listResourceDuplicateError(typeName string) *tfprotov5.Diagnostic {
return &tfprotov5.Diagnostic{
Severity: tfprotov5.DiagnosticSeverityError,
Expand Down
41 changes: 40 additions & 1 deletion tf5muxserver/mux_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"context"
"sync"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-mux/internal/logging"
)

Expand Down Expand Up @@ -65,6 +65,10 @@ func (s *muxServer) ProviderServer() tfprotov5.ProviderServer {
return s
}

func (s *muxServer) ProviderServers() []tfprotov5.ProviderServer {
return s.servers
}

func (s *muxServer) getActionServer(ctx context.Context, actionType string) (tfprotov5.ProviderServer, []*tfprotov5.Diagnostic, error) {
s.serverDiscoveryMutex.RLock()
server, ok := s.actions[actionType]
Expand Down Expand Up @@ -170,6 +174,41 @@ func (s *muxServer) getEphemeralResourceServer(ctx context.Context, typeName str
return server, s.serverDiscoveryDiagnostics, nil
}

func (s *muxServer) getGenerateResourceConfigServer(ctx context.Context, typeName string) (tfprotov5.ProviderServer, []*tfprotov5.Diagnostic, error) {
s.serverDiscoveryMutex.RLock()
server, ok := s.resources[typeName]
discoveryComplete := s.serverDiscoveryComplete
s.serverDiscoveryMutex.RUnlock()

if discoveryComplete {
if ok {
return server, s.serverDiscoveryDiagnostics, nil
}

return nil, []*tfprotov5.Diagnostic{
generateResourceConfigMissingError(typeName),
}, nil
}

err := s.serverDiscovery(ctx)

if err != nil || diagnosticsHasError(s.serverDiscoveryDiagnostics) {
return nil, s.serverDiscoveryDiagnostics, err
}

s.serverDiscoveryMutex.RLock()
server, ok = s.resources[typeName]
s.serverDiscoveryMutex.RUnlock()

if !ok {
return nil, []*tfprotov5.Diagnostic{
generateResourceConfigMissingError(typeName),
}, nil
}

return server, s.serverDiscoveryDiagnostics, nil
}

func (s *muxServer) getListResourceServer(ctx context.Context, typeName string) (tfprotov5.ProviderServer, []*tfprotov5.Diagnostic, error) {
s.serverDiscoveryMutex.RLock()
server, ok := s.listResources[typeName]
Expand Down
52 changes: 52 additions & 0 deletions tf5muxserver/mux_server_GenerateResourceConfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tf5muxserver

import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-mux/internal/logging"
)

func (s *muxServer) GenerateResourceConfig(ctx context.Context, req *tfprotov5.GenerateResourceConfigRequest) (*tfprotov5.GenerateResourceConfigResponse, error) {
rpc := "GenerateResourceConfig"
ctx = logging.InitContext(ctx)
ctx = logging.RpcContext(ctx, rpc)

server, diags, err := s.getGenerateResourceConfigServer(ctx, req.TypeName)

if err != nil {
return nil, err
}

// If there is an error diagnostic, return it directly
if diagnosticsHasError(diags) {
return &tfprotov5.GenerateResourceConfigResponse{
Diagnostics: diags,
}, nil
}

// TODO: Remove and call server.GenerateResourceConfig below directly once interface becomes required.
generateResourceConfigServer, ok := server.(tfprotov5.GenerateResourceConfigServer)
if !ok {
resp := &tfprotov5.GenerateResourceConfigResponse{
Diagnostics: []*tfprotov5.Diagnostic{
{
Severity: tfprotov5.DiagnosticSeverityError,
Summary: "GenerateResourceConfig Not Implemented",
Detail: "A GenerateResourceConfig call was received by the provider, however the provider does not implement GenerateResourceConfig. " +
"Either upgrade the provider to a version that implements GenerateResourceConfig or this is a bug in Terraform that should be reported to the Terraform maintainers.",
},
},
}

return resp, nil
}

ctx = logging.Tfprotov5ProviderServerContext(ctx, server)
logging.MuxTrace(ctx, "calling downstream server")

return generateResourceConfigServer.GenerateResourceConfig(ctx, req)
}
13 changes: 13 additions & 0 deletions tf5muxserver/mux_server_GetMetadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"duplicate-action": {
Expand Down Expand Up @@ -234,6 +235,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"duplicate-data-source-type": {
Expand Down Expand Up @@ -281,6 +283,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"duplicate-ephemeral-resource-type": {
Expand Down Expand Up @@ -328,6 +331,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"duplicate-list-resource-type": {
Expand Down Expand Up @@ -375,6 +379,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"duplicate-function": {
Expand Down Expand Up @@ -422,6 +427,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"duplicate-resource-type": {
Expand Down Expand Up @@ -469,6 +475,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"server-capabilities": {
Expand Down Expand Up @@ -514,6 +521,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"error-once": {
Expand Down Expand Up @@ -549,6 +557,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"error-multiple": {
Expand Down Expand Up @@ -599,6 +608,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"warning-once": {
Expand Down Expand Up @@ -634,6 +644,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"warning-multiple": {
Expand Down Expand Up @@ -684,6 +695,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
"warning-then-error": {
Expand Down Expand Up @@ -734,6 +746,7 @@ func TestMuxServerGetMetadata(t *testing.T) {
GetProviderSchemaOptional: true,
MoveResourceState: true,
PlanDestroy: true,
GenerateResourceConfig: true,
},
},
}
Expand Down
Loading