Skip to content

Commit 94c0048

Browse files
authored
support updating tags on DB cluster param groups (#75)
Adds support for updating and retrieving tags for DB cluster parameter groups. Signed-off-by: Jay Pipes <[email protected]> Issue aws-controllers-k8s/community#1276 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 3f86cd2 commit 94c0048

File tree

14 files changed

+358
-126
lines changed

14 files changed

+358
-126
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-05-10T13:35:23Z"
2+
build_date: "2022-05-10T15:08:44Z"
33
build_hash: c6efa6ac643edb21219e0763541b2558718b5fe6
44
go_version: go1.18.1
55
version: v0.18.4-10-gc6efa6a
66
api_directory_checksum: e7bbd21f4f975f9cf1e1e804ebd450e8e310023d
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.42.0
99
generator_config_info:
10-
file_checksum: abea9fcd7e75ec05fc8004dc944a49528ff3652f
10+
file_checksum: ad1e93741dacbcf19188d95771c12957936a5e1d
1111
original_file_name: generator.yaml
1212
last_modification:
1313
reason: API generation

apis/v1alpha1/generator.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ resources:
112112
DeleteDBClusterParameterGroup:
113113
input_fields:
114114
DBClusterParameterGroupName: Name
115+
update_operation:
116+
# We need a custom update implementation until the issue behind
117+
# https://github.com/aws-controllers-k8s/community/issues/869 is
118+
# resolved.
119+
custom_method_name: customUpdate
120+
hooks:
121+
sdk_read_many_post_set_output:
122+
template_path: hooks/db_cluster_parameter_group/sdk_read_many_post_set_output.go.tpl
123+
delta_pre_compare:
124+
template_path: hooks/db_cluster_parameter_group/delta_pre_compare.go.tpl
115125
fields:
116126
Name:
117127
is_primary_key: true

generator.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ resources:
112112
DeleteDBClusterParameterGroup:
113113
input_fields:
114114
DBClusterParameterGroupName: Name
115+
update_operation:
116+
# We need a custom update implementation until the issue behind
117+
# https://github.com/aws-controllers-k8s/community/issues/869 is
118+
# resolved.
119+
custom_method_name: customUpdate
120+
hooks:
121+
sdk_read_many_post_set_output:
122+
template_path: hooks/db_cluster_parameter_group/sdk_read_many_post_set_output.go.tpl
123+
delta_pre_compare:
124+
template_path: hooks/db_cluster_parameter_group/delta_pre_compare.go.tpl
115125
fields:
116126
Name:
117127
is_primary_key: true

pkg/resource/db_cluster_parameter_group/delta.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
package db_cluster_parameter_group
15+
16+
import (
17+
"context"
18+
19+
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
20+
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
21+
22+
svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1"
23+
svcsdk "github.com/aws/aws-sdk-go/service/rds"
24+
)
25+
26+
// customUpdate is required to fix
27+
// https://github.com/aws-controllers-k8s/community/issues/869.
28+
//
29+
// We will need to update parameters in a parameter group using custom logic.
30+
// Until then, however, let's support updating tags for the parameter group.
31+
func (rm *resourceManager) customUpdate(
32+
ctx context.Context,
33+
desired *resource,
34+
latest *resource,
35+
delta *ackcompare.Delta,
36+
) (updated *resource, err error) {
37+
rlog := ackrtlog.FromContext(ctx)
38+
exit := rlog.Trace("rm.customUpdate")
39+
defer func() {
40+
exit(err)
41+
}()
42+
if delta.DifferentAt("Spec.Tags") {
43+
if err = rm.syncTags(ctx, desired, latest); err != nil {
44+
return nil, err
45+
}
46+
}
47+
return desired, nil
48+
}
49+
50+
// syncTags keeps the resource's tags in sync
51+
//
52+
// NOTE(jaypipes): RDS' Tagging APIs differ from other AWS APIs in the
53+
// following ways:
54+
//
55+
// 1. The names of the tagging API operations are different. Other APIs use the
56+
// Tagris `ListTagsForResource`, `TagResource` and `UntagResource` API
57+
// calls. RDS uses `ListTagsForResource`, `AddTagsToResource` and
58+
// `RemoveTagsFromResource`.
59+
//
60+
// 2. Even though the name of the `ListTagsForResource` API call is the same,
61+
// the structure of the input and the output are different from other APIs.
62+
// For the input, instead of a `ResourceArn` field, RDS names the field
63+
// `ResourceName`, but actually expects an ARN, not the parameter group
64+
// name. This is the same for the `AddTagsToResource` and
65+
// `RemoveTagsFromResource` input shapes. For the output shape, the field is
66+
// called `TagList` instead of `Tags` but is otherwise the same struct with
67+
// a `Key` and `Value` member field.
68+
func (rm *resourceManager) syncTags(
69+
ctx context.Context,
70+
desired *resource,
71+
latest *resource,
72+
) (err error) {
73+
rlog := ackrtlog.FromContext(ctx)
74+
exit := rlog.Trace("rm.syncTags")
75+
defer func() { exit(err) }()
76+
77+
arn := (*string)(latest.ko.Status.ACKResourceMetadata.ARN)
78+
79+
toAdd, toDelete := computeTagsDelta(
80+
desired.ko.Spec.Tags, latest.ko.Spec.Tags,
81+
)
82+
83+
if len(toDelete) > 0 {
84+
rlog.Debug("removing tags from cluster parameter group", "tags", toDelete)
85+
_, err = rm.sdkapi.RemoveTagsFromResourceWithContext(
86+
ctx,
87+
&svcsdk.RemoveTagsFromResourceInput{
88+
ResourceName: arn,
89+
TagKeys: toDelete,
90+
},
91+
)
92+
rm.metrics.RecordAPICall("UPDATE", "RemoveTagsFromResource", err)
93+
if err != nil {
94+
return err
95+
}
96+
}
97+
98+
// NOTE(jaypipes): According to the RDS API documentation, adding a tag
99+
// with a new value overwrites any existing tag with the same key. So, we
100+
// don't need to do anything to "update" a Tag. Simply including it in the
101+
// AddTagsToResource call is enough.
102+
if len(toAdd) > 0 {
103+
rlog.Debug("adding tags to cluster parameter group", "tags", toAdd)
104+
_, err = rm.sdkapi.AddTagsToResourceWithContext(
105+
ctx,
106+
&svcsdk.AddTagsToResourceInput{
107+
ResourceName: arn,
108+
Tags: sdkTagsFromResourceTags(toAdd),
109+
},
110+
)
111+
rm.metrics.RecordAPICall("UPDATE", "AddTagsToResource", err)
112+
if err != nil {
113+
return err
114+
}
115+
}
116+
return nil
117+
}
118+
119+
// getTags retrieves the resource's associated tags
120+
func (rm *resourceManager) getTags(
121+
ctx context.Context,
122+
resourceARN string,
123+
) ([]*svcapitypes.Tag, error) {
124+
resp, err := rm.sdkapi.ListTagsForResourceWithContext(
125+
ctx,
126+
&svcsdk.ListTagsForResourceInput{
127+
ResourceName: &resourceARN,
128+
},
129+
)
130+
rm.metrics.RecordAPICall("GET", "ListTagsForResource", err)
131+
if err != nil {
132+
return nil, err
133+
}
134+
tags := make([]*svcapitypes.Tag, 0, len(resp.TagList))
135+
for _, tag := range resp.TagList {
136+
tags = append(tags, &svcapitypes.Tag{
137+
Key: tag.Key,
138+
Value: tag.Value,
139+
})
140+
}
141+
return tags, nil
142+
}
143+
144+
// compareTags adds a difference to the delta if the supplied resources have
145+
// different tag collections
146+
func compareTags(
147+
delta *ackcompare.Delta,
148+
a *resource,
149+
b *resource,
150+
) {
151+
if len(a.ko.Spec.Tags) != len(b.ko.Spec.Tags) {
152+
delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags)
153+
} else if len(a.ko.Spec.Tags) > 0 {
154+
if !equalTags(a.ko.Spec.Tags, b.ko.Spec.Tags) {
155+
delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags)
156+
}
157+
}
158+
}
159+
160+
// equalTags returns true if two Tag arrays are equal regardless of the order
161+
// of their elements.
162+
func equalTags(
163+
a []*svcapitypes.Tag,
164+
b []*svcapitypes.Tag,
165+
) bool {
166+
added, removed := computeTagsDelta(a, b)
167+
return len(added) == 0 && len(removed) == 0
168+
}
169+
170+
// computeTagsDelta compares two Tag arrays and returns the tags to add and the
171+
// tag keys to delete
172+
func computeTagsDelta(
173+
desired []*svcapitypes.Tag,
174+
latest []*svcapitypes.Tag,
175+
) ([]*svcapitypes.Tag, []*string) {
176+
toDelete := []*string{}
177+
toAdd := []*svcapitypes.Tag{}
178+
179+
desiredTags := map[string]string{}
180+
for _, tag := range desired {
181+
desiredTags[*tag.Key] = *tag.Value
182+
}
183+
184+
for _, tag := range desired {
185+
toAdd = append(toAdd, tag)
186+
}
187+
for _, tag := range latest {
188+
_, ok := desiredTags[*tag.Key]
189+
if !ok {
190+
toDelete = append(toDelete, tag.Key)
191+
}
192+
}
193+
return toAdd, toDelete
194+
}
195+
196+
// sdkTagsFromResourceTags transforms a *svcapitypes.Tag array to a *svcsdk.Tag
197+
// array.
198+
func sdkTagsFromResourceTags(
199+
rTags []*svcapitypes.Tag,
200+
) []*svcsdk.Tag {
201+
tags := make([]*svcsdk.Tag, len(rTags))
202+
for i := range rTags {
203+
tags[i] = &svcsdk.Tag{
204+
Key: rTags[i].Key,
205+
Value: rTags[i].Value,
206+
}
207+
}
208+
return tags
209+
}
210+
211+
func equalStrings(a, b *string) bool {
212+
if a == nil {
213+
return b == nil || *b == ""
214+
}
215+
return (*a == "" && b == nil) || *a == *b
216+
}

pkg/resource/db_cluster_parameter_group/sdk.go

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

pkg/resource/db_parameter_group/hooks.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ func equalTags(
172172
func computeTagsDelta(
173173
desired []*svcapitypes.Tag,
174174
latest []*svcapitypes.Tag,
175-
) (added []*svcapitypes.Tag, removed []*string) {
175+
) ([]*svcapitypes.Tag, []*string) {
176176
toDelete := []*string{}
177177
toAdd := []*svcapitypes.Tag{}
178178

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
compareTags(delta, a, b)

0 commit comments

Comments
 (0)