Skip to content

Commit 9df7dd6

Browse files
authored
Support Tag and Untag API for snapshot. (#46)
Issue #, if available: Customer cannot update tags after snapshot creation. Description of changes: Add functions that support Tag and Untag APIs for snapshot. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 2e57557 commit 9df7dd6

File tree

10 files changed

+294
-18
lines changed

10 files changed

+294
-18
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-23T17:00:07Z"
2+
build_date: "2022-12-24T00:37:23Z"
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: f50534e33903e1ca74491595fd6c21351988eb1c
10+
file_checksum: d7ad13c5bc8d9e9e2171c92dc3ac51c2b5e3b769
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
@@ -212,6 +212,8 @@ resources:
212212
from:
213213
operation: CreateSnapshot
214214
path: ClusterName
215+
update_operation:
216+
custom_method_name: customUpdate
215217
hooks:
216218
sdk_create_pre_build_request:
217219
template_path: hooks/snapshot/sdk_create_pre_build_request.go.tpl

generator.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ resources:
212212
from:
213213
operation: CreateSnapshot
214214
path: ClusterName
215+
update_operation:
216+
custom_method_name: customUpdate
215217
hooks:
216218
sdk_create_pre_build_request:
217219
template_path: hooks/snapshot/sdk_create_pre_build_request.go.tpl

pkg/resource/snapshot/hooks.go

Lines changed: 155 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,20 @@ import (
1717
"context"
1818
"errors"
1919

20-
svcapitypes "github.com/aws-controllers-k8s/memorydb-controller/apis/v1alpha1"
21-
ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1"
22-
ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors"
23-
"github.com/aws/aws-sdk-go/service/memorydb"
2420
svcsdk "github.com/aws/aws-sdk-go/service/memorydb"
25-
2621
corev1 "k8s.io/api/core/v1"
2722
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23+
24+
svcapitypes "github.com/aws-controllers-k8s/memorydb-controller/apis/v1alpha1"
25+
ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1"
26+
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
27+
ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors"
28+
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
29+
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
2830
)
2931

3032
func (rm *resourceManager) customDescribeSnapshotSetOutput(
31-
resp *memorydb.DescribeSnapshotsOutput,
33+
resp *svcsdk.DescribeSnapshotsOutput,
3234
ko *svcapitypes.Snapshot,
3335
) (*svcapitypes.Snapshot, error) {
3436
if len(resp.Snapshots) == 0 {
@@ -40,23 +42,23 @@ func (rm *resourceManager) customDescribeSnapshotSetOutput(
4042
}
4143

4244
func (rm *resourceManager) customCreateSnapshotSetOutput(
43-
resp *memorydb.CreateSnapshotOutput,
45+
resp *svcsdk.CreateSnapshotOutput,
4446
ko *svcapitypes.Snapshot,
4547
) (*svcapitypes.Snapshot, error) {
4648
rm.customSetOutput(resp.Snapshot, ko)
4749
return ko, nil
4850
}
4951

5052
func (rm *resourceManager) customCopySnapshotSetOutput(
51-
resp *memorydb.CopySnapshotOutput,
53+
resp *svcsdk.CopySnapshotOutput,
5254
ko *svcapitypes.Snapshot,
5355
) *svcapitypes.Snapshot {
5456
rm.customSetOutput(resp.Snapshot, ko)
5557
return ko
5658
}
5759

5860
func (rm *resourceManager) customSetOutput(
59-
respSnapshot *memorydb.Snapshot,
61+
respSnapshot *svcsdk.Snapshot,
6062
ko *svcapitypes.Snapshot,
6163
) {
6264
if ko.Status.Conditions == nil {
@@ -245,3 +247,147 @@ func (rm *resourceManager) newCopySnapshotPayload(
245247

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

pkg/resource/snapshot/sdk.go

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

templates/hooks/snapshot/sdk_read_many_post_set_output.go.tpl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,11 @@
22
ko, err = rm.customDescribeSnapshotSetOutput(resp, ko)
33
if err != nil {
44
return nil, err
5-
}
5+
}
6+
7+
resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN)
8+
tags, err := rm.getTags(ctx, *resourceARN)
9+
if err != nil {
10+
return nil, err
11+
}
12+
ko.Spec.Tags = tags

test/e2e/scenarios/Snapshot/snapshot_copy.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
id: "SNAPSHOT_COPY"
22
description: "In this test we copy snapshot from another snapshot"
3+
#marks:
4+
# - slow
5+
# - blocked
36
steps:
47
- id: "CREATE_INITIAL_SNAPSHOT"
58
description: "Create Initial Snapshot"
69
create:
710
apiVersion: $CRD_GROUP/$CRD_VERSION
811
kind: Snapshot
912
metadata:
10-
name: snapshot$RANDOM_SUFFIX
13+
name: snapshot$RANDOM_SUFFIX
1114
spec:
12-
description: "Create ACK snapshot"
1315
clusterName: $SNAPSHOT_CLUSTER_NAME2
1416
name: snapshot$RANDOM_SUFFIX
1517
wait:

test/e2e/scenarios/Snapshot/snapshot_create.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
id: "SNAPSHOT_CREATE"
22
description: "In this test we create Snapshot"
3+
#marks:
4+
# - slow
5+
# - blocked
36
steps:
47
- id: "CREATE_SNAPSHOT"
58
description: "ACK Snapshot"
@@ -9,7 +12,6 @@ steps:
912
metadata:
1013
name: snapshot$RANDOM_SUFFIX
1114
spec:
12-
description: "Create ACK snapshot"
1315
clusterName: $SNAPSHOT_CLUSTER_NAME1
1416
name: snapshot$RANDOM_SUFFIX
1517
wait:

test/e2e/scenarios/Snapshot/snapshot_create_terminal_condition.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
id: "SNAPSHOT_CREATE_TERMINAL_CONDITION"
22
description: "In this test we try to create snapshot without specifying cluster"
3+
#marks:
4+
# - slow
5+
# - blocked
36
steps:
47
- id: "SNAPSHOT_INITIAL_CREATE"
58
description: "Create snapshot with no clustername "
@@ -9,7 +12,6 @@ steps:
912
metadata:
1013
name: snapshot$RANDOM_SUFFIX
1114
spec:
12-
description: "Create ACK snapshot"
1315
name: snapshot$RANDOM_SUFFIX
1416
wait: 120
1517
expect:

0 commit comments

Comments
 (0)