@@ -98,7 +98,7 @@ func ReferenceFieldsValidation(
9898 out += fmt .Sprintf ("%sif %s.%s != nil" +
9999 " && %s.%s != nil {\n " , fIndent , pathVarPrefix , field .GetReferenceFieldName ().Camel , pathVarPrefix , field .Names .Camel )
100100 out += fmt .Sprintf ("%s\t return " +
101- "ackerr.ResourceReferenceAndIDNotSupportedFor(\" %s \" , \" %s \" )\n " ,
101+ "ackerr.ResourceReferenceAndIDNotSupportedFor(%q, %q )\n " ,
102102 fIndent , field .Path , field .ReferenceFieldPath ())
103103
104104 // Close out all the curly braces with proper indentation
@@ -117,7 +117,7 @@ func ReferenceFieldsValidation(
117117 " %s.%s == nil {\n " , fIndent , pathVarPrefix ,
118118 field .ReferenceFieldPath (), pathVarPrefix , field .Path )
119119 out += fmt .Sprintf ("%s\t return " +
120- "ackerr.ResourceReferenceOrIDRequiredFor(\" %s \" , \" %s \" )\n " ,
120+ "ackerr.ResourceReferenceOrIDRequiredFor(%q, %q )\n " ,
121121 fIndent , field .Path , field .ReferenceFieldPath ())
122122 out += fmt .Sprintf ("%s}\n " , fIndent )
123123 }
@@ -185,6 +185,111 @@ func ReferenceFieldsPresent(
185185 return iteratorsOut + returnOut
186186}
187187
188+ // ResolveReferencesForField produces Go code for accessing all references that
189+ // are related to the given concrete field, determining whether its in a valid
190+ // condition and updating the concrete field with the referenced value.
191+ // Sample code (resolving a nested singular reference):
192+ //
193+ // ```
194+ //
195+ // if ko.Spec.JWTConfiguration != nil {
196+ // if ko.Spec.JWTConfiguration.IssuerRef != nil && ko.Spec.JWTConfiguration.IssuerRef.From != nil {
197+ // arr := ko.Spec.JWTConfiguration.IssuerRef.From
198+ // if arr == nil || arr.Name == nil || *arr.Name == "" {
199+ // return fmt.Errorf("provided resource reference is nil or empty: \"JWTConfiguration.IssuerRef"\")
200+ // }
201+ // obj := &svcapitypes.API{}
202+ // if err := getReferencedResourceState_API(ctx, apiReader, obj, *arr.Name, namespace); err != nil {
203+ // return err
204+ // }
205+ // ko.Spec.JWTConfiguration.Issuer = obj.Status.APIID
206+ // }
207+ // }
208+ //
209+ // ```
210+ func ResolveReferencesForField (field * model.Field , sourceVarName string , indentLevel int ) string {
211+ r := field .CRD
212+ fp := fieldpath .FromString (field .Path )
213+
214+ outPrefix := ""
215+ outSuffix := ""
216+
217+ fieldAccessPrefix := fmt .Sprintf ("%s%s" , sourceVarName , r .Config ().PrefixConfig .SpecField )
218+ targetVarName := fmt .Sprintf ("%s.%s" , fieldAccessPrefix , field .Path )
219+
220+ for idx := 0 ; idx < fp .Size (); idx ++ {
221+ curFP := fp .CopyAt (idx ).String ()
222+ cur , ok := r .Fields [curFP ]
223+ if ! ok {
224+ panic (fmt .Sprintf ("unable to find field with path %q. crd: %q" , curFP , r .Kind ))
225+ }
226+
227+ ref := cur .ShapeRef
228+
229+ indent := strings .Repeat ("\t " , indentLevel + idx )
230+
231+ switch ref .Shape .Type {
232+ case ("structure" ):
233+ fieldAccessPrefix = fmt .Sprintf ("%s.%s" , fieldAccessPrefix , fp .At (idx ))
234+
235+ outPrefix += fmt .Sprintf ("%sif %s != nil {\n " , indent , fieldAccessPrefix )
236+ outSuffix = fmt .Sprintf ("%s}\n %s" , indent , outSuffix )
237+ case ("list" ):
238+ if (fp .Size () - idx ) > 1 {
239+ // TODO(nithomso): add support for structs nested within lists
240+ // The logic for structs nested within lists needs to not only
241+ // be added here, but also in a custom patching solution since
242+ // it isn't supported by `StrategicMergePatch`
243+ // see https://github.com/aws-controllers-k8s/community/issues/1291
244+ panic (fmt .Errorf ("references within lists inside lists aren't supported. crd: %q, path: %q" , r .Kind , field .Path ))
245+ }
246+ fieldAccessPrefix = fmt .Sprintf ("%s.%s" , fieldAccessPrefix , fp .At (idx ))
247+
248+ iterVarName := fmt .Sprintf ("iter%d" , idx )
249+
250+ // base case for references in a list
251+ outPrefix += fmt .Sprintf ("%s%s = %s{}\n " , indent , targetVarName , field .GoType )
252+ outPrefix += fmt .Sprintf ("%sfor _, %s := range %s {\n " , indent , iterVarName , fieldAccessPrefix )
253+
254+ fieldAccessPrefix = iterVarName
255+ outPrefix += fmt .Sprintf ("%s\t arr := %s.From\n " , indent , fieldAccessPrefix )
256+ outPrefix += fmt .Sprintf ("%s\t if arr == nil || arr.Name == nil || *arr.Name == \" \" {\n " , indent )
257+ outPrefix += fmt .Sprintf ("%s\t \t return fmt.Errorf(\" provided resource reference is nil or empty: \\ %q\\ \" )\n " , indent , field .ReferenceFieldPath ())
258+ outPrefix += fmt .Sprintf ("%s\t }\n " , indent )
259+
260+ outPrefix += fmt .Sprintf ("%s\t if err := getReferencedResourceState_%s(ctx, apiReader, obj, *arr.Name, namespace); err != nil {\n " , indent , field .FieldConfig .References .Resource )
261+ outPrefix += fmt .Sprintf ("%s\t \t return err\n " , indent )
262+ outPrefix += fmt .Sprintf ("%s\t }\n " , indent )
263+ outPrefix += fmt .Sprintf ("%s\t %s = append(%s, obj.%s)\n " , indent , targetVarName , targetVarName , field .FieldConfig .References .Path )
264+ outPrefix += fmt .Sprintf ("%s}\n " , indent )
265+ case ("map" ):
266+ panic ("references cannot be within a map" )
267+ default :
268+ // base case for single references
269+ fieldAccessPrefix = fmt .Sprintf ("%s.%s" , fieldAccessPrefix , cur .GetReferenceFieldName ().Camel )
270+
271+ outPrefix += fmt .Sprintf ("%sif %s != nil && %s.From != nil {\n " , indent , fieldAccessPrefix , fieldAccessPrefix )
272+ outPrefix += fmt .Sprintf ("%s\t arr := %s.From\n " , indent , fieldAccessPrefix )
273+ outPrefix += fmt .Sprintf ("%s\t if arr == nil || arr.Name == nil || *arr.Name == \" \" {\n " , indent )
274+ outPrefix += fmt .Sprintf ("%s\t \t return fmt.Errorf(\" provided resource reference is nil or empty: \\ %q\\ \" )\n " , indent , field .ReferenceFieldPath ())
275+ outPrefix += fmt .Sprintf ("%s\t }\n " , indent )
276+
277+ if field .FieldConfig .References .ServiceName == "" {
278+ outPrefix += fmt .Sprintf ("%s\t obj := &svcapitypes.%s{}\n " , indent , field .FieldConfig .References .Resource )
279+ } else {
280+ outPrefix += fmt .Sprintf ("%s\t obj := &%sapitypes.%s{}\n " , indent , field .ReferencedServiceName (), field .FieldConfig .References .Resource )
281+ }
282+ outPrefix += fmt .Sprintf ("%s\t if err := getReferencedResourceState_%s(ctx, apiReader, obj, *arr.Name, namespace); err != nil {\n " , indent , field .FieldConfig .References .Resource )
283+ outPrefix += fmt .Sprintf ("%s\t \t return err\n " , indent )
284+ outPrefix += fmt .Sprintf ("%s\t }\n " , indent )
285+ outPrefix += fmt .Sprintf ("%s\t %s = obj.%s\n " , indent , targetVarName , field .FieldConfig .References .Path )
286+ outPrefix += fmt .Sprintf ("%s}\n " , indent )
287+ }
288+ }
289+
290+ return outPrefix + outSuffix
291+ }
292+
188293func nestedStructNilCheck (path fieldpath.Path , fieldAccessPrefix string ) string {
189294 out := ""
190295 fieldNamePrefix := ""
0 commit comments