Skip to content
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
6 changes: 6 additions & 0 deletions pkg/generate/ack/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@ var (
"GoCodeClearResolvedReferences": func(f *ackmodel.Field, targetVarName string, indentLevel int) string {
return code.ClearResolvedReferencesForField(f, targetVarName, indentLevel)
},
"GoCodeConvertToACKTags": func(r *ackmodel.CRD, sourceVarName string, targetVarName string, keyOrderVarName string, indentLevel int) string {
return code.GoCodeConvertToACKTags(r, sourceVarName, targetVarName, keyOrderVarName, indentLevel)
},
"GoCodeFromACKTags": func(r *ackmodel.CRD, sourceVarName string, orderVarName string, targetVarName string, indentLevel int) string {
return code.GoCodeFromACKTags(r, sourceVarName, orderVarName, targetVarName, indentLevel)
},
}
)

Expand Down
12 changes: 8 additions & 4 deletions pkg/generate/code/compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,11 @@ func compareSlice(
//
// Output code will look something like this:
//
// if !ackcompare.MapStringStringEqual(ToACKTags(a.ko.Spec.Tags), ToACKTags(b.ko.Spec.Tags)) {
// delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags)
// }
// desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags)
// latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags)
// if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) {
// delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags)
// }
func compareTags(
// String representing the name of the variable that is of type
// `*ackcompare.Delta`. We will generate Go code that calls the `Add()`
Expand All @@ -549,7 +551,9 @@ func compareTags(
out := ""
indent := strings.Repeat("\t", indentLevel)

out += fmt.Sprintf("%sif !ackcompare.MapStringStringEqual(ToACKTags(%s), ToACKTags(%s)) {\n", indent, firstResVarName, secondResVarName)
out += fmt.Sprintf("%sdesiredACKTags, _ := convertToOrderedACKTags(%s)\n", indent, firstResVarName)
out += fmt.Sprintf("%slatestACKTags, _ := convertToOrderedACKTags(%s)\n", indent, secondResVarName)
out += fmt.Sprintf("%sif !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) {\n", indent)
out += fmt.Sprintf("%s\t%s.Add(\"%s\", %s, %s)\n", indent, deltaVarName, fieldPath, firstResVarName, secondResVarName)
out += fmt.Sprintf("%s}\n", indent)

Expand Down
16 changes: 12 additions & 4 deletions pkg/generate/code/compare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ func TestCompareResource_S3_Bucket(t *testing.T) {
if ackcompare.HasNilDifference(a.ko.Spec.Tagging, b.ko.Spec.Tagging) {
delta.Add("Spec.Tagging", a.ko.Spec.Tagging, b.ko.Spec.Tagging)
} else if a.ko.Spec.Tagging != nil && b.ko.Spec.Tagging != nil {
if !ackcompare.MapStringStringEqual(ToACKTags(a.ko.Spec.Tagging.TagSet), ToACKTags(b.ko.Spec.Tagging.TagSet)) {
desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tagging.TagSet)
latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tagging.TagSet)
if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) {
delta.Add("Spec.Tagging", a.ko.Spec.Tagging.TagSet, b.ko.Spec.Tagging.TagSet)
}
}
Expand Down Expand Up @@ -364,7 +366,9 @@ func TestCompareResource_Lambda_Function(t *testing.T) {
delta.Add("Spec.Runtime", a.ko.Spec.Runtime, b.ko.Spec.Runtime)
}
}
if !ackcompare.MapStringStringEqual(ToACKTags(a.ko.Spec.Tags), ToACKTags(b.ko.Spec.Tags)) {
desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags)
latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags)
if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) {
delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags)
}
if ackcompare.HasNilDifference(a.ko.Spec.Timeout, b.ko.Spec.Timeout) {
Expand Down Expand Up @@ -533,7 +537,9 @@ func TestCompareResource_IAM_OIDC_URL(t *testing.T) {
delta.Add("Spec.ClientIDList", a.ko.Spec.ClientIDList, b.ko.Spec.ClientIDList)
}
}
if !ackcompare.MapStringStringEqual(ToACKTags(a.ko.Spec.Tags), ToACKTags(b.ko.Spec.Tags)) {
desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags)
latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags)
if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) {
delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags)
}
if len(a.ko.Spec.ThumbprintList) != len(b.ko.Spec.ThumbprintList) {
Expand Down Expand Up @@ -586,7 +592,9 @@ func TestCompareResource_MemoryDB_User(t *testing.T) {
delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name)
}
}
if !ackcompare.MapStringStringEqual(ToACKTags(a.ko.Spec.Tags), ToACKTags(b.ko.Spec.Tags)) {
desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags)
latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags)
if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) {
delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags)
}
`
Expand Down
157 changes: 157 additions & 0 deletions pkg/generate/code/tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package code

import (
"fmt"
"strings"

"github.com/aws-controllers-k8s/code-generator/pkg/model"
)

// GoCodeToACKTags returns Go code that converts Resource Tags
// to ACK Tags. If Resource Tags field is of type list, we
// also maintain and return the order of the list as a []string
//
//
//
// Sample output:
//
// for _, k := range keyOrder {
// v, ok := tags[k]
// if ok {
// tag := svcapitypes.Tag{Key: &k, Value: &v}
// result = append(result, &tag)
// delete(tags, k)
// }
// }
// for k, v := range tags {
// tag := svcapitypes.Tag{Key: &k, Value: &v}
// result = append(result, &tag)
// }
func GoCodeConvertToACKTags(r *model.CRD, sourceVarName string, targetVarName string, keyOrderVarName string, indentLevel int) string {

out := "\n"
indent := strings.Repeat("\t", indentLevel)
tagField, err := r.GetTagField()
if err != nil {
panic("error: resource does not have tags. ignore in generator.yaml")
}

if tagField == nil {
return ""
}

tagFieldShapeType := tagField.ShapeRef.Shape.Type
keyMemberName := r.GetTagKeyMemberName()
valueMemberName := r.GetTagValueMemberName()

out += fmt.Sprintf("%sif len(%s) == 0 {\n", indent, sourceVarName)
out += fmt.Sprintf("%s\treturn %s, %s\n", indent, targetVarName, keyOrderVarName)
out += fmt.Sprintf("%s}\n", indent)

switch tagFieldShapeType {
case "list":
out += fmt.Sprintf("%sfor _, t := range %s {\n", indent, sourceVarName)
out += fmt.Sprintf("%s\tif t.%s != nil {\n", indent, keyMemberName)
out += fmt.Sprintf("%s\t\t%s = append(%s, *t.%s)\n", indent, keyOrderVarName, keyOrderVarName, keyMemberName)
out += fmt.Sprintf("%s\t\tif t.%s != nil {\n", indent, valueMemberName)
out += fmt.Sprintf("%s\t\t\t%s[*t.%s] = *t.%s\n", indent, targetVarName, keyMemberName, valueMemberName)
out += fmt.Sprintf("%s\t\t} else {\n", indent)
out += fmt.Sprintf("%s\t\t\t%s[*t.%s] = \"\"\n", indent, targetVarName, keyMemberName)
out += fmt.Sprintf("%s\t\t}\n", indent)
out += fmt.Sprintf("%s\t}\n", indent)
out += fmt.Sprintf("%s}\n", indent)

case "map":
out += fmt.Sprintf("%sfor k, v := range %s {\n", indent, sourceVarName)
out += fmt.Sprintf("%s\tif v == nil {\n", indent)
out += fmt.Sprintf("%s\t\t%s[k] = \"\"\n", indent, targetVarName)
out += fmt.Sprintf("%s\t} else {\n", indent)
out += fmt.Sprintf("%s\t\t%s[k] = *v\n", indent, targetVarName)
out += fmt.Sprintf("%s\t}\n", indent)
out += fmt.Sprintf("%s}\n", indent)
default:
msg := "error: tag type can only be a list or a map"
panic(msg)
}

return out
}

// GoCodeFromACKTags returns Go code that converts ACKTags
// to the Resource Tag shape type. Tag fields can only be
// maps or lists of Tag Go type. If Tag field is a list,
// when converting from ACK Tags, we try to preserve the
// original order
//
//
//
// Sample output:
//
// for _, k := range keyOrder {
// v, ok := tags[k]
// if ok {
// tag := svcapitypes.Tag{Key: &k, Value: &v}
// result = append(result, &tag)
// delete(tags, k)
// }
// }
// for k, v := range tags {
// tag := svcapitypes.Tag{Key: &k, Value: &v}
// result = append(result, &tag)
// }
func GoCodeFromACKTags(r *model.CRD, tagsSourceVarName string, orderVarName string, targetVarName string, indentLevel int) string {
out := "\n"
indent := strings.Repeat("\t", indentLevel)
tagField, _ := r.GetTagField()

if tagField == nil {
return ""
}

tagFieldShapeType := tagField.ShapeRef.Shape.Type
tagFieldGoType := tagField.GoTypeElem
keyMemberName := r.GetTagKeyMemberName()
valueMemberName := r.GetTagValueMemberName()

switch tagFieldShapeType {
case "list":
out += fmt.Sprintf("%sfor _, k := range %s {\n", indent, orderVarName)
out += fmt.Sprintf("%s\tv, ok := %s[k]\n", indent, tagsSourceVarName)
out += fmt.Sprintf("%s\tif ok {\n", indent)
out += fmt.Sprintf("%s\t\ttag := svcapitypes.%s{%s: &k, %s: &v}\n", indent, tagFieldGoType, keyMemberName, valueMemberName)
out += fmt.Sprintf("%s\t\t%s = append(%s, &tag)\n", indent, targetVarName, targetVarName)
out += fmt.Sprintf("%s\t\tdelete(%s, k)\n", indent, tagsSourceVarName)
out += fmt.Sprintf("%s\t}\n", indent)
out += fmt.Sprintf("%s}\n", indent)
case "map":
out += fmt.Sprintf("%s_ = %s\n", indent, orderVarName)
default:
msg := "error: tag type can only be a list of a map"
panic(msg)
}

out += fmt.Sprintf("%sfor k, v := range %s {\n", indent, tagsSourceVarName)
switch tagFieldShapeType {
case "list":
out += fmt.Sprintf("%s\ttag := svcapitypes.%s{%s: &k, %s: &v}\n", indent, tagFieldGoType, keyMemberName, valueMemberName)
out += fmt.Sprintf("%s\t%s = append(%s, &tag)\n", indent, targetVarName, targetVarName)
case "map":
out += fmt.Sprintf("%s\t%s[k] = &v\n", indent, targetVarName)
}
out += fmt.Sprintf("%s}\n", indent)

return out
}
139 changes: 139 additions & 0 deletions pkg/generate/code/tags_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package code_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/aws-controllers-k8s/code-generator/pkg/generate/code"
"github.com/aws-controllers-k8s/code-generator/pkg/testutil"
)

func TestToACKTagsForListShape(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

g := testutil.NewModelForService(t, "ec2")

crd := testutil.GetCRDByName(t, g, "Vpc")
require.NotNil(crd)

expectedSyncedConditions := `
if len(tags) == 0 {
return result, keyOrder
}
for _, t := range tags {
if t.Key != nil {
keyOrder = append(keyOrder, *t.Key)
if t.Value != nil {
result[*t.Key] = *t.Value
} else {
result[*t.Key] = ""
}
}
}
`
assert.Equal(
expectedSyncedConditions,
code.GoCodeConvertToACKTags(
crd, "tags", "result", "keyOrder", 1,
),
)
}

func TestToACKTagsForMapShape(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

g := testutil.NewModelForService(t, "apigatewayv2")

crd := testutil.GetCRDByName(t, g, "Api")
require.NotNil(crd)

expectedSyncedConditions := `
if len(tags) == 0 {
return result, keyOrder
}
for k, v := range tags {
if v == nil {
result[k] = ""
} else {
result[k] = *v
}
}
`
assert.Equal(
expectedSyncedConditions,
code.GoCodeConvertToACKTags(
crd, "tags", "result", "keyOrder", 1,
),
)
}

func TestFromACKTagsForListShape(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

g := testutil.NewModelForService(t, "ec2")

crd := testutil.GetCRDByName(t, g, "Vpc")
require.NotNil(crd)

expectedSyncedConditions := `
for _, k := range keyOrder {
v, ok := tags[k]
if ok {
tag := svcapitypes.Tag{Key: &k, Value: &v}
result = append(result, &tag)
delete(tags, k)
}
}
for k, v := range tags {
tag := svcapitypes.Tag{Key: &k, Value: &v}
result = append(result, &tag)
}
`
assert.Equal(
expectedSyncedConditions,
code.GoCodeFromACKTags(
crd, "tags", "keyOrder", "result", 1,
),
)
}

func TestFromACKTagsForMapShape(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

g := testutil.NewModelForService(t, "apigatewayv2")

crd := testutil.GetCRDByName(t, g, "Api")
require.NotNil(crd)

expectedSyncedConditions := `
_ = keyOrder
for k, v := range tags {
result[k] = &v
}
`
assert.Equal(
expectedSyncedConditions,
code.GoCodeFromACKTags(
crd, "tags", "keyOrder", "result", 1,
),
)
}
Loading