Skip to content

Commit 2585244

Browse files
authored
plugin: Always forward tf6server close channel (#905)
Replicating the `tf5server` close channel handling right above it -- it was a copy-paste miss on my part. Without this, `tf6server` (such as terraform-plugin-framework providers) will hang until test timeouts. As part of troubleshooting this, was able to add some helpful trace and debug logging for future travelers. Also, CI has been updated to run all terraform-provider-corner testing.
1 parent 42342e3 commit 2585244

File tree

6 files changed

+57
-15
lines changed

6 files changed

+57
-15
lines changed

.github/workflows/ci-go.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ name: ci-go
44
on:
55
pull_request:
66
paths:
7-
- .github/workflows/test.yml
7+
- .github/workflows/ci-go.yml
88
- .golangci.yml
99
- .go-version
1010
- go.mod
@@ -48,7 +48,7 @@ jobs:
4848
go-version: ${{ steps.go-version.outputs.version }}
4949
- run: go mod edit -replace=github.com/hashicorp/terraform-plugin-sdk/v2=../
5050
- run: go mod tidy
51-
- run: go test -v ./internal/sdkv2provider
51+
- run: go test -v ./...
5252
env:
5353
TF_ACC: '1'
5454
test:

helper/resource/plugin.go

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
1515
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
1616
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
17+
"github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging"
1718
"github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest"
1819
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
1920
testing "github.com/mitchellh/go-testing-interface"
@@ -69,12 +70,17 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
6970
// providerName may be returned as terraform-provider-foo, and
7071
// we need just foo. So let's fix that.
7172
providerName = strings.TrimPrefix(providerName, "terraform-provider-")
73+
providerAddress := getProviderAddr(providerName)
74+
75+
logging.HelperResourceDebug(ctx, "Creating sdkv2 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
7276

7377
provider, err := factory()
7478
if err != nil {
7579
return fmt.Errorf("unable to create provider %q from factory: %w", providerName, err)
7680
}
7781

82+
logging.HelperResourceDebug(ctx, "Created sdkv2 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
83+
7884
// keep track of the running factory, so we can make sure it's
7985
// shut down.
8086
wg.Add(1)
@@ -94,14 +100,18 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
94100
}),
95101
NoLogOutputOverride: true,
96102
UseTFLogSink: t,
97-
ProviderAddr: getProviderAddr(providerName),
103+
ProviderAddr: providerAddress,
98104
}
99105

100-
// let's actually start the provider server
106+
logging.HelperResourceDebug(ctx, "Starting sdkv2 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
107+
101108
config, closeCh, err := plugin.DebugServe(ctx, opts)
102109
if err != nil {
103110
return fmt.Errorf("unable to serve provider %q: %w", providerName, err)
104111
}
112+
113+
logging.HelperResourceDebug(ctx, "Started sdkv2 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
114+
105115
tfexecConfig := tfexec.ReattachConfig{
106116
Protocol: config.Protocol,
107117
ProtocolVersion: config.ProtocolVersion,
@@ -136,6 +146,7 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
136146
// providerName may be returned as terraform-provider-foo, and
137147
// we need just foo. So let's fix that.
138148
providerName = strings.TrimPrefix(providerName, "terraform-provider-")
149+
providerAddress := getProviderAddr(providerName)
139150

140151
// If the user has supplied the same provider in both
141152
// ProviderFactories and ProtoV5ProviderFactories, they made a
@@ -149,11 +160,15 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
149160
}
150161
}
151162

163+
logging.HelperResourceDebug(ctx, "Creating tfprotov5 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
164+
152165
provider, err := factory()
153166
if err != nil {
154167
return fmt.Errorf("unable to create provider %q from factory: %w", providerName, err)
155168
}
156169

170+
logging.HelperResourceDebug(ctx, "Created tfprotov5 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
171+
157172
// keep track of the running factory, so we can make sure it's
158173
// shut down.
159174
wg.Add(1)
@@ -173,14 +188,18 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
173188
}),
174189
NoLogOutputOverride: true,
175190
UseTFLogSink: t,
176-
ProviderAddr: getProviderAddr(providerName),
191+
ProviderAddr: providerAddress,
177192
}
178193

179-
// let's actually start the provider server
194+
logging.HelperResourceDebug(ctx, "Starting tfprotov5 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
195+
180196
config, closeCh, err := plugin.DebugServe(ctx, opts)
181197
if err != nil {
182198
return fmt.Errorf("unable to serve provider %q: %w", providerName, err)
183199
}
200+
201+
logging.HelperResourceDebug(ctx, "Started tfprotov5 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
202+
184203
tfexecConfig := tfexec.ReattachConfig{
185204
Protocol: config.Protocol,
186205
ProtocolVersion: config.ProtocolVersion,
@@ -216,6 +235,7 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
216235
// providerName may be returned as terraform-provider-foo, and
217236
// we need just foo. So let's fix that.
218237
providerName = strings.TrimPrefix(providerName, "terraform-provider-")
238+
providerAddress := getProviderAddr(providerName)
219239

220240
// If the user has already registered this provider in
221241
// ProviderFactories or ProtoV5ProviderFactories, they made a
@@ -229,11 +249,15 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
229249
}
230250
}
231251

252+
logging.HelperResourceDebug(ctx, "Creating tfprotov6 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
253+
232254
provider, err := factory()
233255
if err != nil {
234256
return fmt.Errorf("unable to create provider %q from factory: %w", providerName, err)
235257
}
236258

259+
logging.HelperResourceDebug(ctx, "Created tfprotov6 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
260+
237261
// keep track of the running factory, so we can make sure it's
238262
// shut down.
239263
wg.Add(1)
@@ -249,15 +273,18 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
249273
}),
250274
NoLogOutputOverride: true,
251275
UseTFLogSink: t,
252-
ProviderAddr: getProviderAddr(providerName),
276+
ProviderAddr: providerAddress,
253277
}
254278

255-
// let's actually start the provider server
279+
logging.HelperResourceDebug(ctx, "Starting tfprotov6 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
280+
256281
config, closeCh, err := plugin.DebugServe(ctx, opts)
257282
if err != nil {
258283
return fmt.Errorf("unable to serve provider %q: %w", providerName, err)
259284
}
260285

286+
logging.HelperResourceDebug(ctx, "Started tfprotov6 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress})
287+
261288
tfexecConfig := tfexec.ReattachConfig{
262289
Protocol: config.Protocol,
263290
ProtocolVersion: config.ProtocolVersion,
@@ -289,7 +316,9 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
289316

290317
// set the working directory reattach info that will tell Terraform how to
291318
// connect to our various running servers.
292-
wd.SetReattachInfo(reattachInfo)
319+
wd.SetReattachInfo(ctx, reattachInfo)
320+
321+
logging.HelperResourceTrace(ctx, "Calling wrapped Terraform CLI command")
293322

294323
// ok, let's call whatever Terraform command the test was trying to
295324
// call, now that we know it'll attach back to those servers we just
@@ -299,16 +328,23 @@ func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *pl
299328
log.Printf("[WARN] Got error running Terraform: %s", err)
300329
}
301330

331+
logging.HelperResourceTrace(ctx, "Called wrapped Terraform CLI command")
332+
logging.HelperResourceDebug(ctx, "Stopping providers")
333+
302334
// cancel the servers so they'll return. Otherwise, this closeCh won't
303335
// get closed, and we'll hang here.
304336
cancel()
305337

338+
logging.HelperResourceTrace(ctx, "Waiting for providers to stop")
339+
306340
// wait for the servers to actually shut down; it may take a moment for
307341
// them to clean up, or whatever.
308342
// TODO: add a timeout here?
309343
// PC: do we need one? The test will time out automatically...
310344
wg.Wait()
311345

346+
logging.HelperResourceTrace(ctx, "Providers have successfully stopped")
347+
312348
// once we've run the Terraform command, let's remove the reattach
313349
// information from the WorkingDir's environment. The WorkingDir will
314350
// persist until the next call, but the server in the reattach info

helper/resource/testing_new.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest
103103
return
104104
}
105105

106+
logging.HelperResourceDebug(ctx, "Starting TestSteps")
107+
106108
// use this to track last step succesfully applied
107109
// acts as default for import tests
108110
var appliedCfg string

internal/logging/keys.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ const (
1414
// Underlying Go error string when logging an error.
1515
KeyError = "error"
1616

17+
// The full address of the provider, such as
18+
// registry.terraform.io/hashicorp/random
19+
KeyProviderAddress = "tf_provider_addr"
20+
1721
// The type of resource being operated on, such as "random_pet"
1822
KeyResourceType = "tf_resource_type"
1923

internal/plugintest/working_dir.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ func (wd *WorkingDir) Unsetenv(envVar string) {
6565
delete(wd.env, envVar)
6666
}
6767

68-
func (wd *WorkingDir) SetReattachInfo(reattachInfo tfexec.ReattachInfo) {
68+
func (wd *WorkingDir) SetReattachInfo(ctx context.Context, reattachInfo tfexec.ReattachInfo) {
69+
logging.HelperResourceTrace(ctx, "Setting Terraform CLI reattach configuration", map[string]interface{}{"tf_reattach_config": reattachInfo})
6970
wd.reattachInfo = reattachInfo
7071
}
7172

plugin/serve.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,10 @@ func tf6serverServe(opts *ServeOpts) error {
199199
reattachConfigCh := make(chan *plugin.ReattachConfig)
200200

201201
go func() {
202-
val, ok := <-closeCh
203-
204-
if ok {
205-
opts.TestConfig.CloseCh <- val
206-
}
202+
// Always forward close channel receive, since its signaling that
203+
// the channel is closed.
204+
val := <-closeCh
205+
opts.TestConfig.CloseCh <- val
207206
}()
208207

209208
go func() {

0 commit comments

Comments
 (0)