- Notifications
You must be signed in to change notification settings - Fork1k
fix(coderd/wsbuilder): correctly evaluate dynamic workspace tag values#15897
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
0ebaeb2
f8a0356
2279385
f7cb744
c6fe518
40d3dfe
e17bceb
cf7d67e
5b3c33a
82d8c93
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -12,9 +12,9 @@ import ( | ||
"github.com/hashicorp/hcl/v2" | ||
"github.com/hashicorp/hcl/v2/hclsyntax" | ||
"github.com/coder/coder/v2/coderd/rbac/policy" | ||
"github.com/coder/coder/v2/provisioner/terraform/tfparse" | ||
"github.com/coder/coder/v2/provisionersdk" | ||
"github.com/google/uuid" | ||
@@ -64,6 +64,7 @@ type Builder struct { | ||
templateVersion *database.TemplateVersion | ||
templateVersionJob *database.ProvisionerJob | ||
templateVersionParameters *[]database.TemplateVersionParameter | ||
templateVersionVariables *[]database.TemplateVersionVariable | ||
templateVersionWorkspaceTags *[]database.TemplateVersionWorkspaceTag | ||
lastBuild *database.WorkspaceBuild | ||
lastBuildErr *error | ||
@@ -617,6 +618,22 @@ func (b *Builder) getTemplateVersionParameters() ([]database.TemplateVersionPara | ||
return tvp, nil | ||
} | ||
func (b *Builder) getTemplateVersionVariables() ([]database.TemplateVersionVariable, error) { | ||
if b.templateVersionVariables != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Should we use a mutex/atomic here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I don't think the builder is meant to be safe for concurrent use. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Yea, we do this pattern everywhere. It's all single threaded | ||
return *b.templateVersionVariables, nil | ||
} | ||
tvID, err := b.getTemplateVersionID() | ||
if err != nil { | ||
return nil, xerrors.Errorf("get template version ID to get variables: %w", err) | ||
} | ||
tvs, err := b.store.GetTemplateVersionVariables(b.ctx, tvID) | ||
if err != nil && !xerrors.Is(err, sql.ErrNoRows) { | ||
return nil, xerrors.Errorf("get template version %s variables: %w", tvID, err) | ||
} | ||
b.templateVersionVariables = &tvs | ||
return tvs, nil | ||
} | ||
// verifyNoLegacyParameters verifies that initiator can't start the workspace build | ||
// if it uses legacy parameters (database.ParameterSchemas). | ||
func (b *Builder) verifyNoLegacyParameters() error { | ||
@@ -678,17 +695,40 @@ func (b *Builder) getProvisionerTags() (map[string]string, error) { | ||
tags[name] = value | ||
} | ||
// Step 2: Mutate workspace tags: | ||
// - Get workspace tags from the template version job | ||
// - Get template version variables from the template version as they can be | ||
// referenced in workspace tags | ||
// - Get parameters from the workspace build as they can also be referenced | ||
// in workspace tags | ||
// - Evaluate workspace tags given the above inputs | ||
workspaceTags, err := b.getTemplateVersionWorkspaceTags() | ||
if err != nil { | ||
return nil, BuildError{http.StatusInternalServerError, "failed to fetch template version workspace tags", err} | ||
} | ||
tvs, err := b.getTemplateVersionVariables() | ||
if err != nil { | ||
return nil, BuildError{http.StatusInternalServerError, "failed to fetch template version variables", err} | ||
} | ||
varsM := make(map[string]string) | ||
for _, tv := range tvs { | ||
// FIXME: do this in Terraform? This is a bit of a hack. | ||
if tv.Value == "" { | ||
varsM[tv.Name] = tv.DefaultValue | ||
} else { | ||
varsM[tv.Name] = tv.Value | ||
} | ||
} | ||
parameterNames, parameterValues, err := b.getParameters() | ||
if err != nil { | ||
return nil, err // already wrapped BuildError | ||
} | ||
paramsM := make(map[string]string) | ||
for i, name := range parameterNames { | ||
paramsM[name] = parameterValues[i] | ||
} | ||
evalCtx :=tfparse.BuildEvalContext(varsM, paramsM) | ||
for _, workspaceTag := range workspaceTags { | ||
expr, diags := hclsyntax.ParseExpression([]byte(workspaceTag.Value), "expression.hcl", hcl.InitialPos) | ||
if diags.HasErrors() { | ||
@@ -701,7 +741,7 @@ func (b *Builder) getProvisionerTags() (map[string]string, error) { | ||
} | ||
// Do not use "val.AsString()" as it can panic | ||
str, err :=tfparse.CtyValueString(val) | ||
if err != nil { | ||
return nil, BuildError{http.StatusBadRequest, "failed to marshal cty.Value as string", err} | ||
} | ||
@@ -710,44 +750,6 @@ func (b *Builder) getProvisionerTags() (map[string]string, error) { | ||
return tags, nil | ||
} | ||
func (b *Builder) getTemplateVersionWorkspaceTags() ([]database.TemplateVersionWorkspaceTag, error) { | ||
if b.templateVersionWorkspaceTags != nil { | ||
return *b.templateVersionWorkspaceTags, nil | ||
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.