Skip to content

Commit ca12303

Browse files
authored
Add new tag conversion funcitons that preserve order in lists of Tags (#572)
Description of changes: When converting between ACK tags (map[string]string) and resource tags(which could be either a list of Tag struct or map[string]*string) can be tricky. One issue that we found was order preservation, especially when converting from `map[string]string` to list of `Tag`. The changed order, when patched to the resource in the cluster, would trigger a reconciliation, for an unpredictable amount of times (at least until we luckily convert to the list with a preserved order.) This change introduces two new functions, similar to the existing ones. The `toACKTagsWithKeyOrder` has the same function as `ToACKTags`, but besides returning the ACK tags, it also returns a list of keys in the same order it is in the resource. The `fromACKTagsWithKeyOrder`, also similar to `FromACKTags`, accepts the keyOrder returned by `toACKTagsWithKeyOrder`, and rebuilds the resource tags, if it's a list, in the same order as it was before. Any extra tags will be added in random order. These two new functions will be called before and after `mirrowAWSTags` and `FilterSystemTags`. The extra tags mentioned earlier are the AWS tags that are mirrored from the latest resource (more explanation on what they are [here](aws-controllers-k8s/runtime#170)) and will be filtered before getting patched with [this](aws-controllers-k8s/runtime#172) change. This will ensure that the tags in desired will maintain their order and avoid triggering unnecessary reconciliations. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 5645e51 commit ca12303

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

templates/pkg/resource/manager.go.tpl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,10 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) {
341341
}
342342
{{ end -}}
343343
existingTags = r.ko.Spec.{{ $tagField.Path }}
344-
resourceTags := ToACKTags(existingTags)
344+
resourceTags, tagKeyOrder := toACKTagsWithKeyOrder(existingTags)
345345
ignoreSystemTags(resourceTags)
346346
{{ GoCodeInitializeNestedStructField .CRD "r.ko" $tagField "svcapitypes" 1 -}}
347-
r.ko.Spec.{{ $tagField.Path }} = FromACKTags(resourceTags)
347+
r.ko.Spec.{{ $tagField.Path }} = fromACKTagsWithKeyOrder(resourceTags, tagKeyOrder)
348348
{{- end }}
349349
{{- end }}
350350
}
@@ -393,11 +393,11 @@ func mirrorAWSTags(a *resource, b *resource) {
393393
existingDesiredTags = a.ko.Spec.{{ $tagField.Path }}
394394
{{ end -}}
395395
existingLatestTags = b.ko.Spec.{{ $tagField.Path }}
396-
desiredTags := ToACKTags(existingDesiredTags)
397-
latestTags := ToACKTags(existingLatestTags)
396+
desiredTags, desiredTagKeyOrder := toACKTagsWithKeyOrder(existingDesiredTags)
397+
latestTags, _ := toACKTagsWithKeyOrder(existingLatestTags)
398398
syncAWSTags(desiredTags, latestTags)
399399
{{ GoCodeInitializeNestedStructField .CRD "a.ko" $tagField "svcapitypes" 1 -}}
400-
a.ko.Spec.{{ $tagField.Path }} = FromACKTags(desiredTags)
400+
a.ko.Spec.{{ $tagField.Path }} = fromACKTagsWithKeyOrder(desiredTags, desiredTagKeyOrder)
401401
{{- end }}
402402
{{- end }}
403403
}

templates/pkg/resource/tags.go.tpl

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,41 @@ func ToACKTags(tags {{ $tagFieldGoType }}) acktags.Tags {
6262
return result
6363
}
6464

65+
// toACKTagsWithKeyOrder converts the tags parameter into 'acktags.Tags' shape.
66+
// This method helps in creating the hub(acktags.Tags) for merging
67+
// default controller tags with existing resource tags. It also returns a slice
68+
// of keys maintaining the original key Order when the tags are a list
69+
func toACKTagsWithKeyOrder(tags {{ $tagFieldGoType }}) (acktags.Tags, []string) {
70+
result := acktags.NewTags()
71+
keyOrder := []string{}
72+
{{- if $hookCode := Hook .CRD "pre_convert_to_ack_tags" }}
73+
{{ $hookCode }}
74+
{{ end }}
75+
if tags == nil || len(tags) == 0 {
76+
return result, keyOrder
77+
}
78+
{{ if eq "map" $tagFieldShapeType }}
79+
for k, v := range tags {
80+
if v == nil {
81+
result[k] = ""
82+
} else {
83+
result[k] = *v
84+
}
85+
}
86+
{{ else if eq "list" $tagFieldShapeType }}
87+
for _, t := range tags {
88+
if t.{{ $keyMemberName}} != nil {
89+
keyOrder = append(keyOrder, *t.{{ $keyMemberName}})
90+
}
91+
}
92+
result = ToACKTags(tags)
93+
{{ end }}
94+
{{- if $hookCode := Hook .CRD "post_convert_to_ack_tags" }}
95+
{{ $hookCode }}
96+
{{ end }}
97+
return result, keyOrder
98+
}
99+
65100
// FromACKTags converts the tags parameter into {{ $tagFieldGoType }} shape.
66101
// This method helps in setting the tags back inside AWSResource after merging
67102
// default controller tags with existing resource tags.
@@ -86,6 +121,43 @@ func FromACKTags(tags acktags.Tags) {{ $tagFieldGoType }} {
86121
{{ end }}
87122
return result
88123
}
124+
125+
// fromACKTagsWithTagKeys converts the tags parameter into {{ $tagFieldGoType }} shape.
126+
// This method helps in setting the tags back inside AWSResource after merging
127+
// default controller tags with existing resource tags. When a list,
128+
// it maintains the order from original
129+
func fromACKTagsWithKeyOrder(tags acktags.Tags, keyOrder []string) {{ $tagFieldGoType }} {
130+
result := {{ $tagFieldGoType }}{}
131+
{{- if $hookCode := Hook .CRD "pre_convert_from_ack_tags" }}
132+
{{ $hookCode }}
133+
{{ end }}
134+
135+
{{- if eq "list" $tagFieldShapeType }}
136+
for _, k := range keyOrder {
137+
v, ok := tags[k]
138+
if ok {
139+
tag := svcapitypes.Tag{Key: &k, Value: &v}
140+
result = append(result, &tag)
141+
delete(tags, k)
142+
}
143+
}
144+
145+
{{- else }}
146+
_ = keyOrder
147+
{{- end }}
148+
{{- if eq "map" $tagFieldShapeType }}
149+
for k, v := range tags {
150+
vCopy := v
151+
result[k] = &vCopy
152+
}
153+
{{- else if eq "list" $tagFieldShapeType }}
154+
result = append(result, FromACKTags(tags)...)
155+
{{- end }}
156+
{{- if $hookCode := Hook .CRD "post_convert_from_ack_tags" }}
157+
{{ $hookCode }}
158+
{{ end }}
159+
return result
160+
}
89161
{{ end }}
90162

91163
// ignoreSystemTags ignores tags that have keys that start with "aws:"

0 commit comments

Comments
 (0)