Skip to content

Commit a6318da

Browse files
authored
Tag and Untag API for cluster. (#43)
Issue #, if available: ACK MemoryDB controller doesn't provide tags update after creation of cluster. Description of changes: Add functions so that customers can update tags of cluster after creation. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent d86b927 commit a6318da

File tree

6 files changed

+256
-6
lines changed

6 files changed

+256
-6
lines changed

apis/v1alpha1/ack-generate-metadata.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
ack_generate_info:
2-
build_date: "2022-12-14T00:10:49Z"
2+
build_date: "2022-12-22T20:12:01Z"
33
build_hash: 16f0e201b37a06b535370cc69e11adb934a22d33
44
go_version: go1.19
55
version: v0.20.1-18-g16f0e20

pkg/resource/cluster/hooks.go

Lines changed: 131 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ import (
1717
"context"
1818
"errors"
1919
"fmt"
20+
"strconv"
2021

2122
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
2223
ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors"
23-
"strconv"
24+
ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
25+
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
26+
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
2427

2528
svcapitypes "github.com/aws-controllers-k8s/memorydb-controller/apis/v1alpha1"
2629
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
27-
28-
ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
2930
)
3031

3132
var (
@@ -262,3 +263,130 @@ func (rm *resourceManager) newMemoryDBClusterUploadPayload(
262263

263264
return res
264265
}
266+
267+
// getTags gets tags from given ParameterGroup.
268+
func (rm *resourceManager) getTags(
269+
ctx context.Context,
270+
resourceARN string,
271+
) ([]*svcapitypes.Tag, error) {
272+
resp, err := rm.sdkapi.ListTagsWithContext(
273+
ctx,
274+
&svcsdk.ListTagsInput{
275+
ResourceArn: &resourceARN,
276+
},
277+
)
278+
rm.metrics.RecordAPICall("GET", "ListTags", err)
279+
if err != nil {
280+
return nil, err
281+
}
282+
tags := resourceTagsFromSDKTags(resp.TagList)
283+
return tags, nil
284+
}
285+
286+
// updateTags updates tags of given ParameterGroup to desired tags.
287+
func (rm *resourceManager) updateTags(
288+
ctx context.Context,
289+
desired *resource,
290+
latest *resource,
291+
) (err error) {
292+
rlog := ackrtlog.FromContext(ctx)
293+
exit := rlog.Trace("rm.updateTags")
294+
defer func(err error) { exit(err) }(err)
295+
296+
arn := (*string)(latest.ko.Status.ACKResourceMetadata.ARN)
297+
298+
toAdd, toDelete := computeTagsDelta(
299+
desired.ko.Spec.Tags, latest.ko.Spec.Tags,
300+
)
301+
302+
if len(toDelete) > 0 {
303+
rlog.Debug("removing tags from cluster", "tags", toDelete)
304+
_, err = rm.sdkapi.UntagResourceWithContext(
305+
ctx,
306+
&svcsdk.UntagResourceInput{
307+
ResourceArn: arn,
308+
TagKeys: toDelete,
309+
},
310+
)
311+
rm.metrics.RecordAPICall("UPDATE", "UntagResource", err)
312+
if err != nil {
313+
return err
314+
}
315+
}
316+
317+
if len(toAdd) > 0 {
318+
rlog.Debug("adding tags to cluster", "tags", toAdd)
319+
_, err = rm.sdkapi.TagResourceWithContext(
320+
ctx,
321+
&svcsdk.TagResourceInput{
322+
ResourceArn: arn,
323+
Tags: sdkTagsFromResourceTags(toAdd),
324+
},
325+
)
326+
rm.metrics.RecordAPICall("UPDATE", "TagResource", err)
327+
if err != nil {
328+
return err
329+
}
330+
}
331+
332+
return nil
333+
}
334+
335+
func computeTagsDelta(
336+
desired []*svcapitypes.Tag,
337+
latest []*svcapitypes.Tag,
338+
) (addedOrUpdated []*svcapitypes.Tag, removed []*string) {
339+
var visitedIndexes []string
340+
341+
for _, latestElement := range latest {
342+
visitedIndexes = append(visitedIndexes, *latestElement.Key)
343+
for _, desiredElement := range desired {
344+
if equalStrings(latestElement.Key, desiredElement.Key) {
345+
if !equalStrings(latestElement.Value, desiredElement.Value) {
346+
addedOrUpdated = append(addedOrUpdated, desiredElement)
347+
}
348+
continue
349+
}
350+
}
351+
removed = append(removed, latestElement.Key)
352+
}
353+
for _, desiredElement := range desired {
354+
if !ackutil.InStrings(*desiredElement.Key, visitedIndexes) {
355+
addedOrUpdated = append(addedOrUpdated, desiredElement)
356+
}
357+
}
358+
return addedOrUpdated, removed
359+
}
360+
361+
func sdkTagsFromResourceTags(
362+
rTags []*svcapitypes.Tag,
363+
) []*svcsdk.Tag {
364+
tags := make([]*svcsdk.Tag, len(rTags))
365+
for i := range rTags {
366+
tags[i] = &svcsdk.Tag{
367+
Key: rTags[i].Key,
368+
Value: rTags[i].Value,
369+
}
370+
}
371+
return tags
372+
}
373+
374+
func resourceTagsFromSDKTags(
375+
sdkTags []*svcsdk.Tag,
376+
) []*svcapitypes.Tag {
377+
tags := make([]*svcapitypes.Tag, len(sdkTags))
378+
for i := range sdkTags {
379+
tags[i] = &svcapitypes.Tag{
380+
Key: sdkTags[i].Key,
381+
Value: sdkTags[i].Value,
382+
}
383+
}
384+
return tags
385+
}
386+
387+
func equalStrings(a, b *string) bool {
388+
if a == nil {
389+
return b == nil || *b == ""
390+
}
391+
return (*a == "" && b == nil) || *a == *b
392+
}

pkg/resource/cluster/sdk.go

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

templates/hooks/cluster/sdk_read_many_post_set_output.go.tpl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,11 @@
2727
respErr := rm.setAllowedNodeTypeUpdates(ctx, ko)
2828
if respErr != nil {
2929
return nil, respErr
30-
}
30+
}
31+
32+
resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN)
33+
tags, err := rm.getTags(ctx, *resourceARN)
34+
if err != nil {
35+
return nil, err
36+
}
37+
ko.Spec.Tags = tags

templates/hooks/cluster/sdk_update_pre_build_request.go.tpl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,15 @@
22

33
if err != nil || res!= nil{
44
return res, err
5-
}
5+
}
6+
7+
if delta.DifferentAt("Spec.Tags") {
8+
err = rm.updateTags(ctx, desired, latest)
9+
if err != nil {
10+
return nil, err
11+
}
12+
}
13+
14+
if !delta.DifferentExcept("Spec.Tags") {
15+
return desired, nil
16+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
id: "CLUSTER_UPDATE_WITH_TAGS"
2+
description: "In this test we create cluster and update cluster with tags"
3+
#marks:
4+
# - slow
5+
# - blocked
6+
steps:
7+
- id: "CLUSTER_INITIAL_CREATE"
8+
description: "Create Cluster with no tags"
9+
create:
10+
apiVersion: $CRD_GROUP/$CRD_VERSION
11+
kind: Cluster
12+
metadata:
13+
name: cluster$RANDOM_SUFFIX
14+
spec:
15+
name: cluster$RANDOM_SUFFIX
16+
nodeType: db.t4g.small
17+
aclName: open-access
18+
numShards: 1
19+
wait:
20+
status:
21+
conditions:
22+
ACK.ResourceSynced:
23+
status: "True"
24+
timeout: 7200
25+
- id: "CLUSTER_ADD_TAGS"
26+
description: "Add tags in Cluster"
27+
patch:
28+
apiVersion: $CRD_GROUP/$CRD_VERSION
29+
kind: Cluster
30+
metadata:
31+
name: cluster$RANDOM_SUFFIX
32+
spec:
33+
tags:
34+
- key: "test_key_1"
35+
value: "test_value_1"
36+
- key: "test_key_2"
37+
- key:
38+
wait:
39+
status:
40+
conditions:
41+
ACK.ResourceSynced:
42+
status: "True"
43+
timeout: 100
44+
- id: "CLUSTER_DELETE_TAGS"
45+
description: "Delete tags in Cluster"
46+
patch:
47+
apiVersion: $CRD_GROUP/$CRD_VERSION
48+
kind: Cluster
49+
metadata:
50+
name: cluster$RANDOM_SUFFIX
51+
spec:
52+
tags:
53+
- key: "test_key_1"
54+
value: "test_value_1"
55+
wait:
56+
status:
57+
conditions:
58+
ACK.ResourceSynced:
59+
status: "True"
60+
timeout: 100
61+
- id: "Cluster_ADD_AND_DELETE_TAGS"
62+
description: "Add some tags and delete some tags in Cluster"
63+
patch:
64+
apiVersion: $CRD_GROUP/$CRD_VERSION
65+
kind: Cluster
66+
metadata:
67+
name: cluster$RANDOM_SUFFIX
68+
spec:
69+
tags:
70+
- key: "test_key_2"
71+
value: "test_value_2"
72+
wait:
73+
status:
74+
conditions:
75+
ACK.ResourceSynced:
76+
status: "True"
77+
timeout: 100
78+
- id: "DELETE_CLUSTER"
79+
description: "Delete the cluster"
80+
delete:
81+
apiVersion: $CRD_GROUP/$CRD_VERSION
82+
kind: Cluster
83+
metadata:
84+
name: cluster$RANDOM_SUFFIX

0 commit comments

Comments
 (0)