Skip to content

Commit a8e7770

Browse files
author
Kumar Gaurav Sharma
committed
Extend ack-generate to generate slice with elements of type Kubernetes Secret
Related issue: aws-controllers-k8s/community#828 With this code change, when a field of type slice is configured as secret type inside Generator config, then the generated CRD yaml allows specifying multiple k8s secret values for that field in input yaml and generated sdk code supplies these values to the resource API input field as slice type.
1 parent cac5654 commit a8e7770

File tree

6 files changed

+154
-64
lines changed

6 files changed

+154
-64
lines changed

pkg/generate/code/set_sdk.go

Lines changed: 89 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -236,17 +236,6 @@ func SetSDK(
236236
sourceAdaptedVarName += "." + f.Names.Camel
237237
sourceFieldPath := f.Names.Camel
238238

239-
if r.IsSecretField(memberName) {
240-
out += setSDKForSecret(
241-
cfg, r,
242-
memberName,
243-
targetVarName,
244-
sourceAdaptedVarName,
245-
indentLevel,
246-
)
247-
continue
248-
}
249-
250239
memberShapeRef, _ := inputShape.MemberRefs[memberName]
251240
memberShape := memberShapeRef.Shape
252241

@@ -339,16 +328,26 @@ func SetSDK(
339328
)
340329
}
341330
default:
342-
out += setSDKForScalar(
343-
cfg, r,
344-
memberName,
345-
targetVarName,
346-
inputShape.Type,
347-
sourceFieldPath,
348-
sourceAdaptedVarName,
349-
memberShapeRef,
350-
indentLevel+1,
351-
)
331+
if r.IsSecretField(memberName) {
332+
out += setSDKForSecret(
333+
cfg, r,
334+
memberName,
335+
targetVarName,
336+
sourceAdaptedVarName,
337+
indentLevel,
338+
)
339+
} else {
340+
out += setSDKForScalar(
341+
cfg, r,
342+
memberName,
343+
targetVarName,
344+
inputShape.Type,
345+
sourceFieldPath,
346+
sourceAdaptedVarName,
347+
memberShapeRef,
348+
indentLevel+1,
349+
)
350+
}
352351
}
353352
out += fmt.Sprintf(
354353
"%s}\n", indent,
@@ -770,6 +769,25 @@ func setSDKForContainer(
770769
indentLevel,
771770
)
772771
default:
772+
if r.IsSecretField(sourceFieldPath) {
773+
indent := strings.Repeat("\t", indentLevel)
774+
// if ko.Spec.MasterUserPassword != nil {
775+
out := fmt.Sprintf(
776+
"%sif %s != nil {\n",
777+
indent, sourceVarName,
778+
)
779+
out += setSDKForSecret(
780+
cfg, r,
781+
"",
782+
targetVarName,
783+
sourceVarName,
784+
indentLevel,
785+
)
786+
// }
787+
out += fmt.Sprintf("%s}\n", indent)
788+
return out
789+
}
790+
773791
return setSDKForScalar(
774792
cfg, r,
775793
targetFieldName,
@@ -789,15 +807,27 @@ func setSDKForContainer(
789807
//
790808
// The Go code output from this function looks like this:
791809
//
792-
// if ko.Spec.MasterUserPassword != nil {
793810
// tmpSecret, err := rm.rr.SecretValueFromReference(ctx, ko.Spec.MasterUserPassword)
794811
// if err != nil {
795812
// return nil, err
796813
// }
797814
// if tmpSecret != "" {
798815
// res.SetMasterUserPassword(tmpSecret)
799816
// }
800-
// }
817+
//
818+
// or:
819+
//
820+
// tmpSecret, err := rm.rr.SecretValueFromReference(ctx, f3iter)
821+
// if err != nil {
822+
// return nil, err
823+
// }
824+
// if tmpSecret != "" {
825+
// f3elem = tmpSecret
826+
// }
827+
//
828+
// The second case is used when the SecretKeyReference field
829+
// is a slice of `[]*string` in the original AWS API Input shape.
830+
801831
func setSDKForSecret(
802832
cfg *ackgenconfig.Config,
803833
r *model.CRD,
@@ -809,15 +839,11 @@ func setSDKForSecret(
809839
sourceVarName string,
810840
indentLevel int,
811841
) string {
842+
812843
out := ""
813844
indent := strings.Repeat("\t", indentLevel)
814845
secVar := "tmpSecret"
815846

816-
// if ko.Spec.MasterUserPassword != nil {
817-
out += fmt.Sprintf(
818-
"%sif %s != nil {\n",
819-
indent, sourceVarName,
820-
)
821847
// tmpSecret, err := rm.rr.SecretValueFromReference(ctx, ko.Spec.MasterUserPassword)
822848
out += fmt.Sprintf(
823849
"%s\t%s, err := rm.rr.SecretValueFromReference(ctx, %s)\n",
@@ -833,13 +859,18 @@ func setSDKForSecret(
833859
// res.SetMasterUserPassword(tmpSecret)
834860
// }
835861
out += fmt.Sprintf("%s\tif tmpSecret != \"\" {\n", indent)
836-
out += fmt.Sprintf(
837-
"%s\t\t%s.Set%s(%s)\n",
838-
indent, targetVarName, targetFieldName, secVar,
839-
)
862+
if targetFieldName == "" {
863+
out += fmt.Sprintf(
864+
"%s\t\t%s = %s\n",
865+
indent, targetVarName, secVar,
866+
)
867+
} else {
868+
out += fmt.Sprintf(
869+
"%s\t\t%s.Set%s(%s)\n",
870+
indent, targetVarName, targetFieldName, secVar,
871+
)
872+
}
840873
out += fmt.Sprintf("%s\t}\n", indent)
841-
// }
842-
out += fmt.Sprintf("%s}\n", indent)
843874
return out
844875
}
845876

@@ -871,16 +902,7 @@ func setSDKForStruct(
871902
cleanMemberName := cleanMemberNames.Camel
872903
sourceAdaptedVarName := sourceVarName + "." + cleanMemberName
873904
memberFieldPath := sourceFieldPath + "." + cleanMemberName
874-
if r.IsSecretField(memberFieldPath) {
875-
out += setSDKForSecret(
876-
cfg, r,
877-
memberName,
878-
targetVarName,
879-
sourceAdaptedVarName,
880-
indentLevel,
881-
)
882-
continue
883-
}
905+
884906
out += fmt.Sprintf(
885907
"%sif %s != nil {\n", indent, sourceAdaptedVarName,
886908
)
@@ -918,16 +940,26 @@ func setSDKForStruct(
918940
)
919941
}
920942
default:
921-
out += setSDKForScalar(
922-
cfg, r,
923-
memberName,
924-
targetVarName,
925-
targetShape.Type,
926-
memberFieldPath,
927-
sourceAdaptedVarName,
928-
memberShapeRef,
929-
indentLevel+1,
930-
)
943+
if r.IsSecretField(memberFieldPath) {
944+
out += setSDKForSecret(
945+
cfg, r,
946+
memberName,
947+
targetVarName,
948+
sourceAdaptedVarName,
949+
indentLevel,
950+
)
951+
} else {
952+
out += setSDKForScalar(
953+
cfg, r,
954+
memberName,
955+
targetVarName,
956+
targetShape.Type,
957+
memberFieldPath,
958+
sourceAdaptedVarName,
959+
memberShapeRef,
960+
indentLevel+1,
961+
)
962+
}
931963
}
932964
out += fmt.Sprintf(
933965
"%s}\n", indent,
@@ -974,14 +1006,16 @@ func setSDKForSlice(
9741006
//
9751007
// f0elem.SetMyField(*f0iter)
9761008
containerFieldName := ""
1009+
sourceAttributePath := sourceFieldPath
9771010
if targetShape.MemberRef.Shape.Type == "structure" {
9781011
containerFieldName = targetFieldName
1012+
sourceAttributePath = sourceFieldPath+"."
9791013
}
9801014
out += setSDKForContainer(
9811015
cfg, r,
9821016
containerFieldName,
9831017
elemVarName,
984-
sourceFieldPath+".",
1018+
sourceAttributePath,
9851019
iterVarName,
9861020
&targetShape.MemberRef,
9871021
indentLevel+1,

pkg/generate/code/set_sdk_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,49 @@ func TestSetSDK_Elasticache_ReplicationGroup_Update_Override_Values(t *testing.T
11091109
)
11101110
}
11111111

1112+
func TestSetSDK_Elasticache_User_Create_Override_Values(t *testing.T) {
1113+
assert := assert.New(t)
1114+
require := require.New(t)
1115+
1116+
g := testutil.NewGeneratorForService(t, "elasticache")
1117+
1118+
crd := testutil.GetCRDByName(t, g, "User")
1119+
require.NotNil(crd)
1120+
1121+
expected := `
1122+
if r.ko.Spec.AccessString != nil {
1123+
res.SetAccessString(*r.ko.Spec.AccessString)
1124+
}
1125+
if r.ko.Spec.NoPasswordRequired != nil {
1126+
res.SetNoPasswordRequired(*r.ko.Spec.NoPasswordRequired)
1127+
}
1128+
if r.ko.Spec.Passwords != nil {
1129+
f3 := []*string{}
1130+
for _, f3iter := range r.ko.Spec.Passwords {
1131+
var f3elem string
1132+
if f3iter != nil {
1133+
tmpSecret, err := rm.rr.SecretValueFromReference(ctx, f3iter)
1134+
if err != nil {
1135+
return nil, err
1136+
}
1137+
if tmpSecret != "" {
1138+
f3elem = tmpSecret
1139+
}
1140+
}
1141+
f3 = append(f3, &f3elem)
1142+
}
1143+
res.SetPasswords(f3)
1144+
}
1145+
if r.ko.Spec.UserID != nil {
1146+
res.SetUserId(*r.ko.Spec.UserID)
1147+
}
1148+
`
1149+
assert.Equal(
1150+
expected,
1151+
code.SetSDK(crd.Config(), crd, model.OpTypeUpdate, "r.ko", "res", 1),
1152+
)
1153+
}
1154+
11121155
func TestSetSDK_RDS_DBInstance_Create(t *testing.T) {
11131156
assert := assert.New(t)
11141157
require := require.New(t)

pkg/generate/elasticache_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ func TestElasticache_ValidateAuthTokenIsSecret(t *testing.T) {
274274

275275
assert := assert.New(t)
276276
assert.Equal("*ackv1alpha1.SecretKeyReference", crd.SpecFields["AuthToken"].GoType)
277-
assert.Equal("ackv1alpha1.SecretKeyReference", crd.SpecFields["AuthToken"].GoTypeElem)
277+
assert.Equal("SecretKeyReference", crd.SpecFields["AuthToken"].GoTypeElem)
278278
assert.Equal("*ackv1alpha1.SecretKeyReference", crd.SpecFields["AuthToken"].GoTypeWithPkgName)
279+
280+
crd = getCRDByName("User", crds)
281+
require.NotNil(crd)
282+
283+
assert.Equal("[]*ackv1alpha1.SecretKeyReference", crd.SpecFields["Passwords"].GoType)
284+
assert.Equal("SecretKeyReference", crd.SpecFields["Passwords"].GoTypeElem)
285+
assert.Equal("[]*ackv1alpha1.SecretKeyReference", crd.SpecFields["Passwords"].GoTypeWithPkgName)
279286
}

pkg/generate/testdata/models/apis/elasticache/0000-00-00/generator.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ resources:
1818
from:
1919
operation: DescribeEvents
2020
path: Events
21+
User:
22+
fields:
23+
Passwords:
24+
is_secret: true
2125
ReplicationGroup:
2226
update_conditions_custom_method_name: CustomUpdateConditions
2327
exceptions:
@@ -126,7 +130,6 @@ ignore:
126130
- GlobalReplicationGroup
127131
- CacheCluster
128132
- CacheSecurityGroup
129-
- User
130133
- UserGroup
131134
field_paths:
132135
- DescribeSnapshotsInput.CacheClusterId

pkg/model/field.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,8 @@ func NewField(
9595
shape = shapeRef.Shape
9696
}
9797

98-
if cfg != nil && cfg.IsSecret {
99-
gt = "*ackv1alpha1.SecretKeyReference"
100-
gte = "ackv1alpha1.SecretKeyReference"
101-
gtwp = "*ackv1alpha1.SecretKeyReference"
102-
} else if shape != nil {
103-
gte, gt, gtwp = cleanGoType(crd.sdkAPI, crd.cfg, shape)
98+
if shape != nil {
99+
gte, gt, gtwp = cleanGoType(crd.sdkAPI, crd.cfg, shape, cfg)
104100
} else {
105101
gte = "string"
106102
gt = "*string"

pkg/model/types.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func cleanGoType(
2929
api *SDKAPI,
3030
cfg *ackgenconfig.Config,
3131
shape *awssdkmodel.Shape,
32+
fieldCfg *ackgenconfig.FieldConfig,
3233
) (string, string, string) {
3334
// There are shapes that are called things like DBProxyStatus that are
3435
// fields in a DBProxy CRD... we need to ensure the type names don't
@@ -48,20 +49,26 @@ func cleanGoType(
4849
} else if shape.Type == "list" {
4950
// If it's a list type, where the element is a structure, we need to
5051
// set the GoType to the cleaned-up Camel-cased name
51-
mgte, mgt, _ := cleanGoType(api, cfg, shape.MemberRef.Shape)
52+
mgte, mgt, mgtwp := cleanGoType(api, cfg, shape.MemberRef.Shape, fieldCfg)
5253
cleanNames := names.New(mgte)
5354
gte = cleanNames.Camel
5455
if api.HasConflictingTypeName(mgte, cfg) {
5556
gte += "_SDK"
5657
}
5758

5859
gt = "[]" + mgt
60+
gtwp = "[]" + mgtwp
5961
} else if shape.Type == "timestamp" {
6062
// time.Time needs to be converted to apimachinery/metav1.Time
6163
// otherwise there is no DeepCopy support
6264
gtwp = "*metav1.Time"
6365
gte = "metav1.Time"
6466
gt = "*metav1.Time"
67+
} else if fieldCfg != nil && fieldCfg.IsSecret {
68+
gt = "*ackv1alpha1.SecretKeyReference"
69+
gte = "SecretKeyReference"
70+
gtwp = "*ackv1alpha1.SecretKeyReference"
71+
return gte, gt, gtwp
6572
}
6673

6774
// Replace the type part of the full type-with-package-name with the

0 commit comments

Comments
 (0)