Skip to content

Commit 803e2c7

Browse files
fix: change precedence order between coder_workspace_tags and request_tags (#16239)
Co-authored-by: Cian Johnston <cian@coder.com>
1 parent bd6f426 commit 803e2c7

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

coderd/templateversions.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,11 +1597,9 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
15971597
}
15981598

15991599
// Ensure the "owner" tag is properly applied in addition to request tags and coder_workspace_tags.
1600-
// Tag order precedence:
1601-
// 1) User-specified tags in the request
1602-
// 2) Tags parsed from coder_workspace_tags data source in template file
1603-
// 2 may clobber 1.
1604-
tags := provisionersdk.MutateTags(apiKey.UserID, req.ProvisionerTags, parsedTags)
1600+
// User-specified tags in the request will take precedence over tags parsed from `coder_workspace_tags`
1601+
// data sources defined in the template file.
1602+
tags := provisionersdk.MutateTags(apiKey.UserID, parsedTags, req.ProvisionerTags)
16051603

16061604
var templateVersion database.TemplateVersion
16071605
var provisionerJob database.ProvisionerJob

coderd/templateversions_test.go

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,10 +355,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
355355
wantTags: map[string]string{"owner": "", "scope": "organization", "foo": "bar", "a": "1", "b": "2"},
356356
},
357357
{
358-
name: "main.tf with workspace tags and request tags",
358+
name: "main.tf with request tags not clobbering workspace tags",
359359
files: map[string]string{
360360
`main.tf`: `
361-
// This file is the same as the above, except for this comment.
361+
// This file is, once again, the same as the above, except
362+
// for a slightly different comment.
362363
variable "a" {
363364
type = string
364365
default = "1"
@@ -381,9 +382,57 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
381382
}
382383
}`,
383384
},
384-
reqTags: map[string]string{"baz": "zap", "foo": "noclobber"},
385+
reqTags: map[string]string{"baz": "zap"},
385386
wantTags: map[string]string{"owner": "", "scope": "organization", "foo": "bar", "baz": "zap", "a": "1", "b": "2"},
386387
},
388+
{
389+
name: "main.tf with request tags clobbering workspace tags",
390+
files: map[string]string{
391+
`main.tf`: `
392+
// This file is the same as the above, except for this comment.
393+
variable "a" {
394+
type = string
395+
default = "1"
396+
}
397+
data "coder_parameter" "b" {
398+
type = string
399+
default = "2"
400+
}
401+
data "coder_parameter" "unrelated" {
402+
name = "unrelated"
403+
type = "list(string)"
404+
default = jsonencode(["a", "b"])
405+
}
406+
resource "null_resource" "test" {}
407+
data "coder_workspace_tags" "tags" {
408+
tags = {
409+
"foo": "bar",
410+
"a": var.a,
411+
"b": data.coder_parameter.b.value,
412+
}
413+
}`,
414+
},
415+
reqTags: map[string]string{"baz": "zap", "foo": "clobbered"},
416+
wantTags: map[string]string{"owner": "", "scope": "organization", "foo": "clobbered", "baz": "zap", "a": "1", "b": "2"},
417+
},
418+
// FIXME(cian): we should skip evaluating tags for which values have already been provided.
419+
{
420+
name: "main.tf with variable missing default value but value is passed in request",
421+
files: map[string]string{
422+
`main.tf`: `
423+
variable "a" {
424+
type = string
425+
}
426+
data "coder_workspace_tags" "tags" {
427+
tags = {
428+
"a": var.a,
429+
}
430+
}`,
431+
},
432+
reqTags: map[string]string{"a": "b"},
433+
// wantTags: map[string]string{"owner": "", "scope": "organization", "a": "b"},
434+
expectError: `provisioner tag "a" evaluated to an empty value`,
435+
},
387436
{
388437
name: "main.tf with disallowed workspace tag value",
389438
files: map[string]string{

enterprise/coderd/workspaces_test.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,7 +1217,8 @@ func TestWorkspaceTagsTerraform(t *testing.T) {
12171217
createTemplateVersionRequestTags map[string]string
12181218
// the coder_workspace_tags bit of main.tf.
12191219
// you can add more stuff here if you need
1220-
tfWorkspaceTags string
1220+
tfWorkspaceTags string
1221+
skipCreateWorkspace bool
12211222
}{
12221223
{
12231224
name: "no tags",
@@ -1304,15 +1305,18 @@ func TestWorkspaceTagsTerraform(t *testing.T) {
13041305
}`,
13051306
},
13061307
{
1307-
name: "does not override static tag",
1308-
provisionerTags: map[string]string{"foo": "bar"},
1308+
name: "overrides static tag from request",
1309+
provisionerTags: map[string]string{"foo": "baz"},
13091310
createTemplateVersionRequestTags: map[string]string{"foo": "baz"},
13101311
tfWorkspaceTags: `
13111312
data "coder_workspace_tags" "tags" {
13121313
tags = {
13131314
"foo" = "bar"
13141315
}
13151316
}`,
1317+
// When we go to create the workspace, there won't be any provisioner
1318+
// matching tag foo=bar.
1319+
skipCreateWorkspace: true,
13161320
},
13171321
} {
13181322
tc := tc
@@ -1352,13 +1356,15 @@ func TestWorkspaceTagsTerraform(t *testing.T) {
13521356
coderdtest.AwaitTemplateVersionJobCompleted(t, templateAdmin, tv.ID)
13531357
tpl := coderdtest.CreateTemplate(t, templateAdmin, owner.OrganizationID, tv.ID)
13541358

1355-
// Creating a workspace as a non-privileged user must succeed
1356-
ws, err := member.CreateUserWorkspace(ctx, memberUser.Username, codersdk.CreateWorkspaceRequest{
1357-
TemplateID: tpl.ID,
1358-
Name: coderdtest.RandomUsername(t),
1359-
})
1360-
require.NoError(t, err, "failed to create workspace")
1361-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, member, ws.LatestBuild.ID)
1359+
if !tc.skipCreateWorkspace {
1360+
// Creating a workspace as a non-privileged user must succeed
1361+
ws, err := member.CreateUserWorkspace(ctx, memberUser.Username, codersdk.CreateWorkspaceRequest{
1362+
TemplateID: tpl.ID,
1363+
Name: coderdtest.RandomUsername(t),
1364+
})
1365+
require.NoError(t, err, "failed to create workspace")
1366+
coderdtest.AwaitWorkspaceBuildJobCompleted(t, member, ws.LatestBuild.ID)
1367+
}
13621368
})
13631369
}
13641370
}

0 commit comments

Comments
 (0)