Skip to content

Commit cab999c

Browse files
authored
Modify tags related functions and some test files to fix flaky assertion errors (#51)
Issue #, if available: MemoryDB Controller has some flaky tests that randomly show assertion error. Root causes: 1. Snapshot test files didn't clean resources which were created from previous failed tests, so eventually test account reached node limit. 2. Delta compare considers order matters, so it considers two tag arrays are different even though they have same elements with different orders. Function of updating tags didn't include this corner case, and it caused infinite update. 3. When creating resources, some resources take a while to finish creation. Function of getting tags got error because it couldn't find resource, and this error covered previous ResourceNotFound error. Hence, reconciler didn't call requeue, because it didn't recognize the new error. 4. Cluster update validation test file has a step to update and validate Snapshot Window (daily time range to auto snapshot). If this step is executing within the time range of new Snapshot Window, update would succeed (ResourceSynced returns true) because two resources match, but cluster starts snapshotting after it's Snapshot Window is updated to the current time. Hence, for next step to update other fields of cluster, new fields couldn't be updated on time, because the status of cluster is snapshotting and cluster cannot be updated. Description of changes: 1. Fix updateTags function and it covers situation of equal tag arrays. (It still wastes time to call sdkUpdate over and over. It is better to modify delta comparison of tags in code-generator. New PR is created (aws-controllers-k8s/community#1658). 2. Change updateTags functions from parameter group and subnet group to match the updateTags functions in other resources. 3. Add a status check for getTags. It is only called when status of resource (cluster, snapshot, acl, user) is active. 4. Increase wait time for the next update step after Snapshot Window update. The new wait time is enough to cover snapshotting process. 5. Use same method to create cluster for snapshot for snapshot_validate_tags.yaml test file. 6. Correct user names and delete unused resources in test files. 7. Modify some test IDs, step IDs, and descriptions which are not appropriate that makes debugging really hard. 8. Fix import order of hook files. 9. Modify equalStrings function. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent d2483d2 commit cab999c

25 files changed

+298
-183
lines changed

apis/v1alpha1/ack-generate-metadata.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
ack_generate_info:
2-
build_date: "2023-01-10T21:58:28Z"
3-
build_hash: 1b20baf45a0b73a11b296050322a384c705fa897
4-
go_version: go1.17.5
5-
version: v0.22.0
2+
build_date: "2023-02-03T00:39:12Z"
3+
build_hash: c6651c200ba136e5c7f50ad8be751fae060a38e6
4+
go_version: go1.19
5+
version: v0.22.0-1-gc6651c2
66
api_directory_checksum: ee32acc4d4a0ba7e2823dd20fdbe2c4ef1d9e0f4
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.44.93

apis/v1alpha1/subnet_group.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apis/v1alpha1/types.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

helm/crds/memorydb.services.k8s.aws_subnetgroups.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ spec:
3434
type: object
3535
spec:
3636
description: "SubnetGroupSpec defines the desired state of SubnetGroup.
37-
\n Represents the output of one of the following operations: \n * CreateSubnetGroup
38-
\n * UpdateSubnetGroup \n A subnet group is a collection of subnets
37+
\n Represents the output of one of the following operations: \n - CreateSubnetGroup
38+
\n - UpdateSubnetGroup \n A subnet group is a collection of subnets
3939
(typically private) that you can designate for your clusters running
4040
in an Amazon Virtual Private Cloud (VPC) environment."
4141
properties:

pkg/resource/acl/hooks.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@ import (
2020
"github.com/aws-controllers-k8s/runtime/pkg/requeue"
2121
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
2222
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
23+
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
2324

2425
svcapitypes "github.com/aws-controllers-k8s/memorydb-controller/apis/v1alpha1"
25-
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
26+
)
27+
28+
var (
29+
resourceStatusActive string = "active"
2630
)
2731

2832
// validateACLNeedsUpdate this function's purpose is to requeue if the resource is currently unavailable
@@ -32,7 +36,7 @@ func (rm *resourceManager) validateACLNeedsUpdate(
3236

3337
// requeue if necessary
3438
latestStatus := latest.ko.Status.Status
35-
if latestStatus == nil || *latestStatus != "active" {
39+
if latestStatus == nil || *latestStatus != resourceStatusActive {
3640
return requeue.NeededAfter(
3741
errors.New("ACL cannot be modified as its status is not 'active'."),
3842
requeue.DefaultRequeueAfterDuration)
@@ -41,6 +45,14 @@ func (rm *resourceManager) validateACLNeedsUpdate(
4145
return nil
4246
}
4347

48+
// aclActive returns true when the status of the given ACL is set to `active`
49+
func (rm *resourceManager) aclActive(
50+
latest *resource,
51+
) bool {
52+
latestStatus := latest.ko.Status.Status
53+
return latestStatus != nil && *latestStatus == resourceStatusActive
54+
}
55+
4456
// getTags gets tags from given ParameterGroup.
4557
func (rm *resourceManager) getTags(
4658
ctx context.Context,
@@ -114,17 +126,23 @@ func computeTagsDelta(
114126
latest []*svcapitypes.Tag,
115127
) (addedOrUpdated []*svcapitypes.Tag, removed []*string) {
116128
var visitedIndexes []string
129+
var hasSameKey bool
117130

118131
for _, latestElement := range latest {
132+
hasSameKey = false
119133
visitedIndexes = append(visitedIndexes, *latestElement.Key)
120134
for _, desiredElement := range desired {
121135
if equalStrings(latestElement.Key, desiredElement.Key) {
136+
hasSameKey = true
122137
if !equalStrings(latestElement.Value, desiredElement.Value) {
123138
addedOrUpdated = append(addedOrUpdated, desiredElement)
124139
}
125-
continue
140+
break
126141
}
127142
}
143+
if hasSameKey {
144+
continue
145+
}
128146
removed = append(removed, latestElement.Key)
129147
}
130148
for _, desiredElement := range desired {
@@ -163,7 +181,9 @@ func resourceTagsFromSDKTags(
163181

164182
func equalStrings(a, b *string) bool {
165183
if a == nil {
166-
return b == nil || *b == ""
184+
return b == nil
185+
} else if b == nil {
186+
return false
167187
}
168-
return (*a == "" && b == nil) || *a == *b
188+
return *a == *b
169189
}

pkg/resource/acl/sdk.go

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/resource/cluster/hooks.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ import (
2424
ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
2525
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
2626
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
27+
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
2728

2829
svcapitypes "github.com/aws-controllers-k8s/memorydb-controller/apis/v1alpha1"
29-
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
3030
)
3131

3232
var (
33-
condMsgCurrentlyDeleting = "cluster currently being deleted"
34-
condMsgNoDeleteWhileUpdating = "cluster is being updated. cannot delete"
33+
condMsgCurrentlyDeleting = "cluster currently being deleted"
34+
condMsgNoDeleteWhileUpdating = "cluster is being updated. cannot delete"
35+
resourceStatusActive string = "active"
3536
)
3637

3738
var (
@@ -264,6 +265,14 @@ func (rm *resourceManager) newMemoryDBClusterUploadPayload(
264265
return res
265266
}
266267

268+
// clusterActive returns true when the status of the given Cluster is set to `active`
269+
func (rm *resourceManager) clusterActive(
270+
latest *resource,
271+
) bool {
272+
latestStatus := latest.ko.Status.Status
273+
return latestStatus != nil && *latestStatus == resourceStatusActive
274+
}
275+
267276
// getTags gets tags from given ParameterGroup.
268277
func (rm *resourceManager) getTags(
269278
ctx context.Context,
@@ -337,17 +346,23 @@ func computeTagsDelta(
337346
latest []*svcapitypes.Tag,
338347
) (addedOrUpdated []*svcapitypes.Tag, removed []*string) {
339348
var visitedIndexes []string
349+
var hasSameKey bool
340350

341351
for _, latestElement := range latest {
352+
hasSameKey = false
342353
visitedIndexes = append(visitedIndexes, *latestElement.Key)
343354
for _, desiredElement := range desired {
344355
if equalStrings(latestElement.Key, desiredElement.Key) {
356+
hasSameKey = true
345357
if !equalStrings(latestElement.Value, desiredElement.Value) {
346358
addedOrUpdated = append(addedOrUpdated, desiredElement)
347359
}
348-
continue
360+
break
349361
}
350362
}
363+
if hasSameKey {
364+
continue
365+
}
351366
removed = append(removed, latestElement.Key)
352367
}
353368
for _, desiredElement := range desired {
@@ -386,7 +401,9 @@ func resourceTagsFromSDKTags(
386401

387402
func equalStrings(a, b *string) bool {
388403
if a == nil {
389-
return b == nil || *b == ""
404+
return b == nil
405+
} else if b == nil {
406+
return false
390407
}
391-
return (*a == "" && b == nil) || *a == *b
408+
return *a == *b
392409
}

pkg/resource/cluster/sdk.go

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/resource/parameter_group/hooks.go

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ import (
1919
ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1"
2020
ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors"
2121
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
22+
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
23+
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
2224

2325
svcapitypes "github.com/aws-controllers-k8s/memorydb-controller/apis/v1alpha1"
24-
25-
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
2626
)
2727

2828
func (rm *resourceManager) setParameters(
@@ -173,13 +173,7 @@ func (rm *resourceManager) getTags(
173173
if err != nil {
174174
return nil, err
175175
}
176-
tags := make([]*svcapitypes.Tag, 0, len(resp.TagList))
177-
for _, tag := range resp.TagList {
178-
tags = append(tags, &svcapitypes.Tag{
179-
Key: tag.Key,
180-
Value: tag.Value,
181-
})
182-
}
176+
tags := resourceTagsFromSDKTags(resp.TagList)
183177
return tags, nil
184178
}
185179

@@ -235,34 +229,33 @@ func (rm *resourceManager) updateTags(
235229
func computeTagsDelta(
236230
desired []*svcapitypes.Tag,
237231
latest []*svcapitypes.Tag,
238-
) (added []*svcapitypes.Tag, removed []*string) {
239-
toDelete := []*string{}
240-
toAdd := []*svcapitypes.Tag{}
232+
) (addedOrUpdated []*svcapitypes.Tag, removed []*string) {
233+
var visitedIndexes []string
234+
var hasSameKey bool
241235

242-
desiredTags := map[string]string{}
243-
key := ""
244-
value := ""
245-
for _, tag := range desired {
246-
if tag.Key != nil {
247-
key = *tag.Key
248-
value = ""
249-
if tag.Value != nil {
250-
value = *tag.Value
236+
for _, latestElement := range latest {
237+
hasSameKey = false
238+
visitedIndexes = append(visitedIndexes, *latestElement.Key)
239+
for _, desiredElement := range desired {
240+
if equalStrings(latestElement.Key, desiredElement.Key) {
241+
hasSameKey = true
242+
if !equalStrings(latestElement.Value, desiredElement.Value) {
243+
addedOrUpdated = append(addedOrUpdated, desiredElement)
244+
}
245+
break
251246
}
252-
desiredTags[key] = value
253247
}
248+
if hasSameKey {
249+
continue
250+
}
251+
removed = append(removed, latestElement.Key)
254252
}
255-
256-
for _, tag := range desired {
257-
toAdd = append(toAdd, tag)
258-
}
259-
for _, tag := range latest {
260-
_, ok := desiredTags[*tag.Key]
261-
if !ok {
262-
toDelete = append(toDelete, tag.Key)
253+
for _, desiredElement := range desired {
254+
if !ackutil.InStrings(*desiredElement.Key, visitedIndexes) {
255+
addedOrUpdated = append(addedOrUpdated, desiredElement)
263256
}
264257
}
265-
return toAdd, toDelete
258+
return addedOrUpdated, removed
266259
}
267260

268261
func sdkTagsFromResourceTags(
@@ -277,3 +270,25 @@ func sdkTagsFromResourceTags(
277270
}
278271
return tags
279272
}
273+
274+
func resourceTagsFromSDKTags(
275+
sdkTags []*svcsdk.Tag,
276+
) []*svcapitypes.Tag {
277+
tags := make([]*svcapitypes.Tag, len(sdkTags))
278+
for i := range sdkTags {
279+
tags[i] = &svcapitypes.Tag{
280+
Key: sdkTags[i].Key,
281+
Value: sdkTags[i].Value,
282+
}
283+
}
284+
return tags
285+
}
286+
287+
func equalStrings(a, b *string) bool {
288+
if a == nil {
289+
return b == nil
290+
} else if b == nil {
291+
return false
292+
}
293+
return *a == *b
294+
}

0 commit comments

Comments
 (0)