Skip to content

Commit fb9fca8

Browse files
authored
fix: Ensure terraform tests have a cache path and logger (#3161)
* fix: Ensure terraform tests have a cache path and logger * fix: Protect against concurrent `terraform init`
1 parent ad20b23 commit fb9fca8

File tree

4 files changed

+33
-28
lines changed

4 files changed

+33
-28
lines changed

provisioner/terraform/executor.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
)
2424

2525
type executor struct {
26+
initMu sync.Locker
2627
binaryPath string
2728
cachePath string
2829
workdir string
@@ -142,6 +143,19 @@ func (e executor) init(ctx context.Context, logr logger) error {
142143
"-no-color",
143144
"-input=false",
144145
}
146+
147+
// When cache path is set, we must protect against multiple calls
148+
// to `terraform init`.
149+
//
150+
// From the Terraform documentation:
151+
// Note: The plugin cache directory is not guaranteed to be
152+
// concurrency safe. The provider installer's behavior in
153+
// environments with multiple terraform init calls is undefined.
154+
if e.cachePath != "" {
155+
e.initMu.Lock()
156+
defer e.initMu.Unlock()
157+
}
158+
145159
return e.execWriteOutput(ctx, args, e.basicEnv(), outWriter, errWriter)
146160
}
147161

provisioner/terraform/parse_test.go

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,20 @@
33
package terraform_test
44

55
import (
6-
"context"
76
"encoding/json"
87
"os"
98
"path/filepath"
109
"testing"
1110

12-
"github.com/stretchr/testify/assert"
1311
"github.com/stretchr/testify/require"
1412

15-
"github.com/coder/coder/provisioner/terraform"
16-
"github.com/coder/coder/provisionersdk"
1713
"github.com/coder/coder/provisionersdk/proto"
1814
)
1915

2016
func TestParse(t *testing.T) {
2117
t.Parallel()
2218

23-
// Create an in-memory provisioner to communicate with.
24-
client, server := provisionersdk.TransportPipe()
25-
ctx, cancelFunc := context.WithCancel(context.Background())
26-
t.Cleanup(func() {
27-
_ = client.Close()
28-
_ = server.Close()
29-
cancelFunc()
30-
})
31-
go func() {
32-
err := terraform.Serve(ctx, &terraform.ServeOptions{
33-
ServeOptions: &provisionersdk.ServeOptions{
34-
Listener: server,
35-
},
36-
})
37-
assert.NoError(t, err)
38-
}()
39-
api := proto.NewDRPCProvisionerClient(provisionersdk.Conn(client))
19+
ctx, api := setupProvisioner(t)
4020

4121
testCases := []struct {
4222
Name string
@@ -175,7 +155,8 @@ func TestParse(t *testing.T) {
175155
DefaultDestination: &proto.ParameterDestination{
176156
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
177157
},
178-
}},
158+
},
159+
},
179160
},
180161
},
181162
},

provisioner/terraform/provision_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,25 @@ import (
2323
)
2424

2525
func setupProvisioner(t *testing.T) (context.Context, proto.DRPCProvisionerClient) {
26+
cachePath := t.TempDir()
2627
client, server := provisionersdk.TransportPipe()
2728
ctx, cancelFunc := context.WithCancel(context.Background())
29+
serverErr := make(chan error, 1)
2830
t.Cleanup(func() {
2931
_ = client.Close()
3032
_ = server.Close()
3133
cancelFunc()
34+
err := <-serverErr
35+
assert.NoError(t, err)
3236
})
3337
go func() {
34-
err := terraform.Serve(ctx, &terraform.ServeOptions{
38+
serverErr <- terraform.Serve(ctx, &terraform.ServeOptions{
3539
ServeOptions: &provisionersdk.ServeOptions{
3640
Listener: server,
3741
},
38-
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
42+
CachePath: cachePath,
43+
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
3944
})
40-
assert.NoError(t, err)
4145
}()
4246
api := proto.NewDRPCProvisionerClient(provisionersdk.Conn(client))
4347
return ctx, api

provisioner/terraform/serve.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package terraform
33
import (
44
"context"
55
"path/filepath"
6+
"sync"
67

78
"github.com/cli/safeexec"
89
"github.com/hashicorp/go-version"
@@ -109,15 +110,20 @@ func Serve(ctx context.Context, options *ServeOptions) error {
109110
}
110111

111112
type server struct {
113+
// initMu protects against executors running `terraform init`
114+
// concurrently when cache path is set.
115+
initMu sync.Mutex
116+
112117
binaryPath string
113118
cachePath string
114119
logger slog.Logger
115120
}
116121

117-
func (t server) executor(workdir string) executor {
122+
func (s *server) executor(workdir string) executor {
118123
return executor{
119-
binaryPath: t.binaryPath,
120-
cachePath: t.cachePath,
124+
initMu: &s.initMu,
125+
binaryPath: s.binaryPath,
126+
cachePath: s.cachePath,
121127
workdir: workdir,
122128
}
123129
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy