Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tag and Untag API for cluster. #43

Merged
merged 1 commit into from
Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apis/v1alpha1/ack-generate-metadata.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ack_generate_info:
build_date: "2022-12-14T00:10:49Z"
build_date: "2022-12-22T20:12:01Z"
build_hash: 16f0e201b37a06b535370cc69e11adb934a22d33
go_version: go1.19
version: v0.20.1-18-g16f0e20
Expand Down
134 changes: 131 additions & 3 deletions pkg/resource/cluster/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ import (
"context"
"errors"
"fmt"
"strconv"

ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors"
"strconv"
ackrequeue "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"

ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
)

var (
Expand Down Expand Up @@ -262,3 +263,130 @@ func (rm *resourceManager) newMemoryDBClusterUploadPayload(

return res
}

// 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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a READ_MANY instead of GET

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for correcting me!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After careful consideration, I still think it should be GET here. May I know why you think it should be READ_MANY here instead? @jljaco

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kyriechen96 please disregard this comment -- there may be some inconsistencies across ACK controllers in how this choice is made, and we will circle back to this later if necessary. you're good with GET!

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 cluster", "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 cluster", "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
}
20 changes: 20 additions & 0 deletions pkg/resource/cluster/sdk.go

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

9 changes: 8 additions & 1 deletion templates/hooks/cluster/sdk_read_many_post_set_output.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,11 @@
respErr := rm.setAllowedNodeTypeUpdates(ctx, ko)
if respErr != nil {
return nil, respErr
}
}

resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN)
tags, err := rm.getTags(ctx, *resourceARN)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation needs fixing here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this happened. The indentation looks good in my local file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Github bug I think

if err != nil {
return nil, err
}
ko.Spec.Tags = tags
13 changes: 12 additions & 1 deletion templates/hooks/cluster/sdk_update_pre_build_request.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,15 @@

if err != nil || res!= nil{
return res, 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
}
84 changes: 84 additions & 0 deletions test/e2e/scenarios/Cluster/cluster_update_with_tags.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
id: "CLUSTER_UPDATE_WITH_TAGS"
description: "In this test we create cluster and update cluster with tags"
#marks:
# - slow
# - blocked
steps:
- id: "CLUSTER_INITIAL_CREATE"
description: "Create Cluster with no tags"
create:
apiVersion: $CRD_GROUP/$CRD_VERSION
kind: Cluster
metadata:
name: cluster$RANDOM_SUFFIX
spec:
name: cluster$RANDOM_SUFFIX
nodeType: db.t4g.small
aclName: open-access
numShards: 1
wait:
status:
conditions:
ACK.ResourceSynced:
status: "True"
timeout: 7200
- id: "CLUSTER_ADD_TAGS"
description: "Add tags in Cluster"
patch:
apiVersion: $CRD_GROUP/$CRD_VERSION
kind: Cluster
metadata:
name: cluster$RANDOM_SUFFIX
spec:
tags:
- key: "test_key_1"
value: "test_value_1"
- key: "test_key_2"
- key:
wait:
status:
conditions:
ACK.ResourceSynced:
status: "True"
timeout: 100
- id: "CLUSTER_DELETE_TAGS"
description: "Delete tags in Cluster"
patch:
apiVersion: $CRD_GROUP/$CRD_VERSION
kind: Cluster
metadata:
name: cluster$RANDOM_SUFFIX
spec:
tags:
- key: "test_key_1"
value: "test_value_1"
wait:
status:
conditions:
ACK.ResourceSynced:
status: "True"
timeout: 100
- id: "Cluster_ADD_AND_DELETE_TAGS"
description: "Add some tags and delete some tags in Cluster"
patch:
apiVersion: $CRD_GROUP/$CRD_VERSION
kind: Cluster
metadata:
name: cluster$RANDOM_SUFFIX
spec:
tags:
- key: "test_key_2"
value: "test_value_2"
wait:
status:
conditions:
ACK.ResourceSynced:
status: "True"
timeout: 100
- id: "DELETE_CLUSTER"
description: "Delete the cluster"
delete:
apiVersion: $CRD_GROUP/$CRD_VERSION
kind: Cluster
metadata:
name: cluster$RANDOM_SUFFIX