From 6ab95beb58d7d3afd1d12e42aa11729641997906 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Mon, 9 Dec 2024 16:13:45 +0000 Subject: [PATCH 1/3] fix(provisioner/terraform/tfparse): evaluate coder_parameter defaults with variables --- provisioner/terraform/tfparse/tfparse.go | 20 +++++++++-- provisioner/terraform/tfparse/tfparse_test.go | 34 +++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/provisioner/terraform/tfparse/tfparse.go b/provisioner/terraform/tfparse/tfparse.go index 3807c518cbb73..0eb6a0094e505 100644 --- a/provisioner/terraform/tfparse/tfparse.go +++ b/provisioner/terraform/tfparse/tfparse.go @@ -172,7 +172,7 @@ func (p *Parser) WorkspaceTagDefaults(ctx context.Context) (map[string]string, e if err != nil { return nil, xerrors.Errorf("load variable defaults: %w", err) } - paramsDefaults, err := p.CoderParameterDefaults(ctx) + paramsDefaults, err := p.CoderParameterDefaults(ctx, varsDefaults) if err != nil { return nil, xerrors.Errorf("load parameter defaults: %w", err) } @@ -268,7 +268,7 @@ func (p *Parser) VariableDefaults(ctx context.Context) (map[string]string, error // CoderParameterDefaults returns the default values of all coder_parameter data sources // in the parsed module. -func (p *Parser) CoderParameterDefaults(ctx context.Context) (map[string]string, error) { +func (p *Parser) CoderParameterDefaults(ctx context.Context, varsDefaults map[string]string) (map[string]string, error) { defaultsM := make(map[string]string) var ( skipped []string @@ -316,6 +316,7 @@ func (p *Parser) CoderParameterDefaults(ctx context.Context) (map[string]string, } if _, ok := resContent.Attributes["default"]; !ok { + p.logger.Warn(ctx, "coder_parameter data source does not have a default value", slog.F("name", dataResource.Name)) defaultsM[dataResource.Name] = "" } else { expr := resContent.Attributes["default"].Expr @@ -323,7 +324,20 @@ func (p *Parser) CoderParameterDefaults(ctx context.Context) (map[string]string, if err != nil { return nil, xerrors.Errorf("can't preview the resource file: %v", err) } - defaultsM[dataResource.Name] = strings.Trim(value, `"`) + // Issue #15795: the "default" value could also be an expression we need + // to evaluate. + // TODO: should we support coder_parameter default values that reference other coder_parameter data sources? + evalCtx := buildEvalContext(varsDefaults, nil) + val, diags := expr.Value(evalCtx) + if diags.HasErrors() { + return nil, xerrors.Errorf("failed to evaluate coder_parameter %q default value %q: %s", dataResource.Name, value, diags.Error()) + } + // Do not use "val.AsString()" as it can panic + strVal, err := ctyValueString(val) + if err != nil { + return nil, xerrors.Errorf("failed to marshal coder_parameter %q default value %q as string: %s", dataResource.Name, value, err) + } + defaultsM[dataResource.Name] = strings.Trim(strVal, `"`) } } } diff --git a/provisioner/terraform/tfparse/tfparse_test.go b/provisioner/terraform/tfparse/tfparse_test.go index 8436d99e67d03..5643b34bb24d4 100644 --- a/provisioner/terraform/tfparse/tfparse_test.go +++ b/provisioner/terraform/tfparse/tfparse_test.go @@ -114,6 +114,40 @@ func Test_WorkspaceTagDefaultsFromFile(t *testing.T) { expectTags: map[string]string{"platform": "kubernetes", "cluster": "developers", "region": "us", "az": "a"}, expectError: "", }, + { + name: "main.tf with parameter that has default value from dynamic value", + files: map[string]string{ + "main.tf": ` + provider "foo" {} + resource "foo_bar" "baz" {} + variable "region" { + type = string + default = "us" + } + variable "az" { + type = string + default = "${""}${"a"}" + } + data "base" "ours" { + all = true + } + data "coder_parameter" "az" { + name = "az" + type = "string" + default = var.az + } + data "coder_workspace_tags" "tags" { + tags = { + "platform" = "kubernetes", + "cluster" = "${"devel"}${"opers"}" + "region" = var.region + "az" = data.coder_parameter.az.value + } + }`, + }, + expectTags: map[string]string{"platform": "kubernetes", "cluster": "developers", "region": "us", "az": "a"}, + expectError: "", + }, { name: "main.tf with multiple valid workspace tags", files: map[string]string{ From afff08fed59267c1352a0970f3396787949d99d2 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Mon, 9 Dec 2024 16:15:22 +0000 Subject: [PATCH 2/3] add test case with parameter default from another parameter --- provisioner/terraform/tfparse/tfparse_test.go | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/provisioner/terraform/tfparse/tfparse_test.go b/provisioner/terraform/tfparse/tfparse_test.go index 5643b34bb24d4..8c080ad5fa2bd 100644 --- a/provisioner/terraform/tfparse/tfparse_test.go +++ b/provisioner/terraform/tfparse/tfparse_test.go @@ -148,6 +148,39 @@ func Test_WorkspaceTagDefaultsFromFile(t *testing.T) { expectTags: map[string]string{"platform": "kubernetes", "cluster": "developers", "region": "us", "az": "a"}, expectError: "", }, + { + name: "main.tf with parameter that has default value from another parameter", + files: map[string]string{ + "main.tf": ` + provider "foo" {} + resource "foo_bar" "baz" {} + variable "region" { + type = string + default = "us" + } + data "base" "ours" { + all = true + } + data "coder_parameter" "az" { + type = string + default = "${""}${"a"}" + } + data "coder_parameter" "az2" { + name = "az" + type = "string" + default = data.coder_parameter.az.value + } + data "coder_workspace_tags" "tags" { + tags = { + "platform" = "kubernetes", + "cluster" = "${"devel"}${"opers"}" + "region" = var.region + "az" = data.coder_parameter.az2.value + } + }`, + }, + expectError: "Unknown variable; There is no variable named \"data\".", + }, { name: "main.tf with multiple valid workspace tags", files: map[string]string{ From a9b1c17a3a434aa658703743e92934e87b3fb66f Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Tue, 10 Dec 2024 10:33:29 +0000 Subject: [PATCH 3/3] fixup! add test case with parameter default from another parameter --- provisioner/terraform/tfparse/tfparse_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provisioner/terraform/tfparse/tfparse_test.go b/provisioner/terraform/tfparse/tfparse_test.go index 8c080ad5fa2bd..9d9bcc4526584 100644 --- a/provisioner/terraform/tfparse/tfparse_test.go +++ b/provisioner/terraform/tfparse/tfparse_test.go @@ -132,7 +132,7 @@ func Test_WorkspaceTagDefaultsFromFile(t *testing.T) { all = true } data "coder_parameter" "az" { - name = "az" + name = "az" type = "string" default = var.az }