Skip to content

Commit

Permalink
Supports Tag and Untag APIs for ACL. (#44)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kyriechen96 authored Dec 23, 2022
1 parent a6318da commit 0cd29f3
Show file tree
Hide file tree
Showing 9 changed files with 344 additions and 60 deletions.
4 changes: 2 additions & 2 deletions apis/v1alpha1/ack-generate-metadata.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
ack_generate_info:
build_date: "2022-12-22T20:12:01Z"
build_date: "2022-12-23T06:27:19Z"
build_hash: 16f0e201b37a06b535370cc69e11adb934a22d33
go_version: go1.19
version: v0.20.1-18-g16f0e20
api_directory_checksum: a1e396caca4bdd1612fa7d09f0ee56f3e4976ff7
api_version: v1alpha1
aws_sdk_go_version: v1.44.93
generator_config_info:
file_checksum: 8aa3940404a0667041e270bce2d86684b9e1df4d
file_checksum: 62ca61f60f6152f6c53f31b6ebbe43b39f86d225
original_file_name: generator.yaml
last_modification:
reason: API generation
2 changes: 2 additions & 0 deletions apis/v1alpha1/generator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ resources:
- InvalidParameterCombinationException
- TagQuotaPerResourceExceeded
hooks:
sdk_read_many_post_set_output:
template_path: hooks/acl/sdk_read_many_post_set_output.go.tpl
sdk_update_pre_build_request:
template_path: hooks/acl/sdk_update_pre_build_request.go.tpl
sdk_update_post_build_request:
Expand Down
2 changes: 2 additions & 0 deletions generator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ resources:
- InvalidParameterCombinationException
- TagQuotaPerResourceExceeded
hooks:
sdk_read_many_post_set_output:
template_path: hooks/acl/sdk_read_many_post_set_output.go.tpl
sdk_update_pre_build_request:
template_path: hooks/acl/sdk_update_pre_build_request.go.tpl
sdk_update_post_build_request:
Expand Down
133 changes: 133 additions & 0 deletions pkg/resource/acl/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@
package acl

import (
"context"
"github.com/pkg/errors"

"github.com/aws-controllers-k8s/runtime/pkg/requeue"
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"

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

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

return nil
}

// getTags gets tags from given ParameterGroup.
func (rm *resourceManager) getTags(
ctx context.Context,
resourceARN string,
) ([]*svcapitypes.Tag, error) {
resp, err := rm.sdkapi.ListTagsWithContext(
ctx,
&svcsdk.ListTagsInput{
ResourceArn: &resourceARN,
},
)
rm.metrics.RecordAPICall("GET", "ListTags", err)
if err != nil {
return nil, err
}
tags := resourceTagsFromSDKTags(resp.TagList)
return tags, nil
}

// updateTags updates tags of given ParameterGroup to desired tags.
func (rm *resourceManager) updateTags(
ctx context.Context,
desired *resource,
latest *resource,
) (err error) {
rlog := ackrtlog.FromContext(ctx)
exit := rlog.Trace("rm.updateTags")
defer func(err error) { exit(err) }(err)

arn := (*string)(latest.ko.Status.ACKResourceMetadata.ARN)

toAdd, toDelete := computeTagsDelta(
desired.ko.Spec.Tags, latest.ko.Spec.Tags,
)

if len(toDelete) > 0 {
rlog.Debug("removing tags from ACL", "tags", toDelete)
_, err = rm.sdkapi.UntagResourceWithContext(
ctx,
&svcsdk.UntagResourceInput{
ResourceArn: arn,
TagKeys: toDelete,
},
)
rm.metrics.RecordAPICall("UPDATE", "UntagResource", err)
if err != nil {
return err
}
}

if len(toAdd) > 0 {
rlog.Debug("adding tags to ACL", "tags", toAdd)
_, err = rm.sdkapi.TagResourceWithContext(
ctx,
&svcsdk.TagResourceInput{
ResourceArn: arn,
Tags: sdkTagsFromResourceTags(toAdd),
},
)
rm.metrics.RecordAPICall("UPDATE", "TagResource", err)
if err != nil {
return err
}
}

return nil
}

func computeTagsDelta(
desired []*svcapitypes.Tag,
latest []*svcapitypes.Tag,
) (addedOrUpdated []*svcapitypes.Tag, removed []*string) {
var visitedIndexes []string

for _, latestElement := range latest {
visitedIndexes = append(visitedIndexes, *latestElement.Key)
for _, desiredElement := range desired {
if equalStrings(latestElement.Key, desiredElement.Key) {
if !equalStrings(latestElement.Value, desiredElement.Value) {
addedOrUpdated = append(addedOrUpdated, desiredElement)
}
continue
}
}
removed = append(removed, latestElement.Key)
}
for _, desiredElement := range desired {
if !ackutil.InStrings(*desiredElement.Key, visitedIndexes) {
addedOrUpdated = append(addedOrUpdated, desiredElement)
}
}
return addedOrUpdated, removed
}

func sdkTagsFromResourceTags(
rTags []*svcapitypes.Tag,
) []*svcsdk.Tag {
tags := make([]*svcsdk.Tag, len(rTags))
for i := range rTags {
tags[i] = &svcsdk.Tag{
Key: rTags[i].Key,
Value: rTags[i].Value,
}
}
return tags
}

func resourceTagsFromSDKTags(
sdkTags []*svcsdk.Tag,
) []*svcapitypes.Tag {
tags := make([]*svcapitypes.Tag, len(sdkTags))
for i := range sdkTags {
tags[i] = &svcapitypes.Tag{
Key: sdkTags[i].Key,
Value: sdkTags[i].Value,
}
}
return tags
}

func equalStrings(a, b *string) bool {
if a == nil {
return b == nil || *b == ""
}
return (*a == "" && b == nil) || *a == *b
}
19 changes: 19 additions & 0 deletions pkg/resource/acl/sdk.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions templates/hooks/acl/sdk_read_many_post_set_output.go.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN)
tags, err := rm.getTags(ctx, *resourceARN)
if err != nil {
return nil, err
}
ko.Spec.Tags = tags
108 changes: 54 additions & 54 deletions templates/hooks/acl/sdk_update_post_build_request.go.tpl
Original file line number Diff line number Diff line change
@@ -1,54 +1,54 @@
createMapForUserNames := func(userIds []*string) map[string]bool {
userIdsMap := make(map[string]bool)
for _, userId := range userIds {
userIdsMap[*userId] = true
}

return userIdsMap
}

for _, diff := range delta.Differences {
if diff.Path.Contains("Spec.UserNames") {
existingUserNamesMap := createMapForUserNames(diff.B.([]*string))
requiredUserNamesMap := createMapForUserNames(diff.A.([]*string))
// If a user ID is not required to be deleted or added set its value as false
for userName, _ := range existingUserNamesMap {
if _, ok := requiredUserNamesMap[userName]; ok {
requiredUserNamesMap[userName] = false
existingUserNamesMap[userName] = false
}
}

if err != nil {
return nil, err
}

// User Ids to add
{
var userNamesToAdd []*string
for userName, include := range requiredUserNamesMap {
if include {
userNamesToAdd = append(userNamesToAdd, &userName)
}
}

input.SetUserNamesToAdd(userNamesToAdd)
}

// User Ids to remove
{
var userNamesToRemove []*string
for userName, include := range existingUserNamesMap {
if include {
userNamesToRemove = append(userNamesToRemove, &userName)
}
}

input.SetUserNamesToRemove(userNamesToRemove)
}
}
}
createMapForUserNames := func(userIds []*string) map[string]bool {
userIdsMap := make(map[string]bool)
for _, userId := range userIds {
userIdsMap[*userId] = true
}

return userIdsMap
}

for _, diff := range delta.Differences {
if diff.Path.Contains("Spec.UserNames") {
existingUserNamesMap := createMapForUserNames(diff.B.([]*string))
requiredUserNamesMap := createMapForUserNames(diff.A.([]*string))
// If a user ID is not required to be deleted or added set its value as false
for userName, _ := range existingUserNamesMap {
if _, ok := requiredUserNamesMap[userName]; ok {
requiredUserNamesMap[userName] = false
existingUserNamesMap[userName] = false
}
}

if err != nil {
return nil, err
}

// User Ids to add
{
var userNamesToAdd []*string
for userName, include := range requiredUserNamesMap {
if include {
userNamesToAdd = append(userNamesToAdd, &userName)
}
}

input.SetUserNamesToAdd(userNamesToAdd)
}

// User Ids to remove
{
var userNamesToRemove []*string
for userName, include := range existingUserNamesMap {
if include {
userNamesToRemove = append(userNamesToRemove, &userName)
}
}

input.SetUserNamesToRemove(userNamesToRemove)
}
}
}
19 changes: 15 additions & 4 deletions templates/hooks/acl/sdk_update_pre_build_request.go.tpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
validationErr := rm.validateACLNeedsUpdate(latest)
validationErr := rm.validateACLNeedsUpdate(latest)

if validationErr != nil {
return nil, err
}
if validationErr != nil {
return nil, err
}

if delta.DifferentAt("Spec.Tags") {
err = rm.updateTags(ctx, desired, latest)
if err != nil {
return nil, err
}
}

if !delta.DifferentExcept("Spec.Tags") {
return desired, nil
}
Loading

0 comments on commit 0cd29f3

Please sign in to comment.