@@ -16,7 +16,9 @@ import (
16
16
17
17
// This is the exact version of Terraform used internally
18
18
// when Terraform is missing on the system.
19
- const terraformVersion = "1.1.9"
19
+ var terraformVersion = version .Must (version .NewVersion ("1.1.9" ))
20
+ var minTerraformVersion = version .Must (version .NewVersion ("1.1.0" ))
21
+ var maxTerraformVersion = version .Must (version .NewVersion ("1.2.0" ))
20
22
21
23
var (
22
24
// The minimum version of Terraform supported by the provisioner.
31
33
}()
32
34
)
33
35
36
+ var terraformMinorVersionMismatch = xerrors .New ("Terraform binary minor version mismatch." )
37
+
34
38
type ServeOptions struct {
35
39
* provisionersdk.ServeOptions
36
40
@@ -41,15 +45,51 @@ type ServeOptions struct {
41
45
Logger slog.Logger
42
46
}
43
47
48
+ func absoluteBinaryPath (ctx context.Context ) (string , error ) {
49
+ binaryPath , err := safeexec .LookPath ("terraform" )
50
+ if err != nil {
51
+ return "" , xerrors .Errorf ("Terraform binary not found: %w" , err )
52
+ }
53
+
54
+ // If the "coder" binary is in the same directory as
55
+ // the "terraform" binary, "terraform" is returned.
56
+ //
57
+ // We must resolve the absolute path for other processes
58
+ // to execute this properly!
59
+ absoluteBinary , err := filepath .Abs (binaryPath )
60
+ if err != nil {
61
+ return "" , xerrors .Errorf ("Terraform binary absolute path not found: %w" , err )
62
+ }
63
+
64
+ // Checking the installed version of Terraform.
65
+ version , err := versionFromBinaryPath (ctx , absoluteBinary )
66
+ if err != nil {
67
+ return "" , xerrors .Errorf ("Terraform binary get version failed: %w" , err )
68
+ }
69
+
70
+ if version .LessThan (minTerraformVersion ) || version .GreaterThanOrEqual (maxTerraformVersion ) {
71
+ return "" , terraformMinorVersionMismatch
72
+ }
73
+
74
+ return absoluteBinary , nil
75
+ }
76
+
44
77
// Serve starts a dRPC server on the provided transport speaking Terraform provisioner.
45
78
func Serve (ctx context.Context , options * ServeOptions ) error {
46
79
if options .BinaryPath == "" {
47
- binaryPath , err := safeexec . LookPath ( "terraform" )
80
+ absoluteBinary , err := absoluteBinaryPath ( ctx )
48
81
if err != nil {
82
+ // This is an early exit to prevent extra execution in case the context is canceled.
83
+ // It generally happens in unit tests since this method is asynchronous and
84
+ // the unit test kills the app before this is complete.
85
+ if xerrors .Is (err , context .Canceled ) {
86
+ return xerrors .Errorf ("absolute binary context canceled: %w" , err )
87
+ }
88
+
49
89
installer := & releases.ExactVersion {
50
90
InstallDir : options .CachePath ,
51
91
Product : product .Terraform ,
52
- Version : version . Must ( version . NewVersion ( terraformVersion )) ,
92
+ Version : terraformVersion ,
53
93
}
54
94
55
95
execPath , err := installer .Install (ctx )
@@ -58,15 +98,6 @@ func Serve(ctx context.Context, options *ServeOptions) error {
58
98
}
59
99
options .BinaryPath = execPath
60
100
} else {
61
- // If the "coder" binary is in the same directory as
62
- // the "terraform" binary, "terraform" is returned.
63
- //
64
- // We must resolve the absolute path for other processes
65
- // to execute this properly!
66
- absoluteBinary , err := filepath .Abs (binaryPath )
67
- if err != nil {
68
- return xerrors .Errorf ("absolute: %w" , err )
69
- }
70
101
options .BinaryPath = absoluteBinary
71
102
}
72
103
}
0 commit comments