Skip to content

Commit b005008

Browse files
committed
fix: validate agent & resource metadata keys during plan
1 parent 286841d commit b005008

File tree

6 files changed

+43
-24
lines changed

6 files changed

+43
-24
lines changed

integration/integration_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func TestIntegration(t *testing.T) {
8787
},
8888
{
8989
name: "workspace-owner",
90-
minVersion: "v2.12.0",
90+
minVersion: "v2.13.0",
9191
expectedOutput: map[string]string{
9292
"provisioner.arch": runtime.GOARCH,
9393
"provisioner.id": `[a-zA-Z0-9-]+`,
@@ -103,7 +103,7 @@ func TestIntegration(t *testing.T) {
103103
"workspace.transition": `start`,
104104
"workspace_owner.email": `testing@coder\.com`,
105105
"workspace_owner.full_name": `default`,
106-
"workspace_owner.groups": `\[\]`,
106+
"workspace_owner.groups": `\[\"Everyone\"\]`,
107107
"workspace_owner.id": `[a-zA-Z0-9-]+`,
108108
"workspace_owner.name": `testing`,
109109
"workspace_owner.oidc_access_token": `^$`, // TODO: test OIDC integration

provider/agent.go

+17-12
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,6 @@ func agentResource() *schema.Resource {
4343
}
4444
}
4545

46-
rawPlan := resourceData.GetRawPlan()
47-
items := rawPlan.GetAttr("metadata").AsValueSlice()
48-
itemKeys := map[string]struct{}{}
49-
for _, item := range items {
50-
key := valueAsString(item.GetAttr("key"))
51-
_, exists := itemKeys[key]
52-
if exists {
53-
return diag.FromErr(xerrors.Errorf("duplicate agent metadata key %q", key))
54-
}
55-
itemKeys[key] = struct{}{}
56-
}
57-
5846
return updateInitScript(resourceData, i)
5947
},
6048
ReadWithoutTimeout: func(ctx context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
@@ -272,6 +260,23 @@ func agentResource() *schema.Resource {
272260
Optional: true,
273261
},
274262
},
263+
CustomizeDiff: func(ctx context.Context, rd *schema.ResourceDiff, i interface{}) error {
264+
if !rd.HasChange("metadata") {
265+
return nil
266+
}
267+
268+
keys := map[string]struct{}{}
269+
for _, t := range rd.Get("metadata").([]interface{}) {
270+
taint := t.(map[string]interface{})
271+
key := taint["key"].(string)
272+
_, ok := keys[key]
273+
if ok {
274+
return xerrors.Errorf("duplicate agent metadata key %q", key)
275+
}
276+
keys[key] = struct{}{}
277+
}
278+
return nil
279+
},
275280
}
276281
}
277282

provider/agent_test.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ func TestAgent_MetadataDuplicateKeys(t *testing.T) {
254254
}
255255
`,
256256
ExpectError: regexp.MustCompile("duplicate agent metadata key"),
257+
PlanOnly: true,
257258
}},
258259
})
259260
}
@@ -281,7 +282,7 @@ func TestAgent_DisplayApps(t *testing.T) {
281282
web_terminal = false
282283
port_forwarding_helper = false
283284
ssh_helper = false
284-
}
285+
}
285286
}
286287
`,
287288
Check: func(state *terraform.State) error {
@@ -331,7 +332,7 @@ func TestAgent_DisplayApps(t *testing.T) {
331332
display_apps {
332333
vscode_insiders = true
333334
web_terminal = true
334-
}
335+
}
335336
}
336337
`,
337338
Check: func(state *terraform.State) error {
@@ -426,7 +427,7 @@ func TestAgent_DisplayApps(t *testing.T) {
426427
web_terminal = false
427428
port_forwarding_helper = false
428429
ssh_helper = false
429-
}
430+
}
430431
}
431432
`,
432433
ExpectError: regexp.MustCompile(`An argument named "fake_app" is not expected here.`),

provider/metadata.go

+18
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/google/uuid"
88
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
99
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
"golang.org/x/xerrors"
1011
)
1112

1213
func metadataResource() *schema.Resource {
@@ -111,5 +112,22 @@ func metadataResource() *schema.Resource {
111112
},
112113
},
113114
},
115+
CustomizeDiff: func(ctx context.Context, rd *schema.ResourceDiff, i interface{}) error {
116+
if !rd.HasChange("item") {
117+
return nil
118+
}
119+
120+
keys := map[string]struct{}{}
121+
for _, t := range rd.Get("item").([]interface{}) {
122+
taint := t.(map[string]interface{})
123+
key := taint["key"].(string)
124+
_, ok := keys[key]
125+
if ok {
126+
return xerrors.Errorf("duplicate resource metadata key %q", key)
127+
}
128+
keys[key] = struct{}{}
129+
}
130+
return nil
131+
},
114132
}
115133
}

provider/metadata_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ func TestMetadataDuplicateKeys(t *testing.T) {
123123
}
124124
}
125125
`,
126-
ExpectError: regexp.MustCompile("duplicate metadata key"),
126+
PlanOnly: true,
127+
ExpectError: regexp.MustCompile("duplicate resource metadata key"),
127128
}},
128129
})
129130
}

provider/provider.go

-6
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,8 @@ func populateIsNull(resourceData *schema.ResourceData) (result interface{}, err
9797
items := rawPlan.GetAttr("item").AsValueSlice()
9898

9999
var resultItems []interface{}
100-
itemKeys := map[string]struct{}{}
101100
for _, item := range items {
102101
key := valueAsString(item.GetAttr("key"))
103-
_, exists := itemKeys[key]
104-
if exists {
105-
return nil, xerrors.Errorf("duplicate metadata key %q", key)
106-
}
107-
itemKeys[key] = struct{}{}
108102
resultItem := map[string]interface{}{
109103
"key": key,
110104
"value": valueAsString(item.GetAttr("value")),

0 commit comments

Comments
 (0)