Skip to content

Commit 6468763

Browse files
authored
feat: enable Terraform template-wide variables by default (#8334)
1 parent 435c67a commit 6468763

File tree

11 files changed

+19
-156
lines changed

11 files changed

+19
-156
lines changed

docs/templates/parameters.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,14 @@ data "coder_parameter" "cpu" {
248248

249249
As a template improvement, the template author can consider making some of the new `coder_parameter` resources `mutable`.
250250

251-
## Managed Terraform variables
251+
## Terraform template-wide variables
252+
253+
> ⚠️ Flag `feature_use_managed_variables` is available until v0.25.0 (Jul 2023) release. After this release, template-wide Terraform variables will be enabled by default.
252254
253255
As parameters are intended to be used only for workspace customization purposes, Terraform variables can be freely managed by the template author to build templates. Workspace users are not able to modify
254256
template variables.
255257

256-
The template author can enable managed Terraform variables mode by specifying the following flag:
258+
The template author can enable Terraform template-wide variables mode by specifying the following flag:
257259

258260
```hcl
259261
provider "coder" {

examples/templates/aws-ecs-container/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ terraform {
1212
}
1313

1414
provider "coder" {
15-
feature_use_managed_variables = true
1615
}
1716

1817
variable "ecs-cluster" {

examples/templates/do-linux/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ terraform {
1212
}
1313

1414
provider "coder" {
15-
feature_use_managed_variables = true
1615
}
1716

1817
variable "step1_do_project_id" {

examples/templates/envbox/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ variable "use_kubeconfig" {
3838
}
3939

4040
provider "coder" {
41-
feature_use_managed_variables = "true"
4241
}
4342

4443
variable "namespace" {

examples/templates/fly-docker-image/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ provider "fly" {
1616
}
1717

1818
provider "coder" {
19-
feature_use_managed_variables = true
2019
}
2120

2221
resource "fly_app" "workspace" {

examples/templates/gcp-linux/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ terraform {
1212
}
1313

1414
provider "coder" {
15-
feature_use_managed_variables = true
1615
}
1716

1817
variable "project_id" {

examples/templates/gcp-vm-container/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ terraform {
1212
}
1313

1414
provider "coder" {
15-
feature_use_managed_variables = true
1615
}
1716

1817
variable "project_id" {

examples/templates/gcp-windows/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ terraform {
1212
}
1313

1414
provider "coder" {
15-
feature_use_managed_variables = true
1615
}
1716

1817
variable "project_id" {

examples/templates/kubernetes/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ terraform {
1212
}
1313

1414
provider "coder" {
15-
feature_use_managed_variables = true
1615
}
1716

1817
variable "use_kubeconfig" {

provisioner/terraform/parse.go

Lines changed: 7 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,10 @@ package terraform
33
import (
44
"encoding/json"
55
"fmt"
6-
"os"
7-
"path"
86
"path/filepath"
97
"sort"
108
"strings"
119

12-
"github.com/hashicorp/hcl/v2"
13-
"github.com/hashicorp/hcl/v2/gohcl"
14-
"github.com/hashicorp/hcl/v2/hclparse"
1510
"github.com/hashicorp/terraform-config-inspect/tfconfig"
1611
"github.com/mitchellh/go-wordwrap"
1712
"golang.org/x/xerrors"
@@ -20,25 +15,6 @@ import (
2015
"github.com/coder/coder/provisionersdk/proto"
2116
)
2217

23-
const featureUseManagedVariables = "feature_use_managed_variables"
24-
25-
var terraformWithFeaturesSchema = &hcl.BodySchema{
26-
Blocks: []hcl.BlockHeaderSchema{
27-
{
28-
Type: "provider",
29-
LabelNames: []string{"type"},
30-
},
31-
},
32-
}
33-
34-
var providerFeaturesConfigSchema = &hcl.BodySchema{
35-
Attributes: []hcl.AttributeSchema{
36-
{
37-
Name: featureUseManagedVariables,
38-
},
39-
},
40-
}
41-
4218
// Parse extracts Terraform variables from source-code.
4319
func (s *server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_ParseStream) error {
4420
_, span := s.startTrace(stream.Context(), tracing.FuncName())
@@ -50,11 +26,6 @@ func (s *server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisione
5026
return xerrors.Errorf("load module: %s", formatDiagnostics(request.Directory, diags))
5127
}
5228

53-
flags, flagsDiags := loadEnabledFeatures(request.Directory)
54-
if flagsDiags.HasErrors() {
55-
return xerrors.Errorf("load coder provider features: %s", formatDiagnostics(request.Directory, diags))
56-
}
57-
5829
// Sort variables by (filename, line) to make the ordering consistent
5930
variables := make([]*tfconfig.Variable, 0, len(module.Variables))
6031
for _, v := range module.Variables {
@@ -66,17 +37,12 @@ func (s *server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisione
6637

6738
var templateVariables []*proto.TemplateVariable
6839

69-
useManagedVariables := flags != nil && flags[featureUseManagedVariables]
70-
if useManagedVariables {
71-
for _, v := range variables {
72-
mv, err := convertTerraformVariableToManagedVariable(v)
73-
if err != nil {
74-
return xerrors.Errorf("can't convert the Terraform variable to a managed one: %w", err)
75-
}
76-
templateVariables = append(templateVariables, mv)
40+
for _, v := range variables {
41+
mv, err := convertTerraformVariable(v)
42+
if err != nil {
43+
return xerrors.Errorf("can't convert the Terraform variable to a managed one: %w", err)
7744
}
78-
} else if len(variables) > 0 {
79-
return xerrors.Errorf("legacy parameters are not supported anymore, use %q flag to enable managed Terraform variables", featureUseManagedVariables)
45+
templateVariables = append(templateVariables, mv)
8046
}
8147
return stream.Send(&proto.Parse_Response{
8248
Type: &proto.Parse_Response_Complete{
@@ -87,81 +53,8 @@ func (s *server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisione
8753
})
8854
}
8955

90-
func loadEnabledFeatures(moduleDir string) (map[string]bool, hcl.Diagnostics) {
91-
flags := map[string]bool{}
92-
var diags hcl.Diagnostics
93-
94-
entries, err := os.ReadDir(moduleDir)
95-
if err != nil {
96-
diags = append(diags, &hcl.Diagnostic{
97-
Severity: hcl.DiagError,
98-
Summary: "Failed to read module directory",
99-
Detail: fmt.Sprintf("Module directory %s does not exist or cannot be read.", moduleDir),
100-
})
101-
return flags, diags
102-
}
103-
104-
var found bool
105-
for _, entry := range entries {
106-
if !strings.HasSuffix(entry.Name(), ".tf") && !strings.HasSuffix(entry.Name(), ".tf.json") {
107-
continue
108-
}
109-
110-
flags, found, diags = parseFeatures(path.Join(moduleDir, entry.Name()))
111-
if found {
112-
break
113-
}
114-
}
115-
return flags, diags
116-
}
117-
118-
func parseFeatures(hclFilepath string) (map[string]bool, bool, hcl.Diagnostics) {
119-
flags := map[string]bool{}
120-
var diags hcl.Diagnostics
121-
122-
_, err := os.Stat(hclFilepath)
123-
if os.IsNotExist(err) {
124-
return flags, false, diags
125-
} else if err != nil {
126-
diags = append(diags, &hcl.Diagnostic{
127-
Severity: hcl.DiagError,
128-
Summary: fmt.Sprintf("Failed to open %q file", hclFilepath),
129-
})
130-
return flags, false, diags
131-
}
132-
133-
parser := hclparse.NewParser()
134-
var parsedHCL *hcl.File
135-
if strings.HasSuffix(hclFilepath, ".tf.json") {
136-
parsedHCL, diags = parser.ParseJSONFile(hclFilepath)
137-
} else {
138-
parsedHCL, diags = parser.ParseHCLFile(hclFilepath)
139-
}
140-
if diags.HasErrors() {
141-
return flags, false, diags
142-
}
143-
144-
var found bool
145-
content, _ := parsedHCL.Body.Content(terraformWithFeaturesSchema)
146-
for _, block := range content.Blocks {
147-
if block.Type == "provider" && block.Labels[0] == "coder" {
148-
content, _, partialDiags := block.Body.PartialContent(providerFeaturesConfigSchema)
149-
diags = append(diags, partialDiags...)
150-
if attr, defined := content.Attributes[featureUseManagedVariables]; defined {
151-
found = true
152-
153-
var useManagedVariables bool
154-
partialDiags := gohcl.DecodeExpression(attr.Expr, nil, &useManagedVariables)
155-
diags = append(diags, partialDiags...)
156-
flags[featureUseManagedVariables] = useManagedVariables
157-
}
158-
}
159-
}
160-
return flags, found, diags
161-
}
162-
163-
// Converts a Terraform variable to a managed variable.
164-
func convertTerraformVariableToManagedVariable(variable *tfconfig.Variable) (*proto.TemplateVariable, error) {
56+
// Converts a Terraform variable to a template-wide variable, processed by Coder.
57+
func convertTerraformVariable(variable *tfconfig.Variable) (*proto.TemplateVariable, error) {
16558
var defaultData string
16659
if variable.Default != nil {
16760
var valid bool

provisioner/terraform/parse_test.go

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@ func TestParse(t *testing.T) {
3131
Files: map[string]string{
3232
"main.tf": `variable "A" {
3333
description = "Testing!"
34-
}
35-
36-
provider "coder" { feature_use_managed_variables = "true" }`,
34+
}`,
3735
},
3836
Response: &proto.Parse_Response{
3937
Type: &proto.Parse_Response_Complete{
@@ -54,9 +52,7 @@ func TestParse(t *testing.T) {
5452
Files: map[string]string{
5553
"main.tf": `variable "A" {
5654
default = "wow"
57-
}
58-
59-
provider "coder" { feature_use_managed_variables = "true" }`,
55+
}`,
6056
},
6157
Response: &proto.Parse_Response{
6258
Type: &proto.Parse_Response_Complete{
@@ -78,9 +74,7 @@ func TestParse(t *testing.T) {
7874
validation {
7975
condition = var.A == "value"
8076
}
81-
}
82-
83-
provider "coder" { feature_use_managed_variables = "true" }`,
77+
}`,
8478
},
8579
Response: &proto.Parse_Response{
8680
Type: &proto.Parse_Response_Complete{
@@ -106,9 +100,7 @@ func TestParse(t *testing.T) {
106100
Name: "multiple-variables",
107101
Files: map[string]string{
108102
"main1.tf": `variable "foo" { }
109-
variable "bar" { }
110-
111-
provider "coder" { feature_use_managed_variables = "true" }`,
103+
variable "bar" { }`,
112104
"main2.tf": `variable "baz" { }
113105
variable "quux" { }`,
114106
},
@@ -138,17 +130,13 @@ func TestParse(t *testing.T) {
138130
},
139131
},
140132
{
141-
Name: "enable-managed-variables-with-default-bool",
133+
Name: "template-variables-with-default-bool",
142134
Files: map[string]string{
143135
"main.tf": `variable "A" {
144136
description = "Testing!"
145137
type = bool
146138
default = true
147139
sensitive = true
148-
}
149-
150-
provider "coder" {
151-
feature_use_managed_variables = true
152140
}`,
153141
},
154142
Response: &proto.Parse_Response{
@@ -169,17 +157,13 @@ func TestParse(t *testing.T) {
169157
},
170158
},
171159
{
172-
Name: "enable-managed-variables-with-default-string",
160+
Name: "template-variables-with-default-string",
173161
Files: map[string]string{
174162
"main.tf": `variable "A" {
175163
description = "Testing!"
176164
type = string
177165
default = "abc"
178166
sensitive = true
179-
}
180-
181-
provider "coder" {
182-
feature_use_managed_variables = true
183167
}`,
184168
},
185169
Response: &proto.Parse_Response{
@@ -200,17 +184,13 @@ func TestParse(t *testing.T) {
200184
},
201185
},
202186
{
203-
Name: "enable-managed-variables-with-default-empty-string",
187+
Name: "template-variables-with-default-empty-string",
204188
Files: map[string]string{
205189
"main.tf": `variable "A" {
206190
description = "Testing!"
207191
type = string
208192
default = ""
209193
sensitive = true
210-
}
211-
212-
provider "coder" {
213-
feature_use_managed_variables = true
214194
}`,
215195
},
216196
Response: &proto.Parse_Response{
@@ -231,16 +211,12 @@ func TestParse(t *testing.T) {
231211
},
232212
},
233213
{
234-
Name: "enable-managed-variables-without-default",
214+
Name: "template-variables-without-default",
235215
Files: map[string]string{
236216
"main2.tf": `variable "A" {
237217
description = "Testing!"
238218
type = string
239219
sensitive = true
240-
}
241-
242-
provider "coder" {
243-
feature_use_managed_variables = true
244220
}`,
245221
},
246222
Response: &proto.Parse_Response{

0 commit comments

Comments
 (0)