Skip to content

Commit 0cd29f3

Browse files
authored
Supports Tag and Untag APIs for ACL. (#44)
Issue #, if available: Customers cannot modify tags of ACL. Description of changes: Adds functions so that customers can modify tags of ACL 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 a6318da commit 0cd29f3

File tree

9 files changed

+344
-60
lines changed

9 files changed

+344
-60
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
ack_generate_info:
2-
build_date: "2022-12-22T20:12:01Z"
2+
build_date: "2022-12-23T06:27:19Z"
33
build_hash: 16f0e201b37a06b535370cc69e11adb934a22d33
44
go_version: go1.19
55
version: v0.20.1-18-g16f0e20
66
api_directory_checksum: a1e396caca4bdd1612fa7d09f0ee56f3e4976ff7
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.44.93
99
generator_config_info:
10-
file_checksum: 8aa3940404a0667041e270bce2d86684b9e1df4d
10+
file_checksum: 62ca61f60f6152f6c53f31b6ebbe43b39f86d225
1111
original_file_name: generator.yaml
1212
last_modification:
1313
reason: API generation

apis/v1alpha1/generator.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ resources:
118118
- InvalidParameterCombinationException
119119
- TagQuotaPerResourceExceeded
120120
hooks:
121+
sdk_read_many_post_set_output:
122+
template_path: hooks/acl/sdk_read_many_post_set_output.go.tpl
121123
sdk_update_pre_build_request:
122124
template_path: hooks/acl/sdk_update_pre_build_request.go.tpl
123125
sdk_update_post_build_request:

generator.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ resources:
118118
- InvalidParameterCombinationException
119119
- TagQuotaPerResourceExceeded
120120
hooks:
121+
sdk_read_many_post_set_output:
122+
template_path: hooks/acl/sdk_read_many_post_set_output.go.tpl
121123
sdk_update_pre_build_request:
122124
template_path: hooks/acl/sdk_update_pre_build_request.go.tpl
123125
sdk_update_post_build_request:

pkg/resource/acl/hooks.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@
1414
package acl
1515

1616
import (
17+
"context"
1718
"github.com/pkg/errors"
1819

1920
"github.com/aws-controllers-k8s/runtime/pkg/requeue"
21+
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
22+
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
23+
24+
svcapitypes "github.com/aws-controllers-k8s/memorydb-controller/apis/v1alpha1"
25+
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
2026
)
2127

2228
// validateACLNeedsUpdate this function's purpose is to requeue if the resource is currently unavailable
@@ -34,3 +40,130 @@ func (rm *resourceManager) validateACLNeedsUpdate(
3440

3541
return nil
3642
}
43+
44+
// getTags gets tags from given ParameterGroup.
45+
func (rm *resourceManager) getTags(
46+
ctx context.Context,
47+
resourceARN string,
48+
) ([]*svcapitypes.Tag, error) {
49+
resp, err := rm.sdkapi.ListTagsWithContext(
50+
ctx,
51+
&svcsdk.ListTagsInput{
52+
ResourceArn: &resourceARN,
53+
},
54+
)
55+
rm.metrics.RecordAPICall("GET", "ListTags", err)
56+
if err != nil {
57+
return nil, err
58+
}
59+
tags := resourceTagsFromSDKTags(resp.TagList)
60+
return tags, nil
61+
}
62+
63+
// updateTags updates tags of given ParameterGroup to desired tags.
64+
func (rm *resourceManager) updateTags(
65+
ctx context.Context,
66+
desired *resource,
67+
latest *resource,
68+
) (err error) {
69+
rlog := ackrtlog.FromContext(ctx)
70+
exit := rlog.Trace("rm.updateTags")
71+
defer func(err error) { exit(err) }(err)
72+
73+
arn := (*string)(latest.ko.Status.ACKResourceMetadata.ARN)
74+
75+
toAdd, toDelete := computeTagsDelta(
76+
desired.ko.Spec.Tags, latest.ko.Spec.Tags,
77+
)
78+
79+
if len(toDelete) > 0 {
80+
rlog.Debug("removing tags from ACL", "tags", toDelete)
81+
_, err = rm.sdkapi.UntagResourceWithContext(
82+
ctx,
83+
&svcsdk.UntagResourceInput{
84+
ResourceArn: arn,
85+
TagKeys: toDelete,
86+
},
87+
)
88+
rm.metrics.RecordAPICall("UPDATE", "UntagResource", err)
89+
if err != nil {
90+
return err
91+
}
92+
}
93+
94+
if len(toAdd) > 0 {
95+
rlog.Debug("adding tags to ACL", "tags", toAdd)
96+
_, err = rm.sdkapi.TagResourceWithContext(
97+
ctx,
98+
&svcsdk.TagResourceInput{
99+
ResourceArn: arn,
100+
Tags: sdkTagsFromResourceTags(toAdd),
101+
},
102+
)
103+
rm.metrics.RecordAPICall("UPDATE", "TagResource", err)
104+
if err != nil {
105+
return err
106+
}
107+
}
108+
109+
return nil
110+
}
111+
112+
func computeTagsDelta(
113+
desired []*svcapitypes.Tag,
114+
latest []*svcapitypes.Tag,
115+
) (addedOrUpdated []*svcapitypes.Tag, removed []*string) {
116+
var visitedIndexes []string
117+
118+
for _, latestElement := range latest {
119+
visitedIndexes = append(visitedIndexes, *latestElement.Key)
120+
for _, desiredElement := range desired {
121+
if equalStrings(latestElement.Key, desiredElement.Key) {
122+
if !equalStrings(latestElement.Value, desiredElement.Value) {
123+
addedOrUpdated = append(addedOrUpdated, desiredElement)
124+
}
125+
continue
126+
}
127+
}
128+
removed = append(removed, latestElement.Key)
129+
}
130+
for _, desiredElement := range desired {
131+
if !ackutil.InStrings(*desiredElement.Key, visitedIndexes) {
132+
addedOrUpdated = append(addedOrUpdated, desiredElement)
133+
}
134+
}
135+
return addedOrUpdated, removed
136+
}
137+
138+
func sdkTagsFromResourceTags(
139+
rTags []*svcapitypes.Tag,
140+
) []*svcsdk.Tag {
141+
tags := make([]*svcsdk.Tag, len(rTags))
142+
for i := range rTags {
143+
tags[i] = &svcsdk.Tag{
144+
Key: rTags[i].Key,
145+
Value: rTags[i].Value,
146+
}
147+
}
148+
return tags
149+
}
150+
151+
func resourceTagsFromSDKTags(
152+
sdkTags []*svcsdk.Tag,
153+
) []*svcapitypes.Tag {
154+
tags := make([]*svcapitypes.Tag, len(sdkTags))
155+
for i := range sdkTags {
156+
tags[i] = &svcapitypes.Tag{
157+
Key: sdkTags[i].Key,
158+
Value: sdkTags[i].Value,
159+
}
160+
}
161+
return tags
162+
}
163+
164+
func equalStrings(a, b *string) bool {
165+
if a == nil {
166+
return b == nil || *b == ""
167+
}
168+
return (*a == "" && b == nil) || *a == *b
169+
}

pkg/resource/acl/sdk.go

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN)
2+
tags, err := rm.getTags(ctx, *resourceARN)
3+
if err != nil {
4+
return nil, err
5+
}
6+
ko.Spec.Tags = tags
Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,54 @@
1-
createMapForUserNames := func(userIds []*string) map[string]bool {
2-
userIdsMap := make(map[string]bool)
3-
4-
for _, userId := range userIds {
5-
userIdsMap[*userId] = true
6-
}
7-
8-
return userIdsMap
9-
}
10-
11-
for _, diff := range delta.Differences {
12-
if diff.Path.Contains("Spec.UserNames") {
13-
existingUserNamesMap := createMapForUserNames(diff.B.([]*string))
14-
requiredUserNamesMap := createMapForUserNames(diff.A.([]*string))
15-
16-
// If a user ID is not required to be deleted or added set its value as false
17-
for userName, _ := range existingUserNamesMap {
18-
if _, ok := requiredUserNamesMap[userName]; ok {
19-
requiredUserNamesMap[userName] = false
20-
existingUserNamesMap[userName] = false
21-
}
22-
}
23-
24-
if err != nil {
25-
return nil, err
26-
}
27-
28-
// User Ids to add
29-
{
30-
var userNamesToAdd []*string
31-
32-
for userName, include := range requiredUserNamesMap {
33-
if include {
34-
userNamesToAdd = append(userNamesToAdd, &userName)
35-
}
36-
}
37-
38-
input.SetUserNamesToAdd(userNamesToAdd)
39-
}
40-
41-
// User Ids to remove
42-
{
43-
var userNamesToRemove []*string
44-
45-
for userName, include := range existingUserNamesMap {
46-
if include {
47-
userNamesToRemove = append(userNamesToRemove, &userName)
48-
}
49-
}
50-
51-
input.SetUserNamesToRemove(userNamesToRemove)
52-
}
53-
}
54-
}
1+
createMapForUserNames := func(userIds []*string) map[string]bool {
2+
userIdsMap := make(map[string]bool)
3+
4+
for _, userId := range userIds {
5+
userIdsMap[*userId] = true
6+
}
7+
8+
return userIdsMap
9+
}
10+
11+
for _, diff := range delta.Differences {
12+
if diff.Path.Contains("Spec.UserNames") {
13+
existingUserNamesMap := createMapForUserNames(diff.B.([]*string))
14+
requiredUserNamesMap := createMapForUserNames(diff.A.([]*string))
15+
16+
// If a user ID is not required to be deleted or added set its value as false
17+
for userName, _ := range existingUserNamesMap {
18+
if _, ok := requiredUserNamesMap[userName]; ok {
19+
requiredUserNamesMap[userName] = false
20+
existingUserNamesMap[userName] = false
21+
}
22+
}
23+
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
// User Ids to add
29+
{
30+
var userNamesToAdd []*string
31+
32+
for userName, include := range requiredUserNamesMap {
33+
if include {
34+
userNamesToAdd = append(userNamesToAdd, &userName)
35+
}
36+
}
37+
38+
input.SetUserNamesToAdd(userNamesToAdd)
39+
}
40+
41+
// User Ids to remove
42+
{
43+
var userNamesToRemove []*string
44+
45+
for userName, include := range existingUserNamesMap {
46+
if include {
47+
userNamesToRemove = append(userNamesToRemove, &userName)
48+
}
49+
}
50+
51+
input.SetUserNamesToRemove(userNamesToRemove)
52+
}
53+
}
54+
}
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1-
validationErr := rm.validateACLNeedsUpdate(latest)
1+
validationErr := rm.validateACLNeedsUpdate(latest)
22

3-
if validationErr != nil {
4-
return nil, err
5-
}
3+
if validationErr != nil {
4+
return nil, err
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+
}

0 commit comments

Comments
 (0)