Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e56cac7

Browse files
committed
fix(provisioner/terraform/tfparse): skip evaluation of defaults if no workspace_tags found
1 parent 94f5d52 commit e56cac7

File tree

4 files changed

+267
-59
lines changed

4 files changed

+267
-59
lines changed

coderd/templateversions_test.go

+86-27
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
293293
type = string
294294
default = "2"
295295
}
296+
data "coder_parameter" "unrelated" {
297+
name = "unrelated"
298+
type = "list(string)"
299+
default = jsonencode(["a", "b"])
300+
}
296301
resource "null_resource" "test" {}`,
297302
},
298303
wantTags: map[string]string{"owner": "", "scope": "organization"},
@@ -301,18 +306,23 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
301306
name: "main.tf with empty workspace tags",
302307
files: map[string]string{
303308
`main.tf`: `
304-
variable "a" {
305-
type = string
306-
default = "1"
307-
}
308-
data "coder_parameter" "b" {
309-
type = string
310-
default = "2"
311-
}
312-
resource "null_resource" "test" {}
313-
data "coder_workspace_tags" "tags" {
314-
tags = {}
315-
}`,
309+
variable "a" {
310+
type = string
311+
default = "1"
312+
}
313+
data "coder_parameter" "b" {
314+
type = string
315+
default = "2"
316+
}
317+
data "coder_parameter" "unrelated" {
318+
name = "unrelated"
319+
type = "list(string)"
320+
default = jsonencode(["a", "b"])
321+
}
322+
resource "null_resource" "test" {}
323+
data "coder_workspace_tags" "tags" {
324+
tags = {}
325+
}`,
316326
},
317327
wantTags: map[string]string{"owner": "", "scope": "organization"},
318328
},
@@ -328,6 +338,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
328338
type = string
329339
default = "2"
330340
}
341+
data "coder_parameter" "unrelated" {
342+
name = "unrelated"
343+
type = "list(string)"
344+
default = jsonencode(["a", "b"])
345+
}
331346
resource "null_resource" "test" {}
332347
data "coder_workspace_tags" "tags" {
333348
tags = {
@@ -343,22 +358,28 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
343358
name: "main.tf with workspace tags and request tags",
344359
files: map[string]string{
345360
`main.tf`: `
346-
variable "a" {
347-
type = string
348-
default = "1"
349-
}
350-
data "coder_parameter" "b" {
351-
type = string
352-
default = "2"
353-
}
354-
resource "null_resource" "test" {}
355-
data "coder_workspace_tags" "tags" {
356-
tags = {
357-
"foo": "bar",
358-
"a": var.a,
359-
"b": data.coder_parameter.b.value,
361+
// This file is the same as the above, except for this comment.
362+
variable "a" {
363+
type = string
364+
default = "1"
365+
}
366+
data "coder_parameter" "b" {
367+
type = string
368+
default = "2"
360369
}
361-
}`,
370+
data "coder_parameter" "unrelated" {
371+
name = "unrelated"
372+
type = "list(string)"
373+
default = jsonencode(["a", "b"])
374+
}
375+
resource "null_resource" "test" {}
376+
data "coder_workspace_tags" "tags" {
377+
tags = {
378+
"foo": "bar",
379+
"a": var.a,
380+
"b": data.coder_parameter.b.value,
381+
}
382+
}`,
362383
},
363384
reqTags: map[string]string{"baz": "zap", "foo": "noclobber"},
364385
wantTags: map[string]string{"owner": "", "scope": "organization", "foo": "bar", "baz": "zap", "a": "1", "b": "2"},
@@ -375,6 +396,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
375396
type = string
376397
default = "2"
377398
}
399+
data "coder_parameter" "unrelated" {
400+
name = "unrelated"
401+
type = "list(string)"
402+
default = jsonencode(["a", "b"])
403+
}
378404
resource "null_resource" "test" {
379405
name = "foo"
380406
}
@@ -401,6 +427,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
401427
type = string
402428
default = "2"
403429
}
430+
data "coder_parameter" "unrelated" {
431+
name = "unrelated"
432+
type = "list(string)"
433+
default = jsonencode(["a", "b"])
434+
}
404435
resource "null_resource" "test" {
405436
name = "foo"
406437
}
@@ -423,6 +454,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
423454
name: "main.tf with workspace tags that attempts to set user scope",
424455
files: map[string]string{
425456
`main.tf`: `
457+
data "coder_parameter" "unrelated" {
458+
name = "unrelated"
459+
type = "list(string)"
460+
default = jsonencode(["a", "b"])
461+
}
426462
resource "null_resource" "test" {}
427463
data "coder_workspace_tags" "tags" {
428464
tags = {
@@ -437,6 +473,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
437473
name: "main.tf with workspace tags that attempt to clobber org ID",
438474
files: map[string]string{
439475
`main.tf`: `
476+
data "coder_parameter" "unrelated" {
477+
name = "unrelated"
478+
type = "list(string)"
479+
default = jsonencode(["a", "b"])
480+
}
440481
resource "null_resource" "test" {}
441482
data "coder_workspace_tags" "tags" {
442483
tags = {
@@ -451,6 +492,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
451492
name: "main.tf with workspace tags that set scope=user",
452493
files: map[string]string{
453494
`main.tf`: `
495+
data "coder_parameter" "unrelated" {
496+
name = "unrelated"
497+
type = "list(string)"
498+
default = jsonencode(["a", "b"])
499+
}
454500
resource "null_resource" "test" {}
455501
data "coder_workspace_tags" "tags" {
456502
tags = {
@@ -460,6 +506,19 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
460506
},
461507
wantTags: map[string]string{"owner": templateAdminUser.ID.String(), "scope": "user"},
462508
},
509+
// Ref: https://github.com/coder/coder/issues/16021
510+
{
511+
name: "main.tf with no workspace_tags and a function call in a parameter default",
512+
files: map[string]string{
513+
`main.tf`: `
514+
data "coder_parameter" "unrelated" {
515+
name = "unrelated"
516+
type = "list(string)"
517+
default = jsonencode(["a", "b"])
518+
}`,
519+
},
520+
wantTags: map[string]string{"owner": "", "scope": "organization"},
521+
},
463522
} {
464523
tt := tt
465524
t.Run(tt.name, func(t *testing.T) {

enterprise/coderd/workspaces_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,11 @@ func TestWorkspaceTagsTerraform(t *testing.T) {
14121412
provider "coder" {}
14131413
data "coder_workspace" "me" {}
14141414
data "coder_workspace_owner" "me" {}
1415+
data "coder_parameter" "unrelated" {
1416+
name = "unrelated"
1417+
type = "list(string)"
1418+
default = jsonencode(["a", "b"])
1419+
}
14151420
%s
14161421
`
14171422

provisioner/terraform/tfparse/tfparse.go

+35-8
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func New(workdir string, opts ...Option) (*Parser, tfconfig.Diagnostics) {
8080
}
8181

8282
// WorkspaceTags looks for all coder_workspace_tags datasource in the module
83-
// and returns the raw values for the tags. Use
83+
// and returns the raw values for the tags.
8484
func (p *Parser) WorkspaceTags(ctx context.Context) (map[string]string, error) {
8585
tags := map[string]string{}
8686
var skipped []string
@@ -166,13 +166,17 @@ func (p *Parser) WorkspaceTagDefaults(ctx context.Context) (map[string]string, e
166166
return nil, xerrors.Errorf("extract workspace tags: %w", err)
167167
}
168168

169+
if len(tags) == 0 {
170+
return map[string]string{}, nil
171+
}
172+
169173
// To evaluate the expressions, we need to load the default values for
170174
// variables and parameters.
171-
varsDefaults, err := p.VariableDefaults(ctx)
175+
varsDefaults, err := p.VariableDefaults(ctx, tags)
172176
if err != nil {
173177
return nil, xerrors.Errorf("load variable defaults: %w", err)
174178
}
175-
paramsDefaults, err := p.CoderParameterDefaults(ctx, varsDefaults)
179+
paramsDefaults, err := p.CoderParameterDefaults(ctx, varsDefaults, tags)
176180
if err != nil {
177181
return nil, xerrors.Errorf("load parameter defaults: %w", err)
178182
}
@@ -247,28 +251,39 @@ func WriteArchive(bs []byte, mimetype string, path string) error {
247251
return nil
248252
}
249253

250-
// VariableDefaults returns the default values for all variables passed to it.
251-
func (p *Parser) VariableDefaults(ctx context.Context) (map[string]string, error) {
254+
// VariableDefaults returns the default values for all variables referenced in the values of tags.
255+
func (p *Parser) VariableDefaults(ctx context.Context, tags map[string]string) (map[string]string, error) {
256+
var skipped []string
252257
// iterate through vars to get the default values for all
253-
// variables.
258+
// required variables.
254259
m := make(map[string]string)
255260
for _, v := range p.module.Variables {
256261
if v == nil {
257262
continue
258263
}
264+
var found bool
265+
for _, tv := range tags {
266+
if strings.Contains(tv, v.Name) {
267+
found = true
268+
}
269+
}
270+
if !found {
271+
skipped = append(skipped, "var."+v.Name)
272+
continue
273+
}
259274
sv, err := interfaceToString(v.Default)
260275
if err != nil {
261276
return nil, xerrors.Errorf("can't convert variable default value to string: %v", err)
262277
}
263278
m[v.Name] = strings.Trim(sv, `"`)
264279
}
265-
p.logger.Debug(ctx, "found default values for variables", slog.F("defaults", m))
280+
p.logger.Debug(ctx, "found default values for variables", slog.F("defaults", m), slog.F("skipped", skipped))
266281
return m, nil
267282
}
268283

269284
// CoderParameterDefaults returns the default values of all coder_parameter data sources
270285
// in the parsed module.
271-
func (p *Parser) CoderParameterDefaults(ctx context.Context, varsDefaults map[string]string) (map[string]string, error) {
286+
func (p *Parser) CoderParameterDefaults(ctx context.Context, varsDefaults map[string]string, tags map[string]string) (map[string]string, error) {
272287
defaultsM := make(map[string]string)
273288
var (
274289
skipped []string
@@ -290,6 +305,18 @@ func (p *Parser) CoderParameterDefaults(ctx context.Context, varsDefaults map[st
290305
continue
291306
}
292307

308+
var found bool
309+
needle := strings.Join([]string{"data", dataResource.Type, dataResource.Name}, ".")
310+
for _, tv := range tags {
311+
if strings.Contains(tv, needle) {
312+
found = true
313+
}
314+
}
315+
if !found {
316+
skipped = append(skipped, needle)
317+
continue
318+
}
319+
293320
// We know in which HCL file is the data resource defined.
294321
// NOTE: hclparse.Parser will cache multiple successive calls to parse the same file.
295322
file, diags = p.underlying.ParseHCLFile(dataResource.Pos.Filename)

0 commit comments

Comments
 (0)