Skip to content

Commit 30bd8a4

Browse files
jukiedxbjavidzirainarkodgvishwas-bm
authored
[release-1.8] V1.8.3 cherry picks (#9540)
* detect ipv6 literal hosts in url2cluster and token endpoint check (#9165) * detect ipv6 literal hosts in url2cluster and token endpoint check Signed-off-by: dxbjavid <dxbjavid@gmail.com> * add release note for ipv6 literal endpoint fix Signed-off-by: dxbjavid <dxbjavid@gmail.com> --------- Signed-off-by: dxbjavid <dxbjavid@gmail.com> Signed-off-by: zirain <zirain2009@gmail.com> Signed-off-by: Javid Khan <dxbjavid@gmail.com> Co-authored-by: zirain <zirain2009@gmail.com> (cherry picked from commit 30d456e) Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> * Revert LuaPerRoute source materialization for Lua (#9426) * Revert "[xds] stabilize listener-level Lua XDS filters to avoid listener drain (#8598)" This reverts commit 80b2762. Why: - Back out the LuaPerRoute stabilization layer together with #8355 while investigating the Gateway-scoped Lua memory regression from #9355. - #8598 only stabilizes per-route Lua HCM slot names; it still leaves Lua source materialized per route, so it is not sufficient for the memory issue. Test plan: - `go test ./internal/xds/translator` Signed-off-by: Arko Dasgupta <arkodg@gmail.com> * Revert "refactor/perf: use LuaPerRoute instead of FilterConfig (#8355)" This reverts commit f31ac4e. Why: - #8355 materialized Gateway-targeted Lua as per-route LuaPerRoute source code. - With large route tables, identical Gateway-scoped scripts are duplicated across route entries and worker Lua runtime state, matching the memory regression reported in #9355. - Restoring listener-level Lua source avoids scaling the Gateway-scoped script with route count. Test plan: - `go test ./internal/xds/translator` Fixes #9355 Signed-off-by: Arko Dasgupta <arkodg@gmail.com> * add filterContext in per route level Signed-off-by: Arko Dasgupta <arkodg@gmail.com> * [xds] scope Lua revert to translator changes Remove unrelated Gateway API status-merge and redirect regression files that were accidentally included with the filterContext follow-up. Add a breaking-change fragment documenting the listener-level Lua source layout and filter-key migration for EnvoyPatchPolicy and extension consumers. Test: make test Signed-off-by: Arko Dasgupta <arkodg@gmail.com> --------- Signed-off-by: Arko Dasgupta <arkodg@gmail.com> (cherry picked from commit 76bd888) Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> * fix: default backend TLS max version to 1.3 (#9412) Backend (upstream) TLS connections were silently capped at TLS 1.2. Apply the defaults (min 1.2, max 1.3) in applyBackendTLSSetting when not configured. Fixes #9395 Signed-off-by: vishwas-bm <b_m.vishwas@nokia.com> (cherry picked from commit 581a9c5) Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> * fix: add default retry policy for Envoy wasm module fetch (#9462) add default retry policy for Envoy wasm module fetch Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> (cherry picked from commit 3e18557) Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> * fix/refactor: deep copy status in translator for all resources (#9458) Signed-off-by: Rudrakh Panigrahi <rudrakh97@gmail.com> Co-authored-by: zirain <zirain2009@gmail.com> (cherry picked from commit e51b417) Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> * fix(logs): restore ISO 8601 timestamp format (#9493) * fix(logs): restore ISO 8601 timestamp format Signed-off-by: Florian Wiegand <florian.wiegand@sap.com> * fix(logs): add release note for ISO 8601 timestamp fix Signed-off-by: Florian Wiegand <florian.wiegand@sap.com> --------- Signed-off-by: Florian Wiegand <florian.wiegand@sap.com> (cherry picked from commit 2621405) Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> * fix: unreferenced Secret events trigger reconciliation when HTTPRouteFilter CRD exists (#9488) * fix: unreferenced Secret events trigger reconciliation when HTTPRouteFilter CRD exists isHTTPRouteFilterReferencingSecret returned true on both branches, so with the HTTPRouteFilter CRD installed (the default), every Secret write in the cluster passed validateSecretForReconcile and enqueued a full reconcile. Any high-frequency Secret writer (secret sync controllers, cert rotation) drives the controller to reconcile continuously. Return false when no HTTPRouteFilter references the Secret, matching the other is*ReferencingSecret helpers. Enable hrfCRDExists in the predicate test so the existing unreferenced-Secret case guards this path, and add positive/negative cases for HTTPRouteFilter credential injection refs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: James Hong <james.hong@zapier.com> (cherry picked from commit 4d7686c) Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --------- Signed-off-by: dxbjavid <dxbjavid@gmail.com> Signed-off-by: zirain <zirain2009@gmail.com> Signed-off-by: Javid Khan <dxbjavid@gmail.com> Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> Signed-off-by: Arko Dasgupta <arkodg@gmail.com> Signed-off-by: vishwas-bm <b_m.vishwas@nokia.com> Signed-off-by: Rudrakh Panigrahi <rudrakh97@gmail.com> Signed-off-by: Florian Wiegand <florian.wiegand@sap.com> Signed-off-by: James Hong <james.hong@zapier.com> Co-authored-by: Javid Khan <dxbjavid@gmail.com> Co-authored-by: zirain <zirain2009@gmail.com> Co-authored-by: Arko Dasgupta <arkodg@users.noreply.github.com> Co-authored-by: vishwas-bm <b_m.vishwas@nokia.com> Co-authored-by: Rudrakh Panigrahi <rudrakh97@gmail.com> Co-authored-by: Florian Wiegand <36593900+wiegandf@users.noreply.github.com> Co-authored-by: James Hong <greyeye@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 30e30aa commit 30bd8a4

70 files changed

Lines changed: 467 additions & 284 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

internal/gatewayapi/backend.go

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ import (
2020
)
2121

2222
func (t *Translator) ProcessBackends(backends []*egv1a1.Backend, backendTLSPolicies []*gwapiv1.BackendTLSPolicy) []*egv1a1.Backend {
23-
backendCopies := backendCopiesWithStatusDeepCopy(backends)
2423
res := make([]*egv1a1.Backend, 0, len(backends))
25-
for i := range backends {
26-
backend := backendCopies[i]
24+
for _, backend := range backends {
2725
// Ensure Backends are enabled
2826
if !t.BackendEnabled {
2927
status.UpdateBackendStatusAcceptedCondition(backend, false,
@@ -205,15 +203,3 @@ func validateIP(epIP *egv1a1.IPEndpoint, runningOnHost bool) status.Error {
205203
}
206204
return nil
207205
}
208-
209-
// backendCopiesWithStatusDeepCopy returns shallow copies with deep-copied Status fields.
210-
// Status is mutated during translation and shares a pointer with the watchable coalesce goroutine.
211-
func backendCopiesWithStatusDeepCopy(backends []*egv1a1.Backend) []*egv1a1.Backend {
212-
copies := make([]*egv1a1.Backend, len(backends))
213-
for i, b := range backends {
214-
out := *b
215-
b.Status.DeepCopyInto(&out.Status)
216-
copies[i] = &out
217-
}
218-
return copies
219-
}

internal/gatewayapi/backendtlspolicy.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,15 @@ func (t *Translator) applyBackendTLSSetting(
158158
mergedTLSConfig.TLSConfig = *mergedClientTLSConfig
159159
}
160160

161+
// Set to the default TLS protocol versions (min 1.2, max 1.3) when
162+
// not explicitly configured.
163+
if mergedTLSConfig.MinVersion == nil {
164+
mergedTLSConfig.MinVersion = new(ir.TLSv12)
165+
}
166+
if mergedTLSConfig.MaxVersion == nil {
167+
mergedTLSConfig.MaxVersion = new(ir.TLSv13)
168+
}
169+
161170
return mergedTLSConfig, nil
162171
}
163172

internal/gatewayapi/backendtrafficpolicy.go

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,6 @@ func (t *Translator) ProcessBackendTrafficPolicies(
259259
SectionIndex: make(map[types.NamespacedName]sets.Set[string], gatewayMapSize),
260260
}
261261

262-
policyCopies := backendTrafficPolicyCopiesWithStatusDeepCopy(backendTrafficPolicies)
263-
264262
handledPolicies := make(map[types.NamespacedName]*egv1a1.BackendTrafficPolicy, policyMapSize)
265263

266264
// Translate
@@ -281,7 +279,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(
281279
if isRouteRule(currTarget) {
282280
policy, found := handledPolicies[policyName]
283281
if !found {
284-
policy = policyCopies[i]
282+
policy = backendTrafficPolicies[i]
285283
handledPolicies[policyName] = policy
286284
res = append(res, policy)
287285
}
@@ -307,7 +305,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(
307305
if isRoute(currTarget) {
308306
policy, found := handledPolicies[policyName]
309307
if !found {
310-
policy = policyCopies[i]
308+
policy = backendTrafficPolicies[i]
311309
handledPolicies[policyName] = policy
312310
res = append(res, policy)
313311
}
@@ -327,7 +325,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(
327325
if isListener(currTarget) {
328326
policy, found := handledPolicies[policyName]
329327
if !found {
330-
policy = policyCopies[i]
328+
policy = backendTrafficPolicies[i]
331329
handledPolicies[policyName] = policy
332330
res = append(res, policy)
333331
}
@@ -352,7 +350,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(
352350
if isGateway(currTarget) {
353351
policy, found := handledPolicies[policyName]
354352
if !found {
355-
policy = policyCopies[i]
353+
policy = backendTrafficPolicies[i]
356354
handledPolicies[policyName] = policy
357355
res = append(res, policy)
358356
}
@@ -2189,15 +2187,3 @@ func buildRouteStatName(routeStatName string, metadata *ir.ResourceMetadata) *st
21892187

21902188
return &statName
21912189
}
2192-
2193-
// backendTrafficPolicyCopiesWithStatusDeepCopy returns shallow copies with deep-copied Status fields.
2194-
// Status is mutated during translation and shares a pointer with the watchable coalesce goroutine.
2195-
func backendTrafficPolicyCopiesWithStatusDeepCopy(policies []*egv1a1.BackendTrafficPolicy) []*egv1a1.BackendTrafficPolicy {
2196-
copies := make([]*egv1a1.BackendTrafficPolicy, len(policies))
2197-
for i, p := range policies {
2198-
out := *p
2199-
p.Status.DeepCopyInto(&out.Status)
2200-
copies[i] = &out
2201-
}
2202-
return copies
2203-
}

internal/gatewayapi/clienttrafficpolicy.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ func (t *Translator) ProcessClientTrafficPolicies(
7777
gatewayMap[key] = &policyGatewayTargetContext{GatewayContext: gw}
7878
}
7979

80-
policyCopies := clientTrafficPolicyCopiesWithStatusDeepCopy(clientTrafficPolicies)
81-
8280
handledPolicies := make(map[types.NamespacedName]*egv1a1.ClientTrafficPolicy)
8381
// Translate
8482
// 1. First translate Policies with a sectionName set
@@ -93,7 +91,7 @@ func (t *Translator) ProcessClientTrafficPolicies(
9391
if hasSectionName(&targetRef) {
9492
policy, found := handledPolicies[policyName]
9593
if !found {
96-
policy = policyCopies[i]
94+
policy = clientTrafficPolicies[i]
9795
handledPolicies[policyName] = policy
9896
res = append(res, policy)
9997
}
@@ -209,7 +207,7 @@ func (t *Translator) ProcessClientTrafficPolicies(
209207

210208
policy, found := handledPolicies[policyName]
211209
if !found {
212-
policy = policyCopies[i]
210+
policy = clientTrafficPolicies[i]
213211
res = append(res, policy)
214212
handledPolicies[policyName] = policy
215213
}
@@ -1346,15 +1344,3 @@ func translateHeaderModifier(headerModifier *egv1a1.HTTPHeaderFilter, modType st
13461344

13471345
return addRequestHeaders, removeRequestHeaders, removeRequestHeadersOnMatch, errs
13481346
}
1349-
1350-
// clientTrafficPolicyCopiesWithStatusDeepCopy returns shallow copies with deep-copied Status fields.
1351-
// Status is mutated during translation and shares a pointer with the watchable coalesce goroutine.
1352-
func clientTrafficPolicyCopiesWithStatusDeepCopy(policies []*egv1a1.ClientTrafficPolicy) []*egv1a1.ClientTrafficPolicy {
1353-
copies := make([]*egv1a1.ClientTrafficPolicy, len(policies))
1354-
for i, p := range policies {
1355-
out := *p
1356-
p.Status.DeepCopyInto(&out.Status)
1357-
copies[i] = &out
1358-
}
1359-
return copies
1360-
}

internal/gatewayapi/envoyextensionpolicy.go

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(
103103
// The routes are grouped by sectionNames of their targetRefs.
104104
gatewayRouteMap := make(map[string]map[string]sets.Set[string])
105105

106-
policyCopies := envoyExtensionPolicyCopiesWithStatusDeepCopy(envoyExtensionPolicies)
107-
108106
handledPolicies := make(map[types.NamespacedName]*egv1a1.EnvoyExtensionPolicy)
109107

110108
// Translate
@@ -122,7 +120,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(
122120
if isRouteRule(currTarget) {
123121
policy, found := handledPolicies[policyName]
124122
if !found {
125-
policy = policyCopies[i]
123+
policy = envoyExtensionPolicies[i]
126124
res = append(res, policy)
127125
handledPolicies[policyName] = policy
128126
}
@@ -148,7 +146,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(
148146
if isRoute(currTarget) {
149147
policy, found := handledPolicies[policyName]
150148
if !found {
151-
policy = policyCopies[i]
149+
policy = envoyExtensionPolicies[i]
152150
res = append(res, policy)
153151
handledPolicies[policyName] = policy
154152
}
@@ -168,7 +166,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(
168166
if isListener(currTarget) {
169167
policy, found := handledPolicies[policyName]
170168
if !found {
171-
policy = policyCopies[i]
169+
policy = envoyExtensionPolicies[i]
172170
res = append(res, policy)
173171
handledPolicies[policyName] = policy
174172
}
@@ -194,7 +192,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(
194192
if isGateway(currTarget) {
195193
policy, found := handledPolicies[policyName]
196194
if !found {
197-
policy = policyCopies[i]
195+
policy = envoyExtensionPolicies[i]
198196
res = append(res, policy)
199197
handledPolicies[policyName] = policy
200198
}
@@ -1277,15 +1275,3 @@ func (t *Translator) buildDynamicModules(
12771275

12781276
return dmIRList, errs
12791277
}
1280-
1281-
// envoyExtensionPolicyCopiesWithStatusDeepCopy returns shallow copies with deep-copied Status fields.
1282-
// Status is mutated during translation and shares a pointer with the watchable coalesce goroutine.
1283-
func envoyExtensionPolicyCopiesWithStatusDeepCopy(policies []*egv1a1.EnvoyExtensionPolicy) []*egv1a1.EnvoyExtensionPolicy {
1284-
copies := make([]*egv1a1.EnvoyExtensionPolicy, len(policies))
1285-
for i, p := range policies {
1286-
out := *p
1287-
p.Status.DeepCopyInto(&out.Status)
1288-
copies[i] = &out
1289-
}
1290-
return copies
1291-
}

internal/gatewayapi/envoypatchpolicy.go

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ import (
1919

2020
func (t *Translator) ProcessEnvoyPatchPolicies(envoyPatchPolicies []*egv1a1.EnvoyPatchPolicy, xdsIR resource.XdsIRMap) []*egv1a1.EnvoyPatchPolicy {
2121
// EnvoyPatchPolicies are already sorted by the provider layer (priority, then timestamp, then name)
22-
policyCopies := envoyPatchPolicyCopiesWithStatusDeepCopy(envoyPatchPolicies)
2322
res := make([]*egv1a1.EnvoyPatchPolicy, 0, len(envoyPatchPolicies))
2423

2524
for i := range envoyPatchPolicies {
26-
policy := policyCopies[i]
25+
policy := envoyPatchPolicies[i]
2726
res = append(res, policy)
2827
var (
2928
ancestorRef gwapiv1.ParentReference
@@ -146,15 +145,3 @@ func (t *Translator) ProcessEnvoyPatchPolicies(envoyPatchPolicies []*egv1a1.Envo
146145

147146
return res
148147
}
149-
150-
// envoyPatchPolicyCopiesWithStatusDeepCopy returns shallow copies with deep-copied Status fields.
151-
// Status is mutated during translation and shares a pointer with the watchable coalesce goroutine.
152-
func envoyPatchPolicyCopiesWithStatusDeepCopy(policies []*egv1a1.EnvoyPatchPolicy) []*egv1a1.EnvoyPatchPolicy {
153-
copies := make([]*egv1a1.EnvoyPatchPolicy, len(policies))
154-
for i, p := range policies {
155-
out := *p
156-
p.Status.DeepCopyInto(&out.Status)
157-
copies[i] = &out
158-
}
159-
return copies
160-
}

internal/gatewayapi/extensionserverpolicy.go

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ import (
99
"encoding/json"
1010
"errors"
1111
"fmt"
12-
"maps"
1312
"strings"
1413

1514
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
16-
"k8s.io/apimachinery/pkg/runtime"
1715
"k8s.io/apimachinery/pkg/types"
1816
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
1917

@@ -38,13 +36,11 @@ func (t *Translator) ProcessExtensionServerPolicies(policies []unstructured.Unst
3836
gatewayMap[key] = &policyGatewayTargetContext{GatewayContext: gw}
3937
}
4038

41-
policyCopies := extensionServerPolicyCopiesWithStatusDeepCopy(policies)
42-
4339
var errs error
4440
// Process the policies targeting Gateways. Only update the policy status if it was accepted.
4541
// A policy is considered accepted if at least one targetRef contained inside matched a listener.
4642
for i := range policies {
47-
policy := policyCopies[i]
43+
policy := policies[i]
4844
var policyStatus gwapiv1.PolicyStatus
4945
accepted := false
5046
targetRefs, err := extractTargetRefs(&policy, gateways)
@@ -192,17 +188,3 @@ func (t *Translator) translateExtServerPolicyForGateway(
192188
}
193189
return found
194190
}
195-
196-
// extensionServerPolicyCopiesWithStatusDeepCopy returns shallow copies with deep-copied status entries.
197-
// Status is mutated during translation and shares a pointer with the watchable coalesce goroutine.
198-
func extensionServerPolicyCopiesWithStatusDeepCopy(policies []unstructured.Unstructured) []unstructured.Unstructured {
199-
copies := make([]unstructured.Unstructured, len(policies))
200-
for i, p := range policies {
201-
p.Object = maps.Clone(p.Object) // shallow copy map - no shared ref for "status" key
202-
if statusObj, ok := policies[i].Object["status"].(map[string]any); ok {
203-
p.Object["status"] = runtime.DeepCopyJSON(statusObj)
204-
}
205-
copies[i] = p
206-
}
207-
return copies
208-
}

internal/gatewayapi/listener_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,7 @@ func TestProcessBackendRefsBackendTLSPolicy(t *testing.T) {
13981398
backendPolicyTLS := &ir.TLSUpstreamConfig{
13991399
SNI: new("otel.example.com"), UseSystemTrustStore: true,
14001400
CACertificate: &ir.TLSCACertificate{Name: "otel-tls/test-ns-ca"}, SubjectAltNames: []ir.SubjectAltName{},
1401+
TLSConfig: ir.TLSConfig{MinVersion: new(ir.TLSv12), MaxVersion: new(ir.TLSv13)},
14011402
}
14021403

14031404
serviceBackendCluster := egv1a1.BackendCluster{BackendRefs: []egv1a1.BackendRef{{
@@ -1436,6 +1437,7 @@ func TestProcessBackendRefsBackendTLSPolicy(t *testing.T) {
14361437
servicePolicyTLS := &ir.TLSUpstreamConfig{
14371438
SNI: new("otel-svc.example.com"), UseSystemTrustStore: true,
14381439
CACertificate: &ir.TLSCACertificate{Name: "otel-svc-tls/test-ns-ca"}, SubjectAltNames: []ir.SubjectAltName{},
1440+
TLSConfig: ir.TLSConfig{MinVersion: new(ir.TLSv12), MaxVersion: new(ir.TLSv13)},
14391441
}
14401442

14411443
tests := []struct {

internal/gatewayapi/resource/resource.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ package resource
77

88
import (
99
"context"
10+
"maps"
1011
"reflect"
1112
"sort"
1213

1314
certificatesv1b1 "k8s.io/api/certificates/v1beta1"
1415
corev1 "k8s.io/api/core/v1"
1516
discoveryv1 "k8s.io/api/discovery/v1"
1617
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
18+
"k8s.io/apimachinery/pkg/runtime"
1719
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
1820
gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
1921
gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1"
@@ -503,3 +505,83 @@ func (r *Resources) Sort() {
503505
return tsI.Before(&tsJ)
504506
})
505507
}
508+
509+
// StatusDeepCopy returns a shallow copy of Resources in which every status-bearing
510+
// object is itself shallow-copied with only its Status field deep-copied.
511+
//
512+
// The translator mutates resource Status in place while building status updates,
513+
// but the input tree is shared with the watchable coalesce goroutine, which walks it
514+
// with reflect.DeepEqual. Deep-copying only the Status fields isolates those in-place
515+
// mutations from the shared objects without the memory cost of a full DeepCopy of the
516+
// (much larger, immutable-during-translation) Spec.
517+
func (r *Resources) StatusDeepCopy() *Resources {
518+
if r == nil {
519+
return nil
520+
}
521+
522+
// Shallow copy of the struct: all fields (including the shared, non-status-bearing
523+
// slices such as Namespaces, Services, Secrets, ...) are carried over as-is.
524+
out := *r
525+
526+
out.GatewayClass = statusDeepCopyObject(r.GatewayClass, func(dst, src *gwapiv1.GatewayClass) { src.Status.DeepCopyInto(&dst.Status) })
527+
out.EnvoyProxyForGatewayClass = statusDeepCopyObject(r.EnvoyProxyForGatewayClass, func(dst, src *egv1a1.EnvoyProxy) { src.Status.DeepCopyInto(&dst.Status) })
528+
out.EnvoyProxiesForGateways = statusDeepCopySlice(r.EnvoyProxiesForGateways, func(dst, src *egv1a1.EnvoyProxy) { src.Status.DeepCopyInto(&dst.Status) })
529+
out.Gateways = statusDeepCopySlice(r.Gateways, func(dst, src *gwapiv1.Gateway) { src.Status.DeepCopyInto(&dst.Status) })
530+
out.ListenerSets = statusDeepCopySlice(r.ListenerSets, func(dst, src *gwapiv1.ListenerSet) { src.Status.DeepCopyInto(&dst.Status) })
531+
out.HTTPRoutes = statusDeepCopySlice(r.HTTPRoutes, func(dst, src *gwapiv1.HTTPRoute) { src.Status.DeepCopyInto(&dst.Status) })
532+
out.GRPCRoutes = statusDeepCopySlice(r.GRPCRoutes, func(dst, src *gwapiv1.GRPCRoute) { src.Status.DeepCopyInto(&dst.Status) })
533+
out.TLSRoutes = statusDeepCopySlice(r.TLSRoutes, func(dst, src *gwapiv1.TLSRoute) { src.Status.DeepCopyInto(&dst.Status) })
534+
out.TCPRoutes = statusDeepCopySlice(r.TCPRoutes, func(dst, src *gwapiv1a2.TCPRoute) { src.Status.DeepCopyInto(&dst.Status) })
535+
out.UDPRoutes = statusDeepCopySlice(r.UDPRoutes, func(dst, src *gwapiv1a2.UDPRoute) { src.Status.DeepCopyInto(&dst.Status) })
536+
out.EnvoyPatchPolicies = statusDeepCopySlice(r.EnvoyPatchPolicies, func(dst, src *egv1a1.EnvoyPatchPolicy) { src.Status.DeepCopyInto(&dst.Status) })
537+
out.ClientTrafficPolicies = statusDeepCopySlice(r.ClientTrafficPolicies, func(dst, src *egv1a1.ClientTrafficPolicy) { src.Status.DeepCopyInto(&dst.Status) })
538+
out.BackendTrafficPolicies = statusDeepCopySlice(r.BackendTrafficPolicies, func(dst, src *egv1a1.BackendTrafficPolicy) { src.Status.DeepCopyInto(&dst.Status) })
539+
out.SecurityPolicies = statusDeepCopySlice(r.SecurityPolicies, func(dst, src *egv1a1.SecurityPolicy) { src.Status.DeepCopyInto(&dst.Status) })
540+
out.BackendTLSPolicies = statusDeepCopySlice(r.BackendTLSPolicies, func(dst, src *gwapiv1.BackendTLSPolicy) { src.Status.DeepCopyInto(&dst.Status) })
541+
out.EnvoyExtensionPolicies = statusDeepCopySlice(r.EnvoyExtensionPolicies, func(dst, src *egv1a1.EnvoyExtensionPolicy) { src.Status.DeepCopyInto(&dst.Status) })
542+
out.Backends = statusDeepCopySlice(r.Backends, func(dst, src *egv1a1.Backend) { src.Status.DeepCopyInto(&dst.Status) })
543+
out.ExtensionServerPolicies = statusDeepCopyUnstructured(r.ExtensionServerPolicies)
544+
545+
return &out
546+
}
547+
548+
// statusDeepCopyObject returns a shallow copy of obj with copyStatus applied to
549+
// deep-copy its Status field, or nil if obj is nil.
550+
func statusDeepCopyObject[T any](obj *T, copyStatus func(dst, src *T)) *T {
551+
if obj == nil {
552+
return nil
553+
}
554+
cp := *obj
555+
copyStatus(&cp, obj)
556+
return &cp
557+
}
558+
559+
// statusDeepCopySlice returns a new slice of shallow copies, each with copyStatus
560+
// applied to deep-copy its Status field, preserving the original length and nil-ness.
561+
func statusDeepCopySlice[T any](in []*T, copyStatus func(dst, src *T)) []*T {
562+
if in == nil {
563+
return nil
564+
}
565+
out := make([]*T, len(in))
566+
for i, obj := range in {
567+
out[i] = statusDeepCopyObject(obj, copyStatus)
568+
}
569+
return out
570+
}
571+
572+
// statusDeepCopyUnstructured returns shallow copies with deep-copied status entries
573+
// for unstructured resources (ExtensionServerPolicies).
574+
func statusDeepCopyUnstructured(in []unstructured.Unstructured) []unstructured.Unstructured {
575+
if in == nil {
576+
return nil
577+
}
578+
out := make([]unstructured.Unstructured, len(in))
579+
for i, p := range in {
580+
p.Object = maps.Clone(p.Object) // shallow copy map - no shared ref for "status" key
581+
if statusObj, ok := in[i].Object["status"].(map[string]any); ok {
582+
p.Object["status"] = runtime.DeepCopyJSON(statusObj)
583+
}
584+
out[i] = p
585+
}
586+
return out
587+
}

0 commit comments

Comments
 (0)