From b41ced48d182f4458bff1de56b18d61bcddd4911 Mon Sep 17 00:00:00 2001 From: Gustavo Diaz Date: Wed, 2 Sep 2026 17:52:37 +0000 Subject: [PATCH 1/2] chore: regenerate references.go to show EnsureReferences output Demonstration only, not for merge. Shows what aws-controllers-k8s/code-generator#738 emits in the context of a full service controller. Regenerated with no other change, so the diff is exactly the generated EnsureReferences methods. go.mod is untouched: the method compiles against the current runtime and stays inert until aws-controllers-k8s/runtime#267 lands, which is what invokes it. lambda covers all three reference shapes, so the per-shape behaviour is visible in one controller: function struct-nested Code.S3BucketRef, VPCConfig.SecurityGroupRefs, VPCConfig.SubnetRefs -> emitted layer_version struct-nested emitted event_source_mapping list-nested -> nothing emitted alias, code_signing_config, function_url_config, version top-level only -> nothing emitted function is the shape reported in aws-controllers-k8s/community#2431. --- pkg/resource/function/references.go | 62 ++++++++++++++++++++++++ pkg/resource/layer_version/references.go | 42 ++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/pkg/resource/function/references.go b/pkg/resource/function/references.go index 4d292744..7240120c 100644 --- a/pkg/resource/function/references.go +++ b/pkg/resource/function/references.go @@ -94,6 +94,68 @@ func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) ack return &resource{ko} } +// EnsureReferences restores, onto a copy of `latest`, the cross-resource reference +// (*Ref) fields it is missing, taking them from `desired`. Only reference fields are +// written, so every concrete value on `latest` stands. +// +// A *Ref is a sibling of the concrete field it resolves into, so rebuilding the +// containing struct from an AWS API response drops it. That disables +// ClearResolvedReferences, which suppresses a resolved value only while the sibling +// *Ref is visible, so the spec patch would otherwise delete the declared *Ref and +// store the resolved value in its place. +// +// Only references reached through structs are restored, and each containing struct +// is created on `latest` when `desired` has it and `latest` does not -- generated +// set-output code nils a struct when the response omits it. A top-level *Ref needs +// no help, since generated set-output code overwrites only the concrete field. One +// reached through a list is not restored: it has no fixed address, and replacing the +// whole list would discard whatever the service populated inside it. +// +// Nothing is written unless `desired` actually holds the reference, so a source that +// declares none leaves `latest` untouched. +func (rm *resourceManager) EnsureReferences( + desired acktypes.AWSResource, + latest acktypes.AWSResource, +) acktypes.AWSResource { + // Deep copy the source as well, so a reference handed over below does not + // alias the caller's declared object. + desiredKO := rm.concreteResource(desired).ko.DeepCopy() + latestKO := rm.concreteResource(latest).ko.DeepCopy() + + if desiredKO.Spec.Code != nil { + if desiredKO.Spec.Code.S3BucketRef != nil { + if latestKO.Spec.Code == nil { + latestKO.Spec.Code = &svcapitypes.FunctionCode{} + } + if latestKO.Spec.Code.S3BucketRef == nil { + latestKO.Spec.Code.S3BucketRef = desiredKO.Spec.Code.S3BucketRef + } + } + } + if desiredKO.Spec.VPCConfig != nil { + if len(desiredKO.Spec.VPCConfig.SecurityGroupRefs) > 0 { + if latestKO.Spec.VPCConfig == nil { + latestKO.Spec.VPCConfig = &svcapitypes.VPCConfig{} + } + if len(latestKO.Spec.VPCConfig.SecurityGroupRefs) == 0 { + latestKO.Spec.VPCConfig.SecurityGroupRefs = desiredKO.Spec.VPCConfig.SecurityGroupRefs + } + } + } + if desiredKO.Spec.VPCConfig != nil { + if len(desiredKO.Spec.VPCConfig.SubnetRefs) > 0 { + if latestKO.Spec.VPCConfig == nil { + latestKO.Spec.VPCConfig = &svcapitypes.VPCConfig{} + } + if len(latestKO.Spec.VPCConfig.SubnetRefs) == 0 { + latestKO.Spec.VPCConfig.SubnetRefs = desiredKO.Spec.VPCConfig.SubnetRefs + } + } + } + + return &resource{latestKO} +} + // ResolveReferences finds if there are any Reference field(s) present // inside AWSResource passed in the parameter and attempts to resolve those // reference field(s) into their respective target field(s). It returns a diff --git a/pkg/resource/layer_version/references.go b/pkg/resource/layer_version/references.go index a3b10f59..f9b3c805 100644 --- a/pkg/resource/layer_version/references.go +++ b/pkg/resource/layer_version/references.go @@ -51,6 +51,48 @@ func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) ack return &resource{ko} } +// EnsureReferences restores, onto a copy of `latest`, the cross-resource reference +// (*Ref) fields it is missing, taking them from `desired`. Only reference fields are +// written, so every concrete value on `latest` stands. +// +// A *Ref is a sibling of the concrete field it resolves into, so rebuilding the +// containing struct from an AWS API response drops it. That disables +// ClearResolvedReferences, which suppresses a resolved value only while the sibling +// *Ref is visible, so the spec patch would otherwise delete the declared *Ref and +// store the resolved value in its place. +// +// Only references reached through structs are restored, and each containing struct +// is created on `latest` when `desired` has it and `latest` does not -- generated +// set-output code nils a struct when the response omits it. A top-level *Ref needs +// no help, since generated set-output code overwrites only the concrete field. One +// reached through a list is not restored: it has no fixed address, and replacing the +// whole list would discard whatever the service populated inside it. +// +// Nothing is written unless `desired` actually holds the reference, so a source that +// declares none leaves `latest` untouched. +func (rm *resourceManager) EnsureReferences( + desired acktypes.AWSResource, + latest acktypes.AWSResource, +) acktypes.AWSResource { + // Deep copy the source as well, so a reference handed over below does not + // alias the caller's declared object. + desiredKO := rm.concreteResource(desired).ko.DeepCopy() + latestKO := rm.concreteResource(latest).ko.DeepCopy() + + if desiredKO.Spec.Content != nil { + if desiredKO.Spec.Content.S3BucketRef != nil { + if latestKO.Spec.Content == nil { + latestKO.Spec.Content = &svcapitypes.LayerVersionContentInput{} + } + if latestKO.Spec.Content.S3BucketRef == nil { + latestKO.Spec.Content.S3BucketRef = desiredKO.Spec.Content.S3BucketRef + } + } + } + + return &resource{latestKO} +} + // ResolveReferences finds if there are any Reference field(s) present // inside AWSResource passed in the parameter and attempts to resolve those // reference field(s) into their respective target field(s). It returns a From 668bbf6fdb710aabec645b534ddb50ff6d75930e Mon Sep 17 00:00:00 2001 From: Gustavo Diaz Date: Wed, 16 Sep 2026 04:04:34 +0000 Subject: [PATCH 2/2] chore: regenerate references.go with the guard sharing from #738 code-generator#738 now emits a container's `!= nil` guard once however many references sit inside it, rather than restating the whole chain per reference. Function's VPCConfig holds two, so its duplicated guard collapses into one and the method goes from 46 lines to 40. Nothing else changes: the same two references are restored under the same conditions, and each container is still materialised inside the guard that establishes the declared resource holds a reference to put in it. LayerVersion is unchanged -- its references sit in distinct containers, so there is nothing to share. Regenerated from code-generator at 0d2d97e. The unrelated apis/ and helm/ churn that regeneration also produces is base drift between the v0.63.0 code-generator this controller was last generated with and current main -- a doc-comment list-marker difference, addressed by code-generator#737 and #742 -- so it is left out to keep this PR to the EnsureReferences output. Builds clean, gofmt-clean, `go test ./...` passes. --- pkg/resource/function/references.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/resource/function/references.go b/pkg/resource/function/references.go index 7240120c..3361968e 100644 --- a/pkg/resource/function/references.go +++ b/pkg/resource/function/references.go @@ -141,8 +141,6 @@ func (rm *resourceManager) EnsureReferences( latestKO.Spec.VPCConfig.SecurityGroupRefs = desiredKO.Spec.VPCConfig.SecurityGroupRefs } } - } - if desiredKO.Spec.VPCConfig != nil { if len(desiredKO.Spec.VPCConfig.SubnetRefs) > 0 { if latestKO.Spec.VPCConfig == nil { latestKO.Spec.VPCConfig = &svcapitypes.VPCConfig{}