Skip to content

fix(provisioner/terraform/tfparse): evaluate coder_parameter defaults with variables #15800

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix(provisioner/terraform/tfparse): evaluate coder_parameter defaults…
… with variables
  • Loading branch information
johnstcn committed Dec 9, 2024
commit 6ab95beb58d7d3afd1d12e42aa11729641997906
20 changes: 17 additions & 3 deletions provisioner/terraform/tfparse/tfparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -316,14 +316,28 @@ 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
value, err := previewFileContent(expr.Range())
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?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has there been an ask? If not, we can probably defer it until such a time. It's best to be careful how much we expand the scope of these expressions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not aware of any ask for this just yet. I'd much prefer to defer it as it opens up several cans of worms.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is sort of a FIXME :)

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, `"`)
}
}
}
Expand Down
34 changes: 34 additions & 0 deletions provisioner/terraform/tfparse/tfparse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember the current bevahior, so let me ask -
how this solution will perform if we have a variable without a default value? AFAIR Coder should require to input the value for variable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, if there is no default value we will fail this 'preflight' check with an error. This only happens if you're using the coder_workspace_tags data source.

}
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{
Expand Down