Skip to content

Commit 51db0c1

Browse files
authored
Merge pull request #47646 from carlosrodgut/b-aws_grafana_workspace-network_access_control-vpce_ids-regression
r/aws_grafana_workspace: Fix `network_access_control` regression when only one of `vpce_ids` or `prefix_list_ids` is set
2 parents 242ed87 + 0b43ee3 commit 51db0c1

4 files changed

Lines changed: 188 additions & 10 deletions

File tree

.changelog/47646.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
resource/aws_grafana_workspace: Fix `network_access_control` regression causing `ValidationException` when only one of `vpce_ids` or `prefix_list_ids` is set
3+
```

internal/service/grafana/exports_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ var (
1717
FindWorkspaceByID = findWorkspaceByID
1818
FindWorkspaceServiceAccountByTwoPartKey = findWorkspaceServiceAccountByTwoPartKey
1919
FindWorkspaceServiceAccountTokenByThreePartKey = findWorkspaceServiceAccountTokenByThreePartKey
20+
21+
ExpandNetworkAccessControl = expandNetworkAccessControl
22+
FlattenNetworkAccessControl = flattenNetworkAccessControl
2023
)

internal/service/grafana/workspace.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -586,21 +586,19 @@ func expandNetworkAccessControl(tfList []any) *awstypes.NetworkAccessConfigurati
586586
}
587587

588588
tfMap := tfList[0].(map[string]any)
589-
apiObject := awstypes.NetworkAccessConfiguration{}
590589

591-
if v, ok := tfMap["prefix_list_ids"].(*schema.Set); ok && v.Len() > 0 {
592-
apiObject.PrefixListIds = flex.ExpandStringValueSet(v)
593-
}
594-
595-
if v, ok := tfMap["vpce_ids"].(*schema.Set); ok && v.Len() > 0 {
596-
apiObject.VpceIds = flex.ExpandStringValueSet(v)
597-
}
590+
// See: https://github.com/aws/aws-sdk-go-v2/issues/2123
591+
prefixListIDs := flex.ExpandStringValueSet(tfMap["prefix_list_ids"].(*schema.Set))
592+
vpceIDs := flex.ExpandStringValueSet(tfMap["vpce_ids"].(*schema.Set))
598593

599-
if len(apiObject.PrefixListIds) == 0 && len(apiObject.VpceIds) == 0 {
594+
if len(prefixListIDs) == 0 && len(vpceIDs) == 0 {
600595
return nil
601596
}
602597

603-
return &apiObject
598+
return &awstypes.NetworkAccessConfiguration{
599+
PrefixListIds: prefixListIDs,
600+
VpceIds: vpceIDs,
601+
}
604602
}
605603

606604
func flattenNetworkAccessControl(apiObject *awstypes.NetworkAccessConfiguration) []any {

internal/service/grafana/workspace_test.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import (
77
"context"
88
"errors"
99
"fmt"
10+
"slices"
1011
"testing"
1112

1213
"github.com/YakDriver/regexache"
1314
"github.com/aws/aws-sdk-go-v2/aws"
1415
awstypes "github.com/aws/aws-sdk-go-v2/service/grafana/types"
16+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1517
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
1618
"github.com/hashicorp/terraform-plugin-testing/plancheck"
1719
"github.com/hashicorp/terraform-plugin-testing/terraform"
@@ -21,6 +23,178 @@ import (
2123
"github.com/hashicorp/terraform-provider-aws/names"
2224
)
2325

26+
func TestExpandNetworkAccessControl(t *testing.T) {
27+
t.Parallel()
28+
29+
testCases := []struct {
30+
TestName string
31+
TFList []any
32+
WantNil bool
33+
WantPrefixListIDs []string
34+
WantVpceIDs []string
35+
}{
36+
{
37+
TestName: "empty list",
38+
TFList: []any{},
39+
WantNil: true,
40+
},
41+
{
42+
TestName: "nil element in list",
43+
TFList: []any{nil},
44+
WantNil: true,
45+
},
46+
{
47+
TestName: "both sets empty",
48+
TFList: buildNetworkAccessTFList(newStringSet(), newStringSet()),
49+
WantNil: true,
50+
},
51+
{
52+
TestName: "both populated",
53+
TFList: buildNetworkAccessTFList(newStringSet("pl-111"), newStringSet("vpce-aaa")),
54+
WantPrefixListIDs: []string{"pl-111"},
55+
WantVpceIDs: []string{"vpce-aaa"},
56+
},
57+
{
58+
TestName: "only prefix_list_ids",
59+
TFList: buildNetworkAccessTFList(newStringSet("pl-222"), newStringSet()),
60+
WantPrefixListIDs: []string{"pl-222"},
61+
WantVpceIDs: []string{},
62+
},
63+
{
64+
TestName: "only vpce_ids",
65+
TFList: buildNetworkAccessTFList(newStringSet(), newStringSet("vpce-aaa", "vpce-bbb")),
66+
WantPrefixListIDs: []string{},
67+
WantVpceIDs: []string{"vpce-aaa", "vpce-bbb"},
68+
},
69+
{
70+
TestName: "multiple vpce_ids",
71+
TFList: buildNetworkAccessTFList(newStringSet("pl-333"), newStringSet("vpce-x", "vpce-y", "vpce-z")),
72+
WantPrefixListIDs: []string{"pl-333"},
73+
WantVpceIDs: []string{"vpce-x", "vpce-y", "vpce-z"},
74+
},
75+
}
76+
77+
for _, testCase := range testCases {
78+
t.Run(testCase.TestName, func(t *testing.T) {
79+
t.Parallel()
80+
81+
out := tfgrafana.ExpandNetworkAccessControl(testCase.TFList)
82+
83+
if testCase.WantNil {
84+
if out != nil {
85+
t.Errorf("expected nil, got %+v", out)
86+
}
87+
return
88+
}
89+
90+
if out == nil {
91+
t.Fatal("expected non-nil NetworkAccessConfiguration")
92+
}
93+
if out.PrefixListIds == nil {
94+
t.Error("PrefixListIds must not be nil (SDK v2 omitempty would drop a nil slice)")
95+
}
96+
if out.VpceIds == nil {
97+
t.Error("VpceIds must not be nil (SDK v2 omitempty would drop a nil slice)")
98+
}
99+
gotPrefix := slices.Clone(out.PrefixListIds)
100+
slices.Sort(gotPrefix)
101+
wantPrefix := slices.Clone(testCase.WantPrefixListIDs)
102+
slices.Sort(wantPrefix)
103+
if !slices.Equal(gotPrefix, wantPrefix) {
104+
t.Errorf("PrefixListIds: got %v, want %v", out.PrefixListIds, testCase.WantPrefixListIDs)
105+
}
106+
gotVpce := slices.Clone(out.VpceIds)
107+
slices.Sort(gotVpce)
108+
wantVpce := slices.Clone(testCase.WantVpceIDs)
109+
slices.Sort(wantVpce)
110+
if !slices.Equal(gotVpce, wantVpce) {
111+
t.Errorf("VpceIds: got %v, want %v", out.VpceIds, testCase.WantVpceIDs)
112+
}
113+
})
114+
}
115+
}
116+
117+
func TestFlattenNetworkAccessControl(t *testing.T) {
118+
t.Parallel()
119+
120+
testCases := []struct {
121+
TestName string
122+
APIObject *awstypes.NetworkAccessConfiguration
123+
WantEmpty bool
124+
WantPrefixIDs []string
125+
WantVpceIDs []string
126+
}{
127+
{
128+
TestName: "nil input",
129+
APIObject: nil,
130+
WantEmpty: true,
131+
},
132+
{
133+
TestName: "both fields empty",
134+
APIObject: &awstypes.NetworkAccessConfiguration{
135+
PrefixListIds: []string{},
136+
VpceIds: []string{},
137+
},
138+
WantEmpty: true,
139+
},
140+
{
141+
TestName: "both fields populated",
142+
APIObject: &awstypes.NetworkAccessConfiguration{
143+
PrefixListIds: []string{"pl-abc"},
144+
VpceIds: []string{"vpce-def"},
145+
},
146+
WantPrefixIDs: []string{"pl-abc"},
147+
WantVpceIDs: []string{"vpce-def"},
148+
},
149+
}
150+
151+
for _, testCase := range testCases {
152+
t.Run(testCase.TestName, func(t *testing.T) {
153+
t.Parallel()
154+
155+
out := tfgrafana.FlattenNetworkAccessControl(testCase.APIObject)
156+
157+
if testCase.WantEmpty {
158+
if len(out) != 0 {
159+
t.Errorf("expected empty slice, got %v", out)
160+
}
161+
return
162+
}
163+
164+
if len(out) != 1 {
165+
t.Fatalf("expected 1 element, got %d", len(out))
166+
}
167+
m, ok := out[0].(map[string]any)
168+
if !ok {
169+
t.Fatalf("element is not map[string]any: %T", out[0])
170+
}
171+
if pl, ok := m["prefix_list_ids"].([]string); !ok || !slices.Equal(pl, testCase.WantPrefixIDs) {
172+
t.Errorf("prefix_list_ids: got %v, want %v", m["prefix_list_ids"], testCase.WantPrefixIDs)
173+
}
174+
if vp, ok := m["vpce_ids"].([]string); !ok || !slices.Equal(vp, testCase.WantVpceIDs) {
175+
t.Errorf("vpce_ids: got %v, want %v", m["vpce_ids"], testCase.WantVpceIDs)
176+
}
177+
})
178+
}
179+
}
180+
181+
func newStringSet(values ...string) *schema.Set {
182+
raw := make([]any, len(values))
183+
for i, v := range values {
184+
raw[i] = v
185+
}
186+
return schema.NewSet(schema.HashString, raw)
187+
}
188+
189+
func buildNetworkAccessTFList(prefixIDs, vpceIDs *schema.Set) []any {
190+
return []any{
191+
map[string]any{
192+
"prefix_list_ids": prefixIDs,
193+
"vpce_ids": vpceIDs,
194+
},
195+
}
196+
}
197+
24198
func testAccWorkspace_saml(t *testing.T) {
25199
ctx := acctest.Context(t)
26200
var v awstypes.WorkspaceDescription

0 commit comments

Comments
 (0)