Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fdb3846

Browse files
committedSep 5, 2024·
fix: validate agent & resource metadata keys during plan
1 parent 286841d commit fdb3846

File tree

5 files changed

+59
-22
lines changed

5 files changed

+59
-22
lines changed
 

‎provider/agent.go

+26-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,32 @@ func agentResource() *schema.Resource {
272260
Optional: true,
273261
},
274262
},
263+
CustomizeDiff: func(ctx context.Context, rd *schema.ResourceDiff, i any) error {
264+
if !rd.HasChange("metadata") {
265+
return nil
266+
}
267+
268+
keys := map[string]bool{}
269+
metadata, ok := rd.Get("metadata").([]any)
270+
if !ok {
271+
return xerrors.Errorf("unexpected type %T for metadata, expected []any", rd.Get("metadata"))
272+
}
273+
for _, t := range metadata {
274+
obj, ok := t.(map[string]any)
275+
if !ok {
276+
return xerrors.Errorf("unexpected type %T for metadata, expected map[string]any", t)
277+
}
278+
key, ok := obj["key"].(string)
279+
if !ok {
280+
return xerrors.Errorf("unexpected type %T for metadata key, expected string", obj["key"])
281+
}
282+
if keys[key] {
283+
return xerrors.Errorf("duplicate agent metadata key %q", key)
284+
}
285+
keys[key] = true
286+
}
287+
return nil
288+
},
275289
}
276290
}
277291

‎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

+27
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,31 @@ 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]bool{}
121+
metadata, ok := rd.Get("item").([]any)
122+
if !ok {
123+
return xerrors.Errorf("unexpected type %T for items, expected []any", rd.Get("metadata"))
124+
}
125+
for _, t := range metadata {
126+
obj, ok := t.(map[string]any)
127+
if !ok {
128+
return xerrors.Errorf("unexpected type %T for item, expected map[string]any", t)
129+
}
130+
key, ok := obj["key"].(string)
131+
if !ok {
132+
return xerrors.Errorf("unexpected type %T for items 'key' attribute, expected string", obj["key"])
133+
}
134+
if keys[key] {
135+
return xerrors.Errorf("duplicate resource metadata key %q", key)
136+
}
137+
keys[key] = true
138+
}
139+
return nil
140+
},
114141
}
115142
}

‎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)
Please sign in to comment.