Skip to content

Commit 02cc5bc

Browse files
apkatsikasjukie
andauthored
feat(policy): support ListenerSet as targetRef for ClientTrafficPolicy (#9026)
* feat(policy): support ListenerSet as targetRef for ClientTrafficPolicy Allow ClientTrafficPolicy to target a ListenerSet in addition to a Gateway, enabling per-listener-group traffic policy without applying settings cluster-wide. Supports both whole-ListenerSet and sectionName-scoped targeting with correct conflict detection. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * refactor(policy): merge sectionName CTP processing passes into one loop Signed-off-by: apkatsikas <apkatsikas@gmail.com> * refactor(policy): collapse no-sectionName CTP processing passes into one loop Signed-off-by: apkatsikas <apkatsikas@gmail.com> * chore: regenerate helm CRD snapshots for ListenerSet targetRef CEL rules Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(policy): enforce mutual exclusion between ListenerSet-wide and Gateway-wide CTPs When a ListenerSet-wide CTP applies to a listener, record the individual listener name in policyMap so a later Gateway-wide CTP correctly skips it. When a Gateway-wide CTP runs first (AllSections="/"), skip LS listeners in the ListenerSet-wide pass. Covers both interaction orderings with new golden file tests. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * refactor(policy): unify targetRef resolution into a single function Replace the separate resolveClientTrafficPolicyTargetRefForListenerSet with a ctpResolvedTarget struct and a single resolveClientTrafficPolicyTargetRef that dispatches on targetRef.Kind internally, reducing the three-return signature to the conventional (result, error) pair. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(policy): enforce ListenerSet-wide > Gateway-wide priority regardless of input order Process ListenerSet-wide CTPs before Gateway-wide in the no-sectionName pass by iterating twice with a processLS filter, matching the more-specific-wins principle already established by sectionName policies. Adds golden file tests covering both input orderings. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * chore: add release notes for ListenerSet targetRef support in CTP Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(policy): remove internal sentinel from CTP Overridden status message When a ListenerSet-wide CTP was overridden by a Gateway-wide CTP, the Overridden message incorrectly included the internal listenerset/... scope sentinel alongside real listener names, e.g.: sections [ext-http-1 ext-http-2 listenerset/envoy-gateway/ext-listeners] Fix by splitting policyMap into two maps: - policyMap: whole-scope sentinels only (Conflicted detection) - claimedListeners: listener names only (skip logic + Overridden messages) The message now correctly shows only real listener names. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * refactor(policy): rename listenersDontBelongToLS to positive listenersBelongToLS Signed-off-by: apkatsikas <apkatsikas@gmail.com> * refactor(policy): hoist passKind check before handledPolicies registration Update fixture to reflect new output ordering: LS-wide policies are now appended to res in pass 1, GW-wide in pass 2. Conditions and XdsIR unchanged. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(policy): scope claimedSections keys to prevent false conflicts across ListenerSets Listeners with the same name in different ListenerSets (or a Gateway listener sharing a name with a ListenerSet listener) would incorrectly produce spurious Conflicted/Overridden status and skip translation. Scope claim keys by LS identity to isolate claims per target. Add test fixtures covering wide and sectionName variants of the collision scenario. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * chore: fix copyloopvar lint error in claimedSections loop Signed-off-by: apkatsikas <apkatsikas@gmail.com> * refactor: precompute listenerSet map to avoid O(n) scan per CTP Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(policy): validate port overlap per-target scope for LS-wide CTPs Introduces ctpAttachScope enum (scopeSpecificSection, scopeEntireGateway, scopeEntireListenerSet) to replace the attachedToGateway bool in validatePortOverlapForClientTrafficPolicy. LS-wide CTPs now correctly allow same-port HTTP listeners within the same ListenerSet, matching the existing gateway-wide behavior. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * test: add CTP LS sectionName conflict/override coverage Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(policy): use ListenerSet as ancestorRef when CTP targets a ListenerSet Per GEP-713, the ancestorRef should be the ancestor where status meaningfully differs. When a CTP directly targets a ListenerSet, that is the ListenerSet itself, not the parent Gateway. Adds a mixed-type test confirming two distinct ancestor entries when a single CTP targets both a Gateway and a ListenerSet. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(policy): support ListenerSet targetSelectors in ClientTrafficPolicy Add resolvePolicyTargetsForGatewayAndListenerSet helper that runs selector resolution against both Gateways and ListenerSets, fixing the gap where targetSelectors with kind: ListenerSet silently matched nothing. Add two test fixtures covering the LS-only and mixed Gateway+ListenerSet selector cases. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * test(cel): update CTP CEL validation tests for ListenerSet kind Fix stale error message strings that still referenced Gateway-only, and add a positive test case for kind: ListenerSet. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix: resolve appendAssign lint error in resolvePolicyTargetsForGatewayAndListenerSet Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(policy): add trailing slash to ListenerSet prefix to prevent false prefix matches in port overlap validation A ListenerSet named ext would falsely match listeners from ext-b in strings.Index comparisons. Adding a trailing slash to the extracted prefix ensures exact boundary matching. Adds a test fixture covering this scenario. Signed-off-by: apkatsikas <apkatsikas@gmail.com> * test(e2e): add e2e test for ClientTrafficPolicy targeting ListenerSet Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(e2e): wait for route parents before dialing in ListenerSetClientTrafficPolicy test Signed-off-by: apkatsikas <apkatsikas@gmail.com> * fix(e2e): poll until listener accepts TLS before version checks in ListenerSetClientTrafficPolicy test Signed-off-by: apkatsikas <apkatsikas@gmail.com> --------- Signed-off-by: apkatsikas <apkatsikas@gmail.com> Signed-off-by: Isaac Wilson <isaac.wilson514@gmail.com> Co-authored-by: Isaac Wilson <isaac.wilson514@gmail.com>
1 parent d65425e commit 02cc5bc

42 files changed

Lines changed: 5962 additions & 174 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.

api/v1alpha1/clienttrafficpolicy_types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ type ClientTrafficPolicy struct {
3939
//
4040
// +kubebuilder:validation:XValidation:rule="(has(self.targetRef) && !has(self.targetRefs)) || (!has(self.targetRef) && has(self.targetRefs)) || (has(self.targetSelectors) && self.targetSelectors.size() > 0) ", message="either targetRef or targetRefs must be used"
4141
// +kubebuilder:validation:XValidation:rule="has(self.targetRef) ? self.targetRef.group == 'gateway.networking.k8s.io' : true", message="this policy can only have a targetRef.group of gateway.networking.k8s.io"
42-
// +kubebuilder:validation:XValidation:rule="has(self.targetRef) ? self.targetRef.kind == 'Gateway' : true", message="this policy can only have a targetRef.kind of Gateway"
42+
// +kubebuilder:validation:XValidation:rule="has(self.targetRef) ? self.targetRef.kind in ['Gateway', 'ListenerSet'] : true", message="this policy can only have a targetRef.kind of Gateway or ListenerSet"
4343
// +kubebuilder:validation:XValidation:rule="has(self.targetRefs) ? self.targetRefs.all(ref, ref.group == 'gateway.networking.k8s.io') : true", message="this policy can only have a targetRefs[*].group of gateway.networking.k8s.io"
44-
// +kubebuilder:validation:XValidation:rule="has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind == 'Gateway') : true", message="this policy can only have a targetRefs[*].kind of Gateway"
44+
// +kubebuilder:validation:XValidation:rule="has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in ['Gateway', 'ListenerSet']) : true", message="this policy can only have a targetRefs[*].kind of Gateway or ListenerSet"
4545
type ClientTrafficPolicySpec struct {
4646
PolicyTargetReferences `json:",inline"`
4747

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,14 +1827,16 @@ spec:
18271827
- message: this policy can only have a targetRef.group of gateway.networking.k8s.io
18281828
rule: 'has(self.targetRef) ? self.targetRef.group == ''gateway.networking.k8s.io''
18291829
: true'
1830-
- message: this policy can only have a targetRef.kind of Gateway
1831-
rule: 'has(self.targetRef) ? self.targetRef.kind == ''Gateway'' : true'
1830+
- message: this policy can only have a targetRef.kind of Gateway or ListenerSet
1831+
rule: 'has(self.targetRef) ? self.targetRef.kind in [''Gateway'', ''ListenerSet'']
1832+
: true'
18321833
- message: this policy can only have a targetRefs[*].group of gateway.networking.k8s.io
18331834
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.group ==
18341835
''gateway.networking.k8s.io'') : true'
1835-
- message: this policy can only have a targetRefs[*].kind of Gateway
1836-
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind == ''Gateway'')
1837-
: true'
1836+
- message: this policy can only have a targetRefs[*].kind of Gateway or
1837+
ListenerSet
1838+
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in [''Gateway'',
1839+
''ListenerSet'']) : true'
18381840
status:
18391841
description: Status defines the current status of ClientTrafficPolicy.
18401842
properties:

charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,14 +1826,16 @@ spec:
18261826
- message: this policy can only have a targetRef.group of gateway.networking.k8s.io
18271827
rule: 'has(self.targetRef) ? self.targetRef.group == ''gateway.networking.k8s.io''
18281828
: true'
1829-
- message: this policy can only have a targetRef.kind of Gateway
1830-
rule: 'has(self.targetRef) ? self.targetRef.kind == ''Gateway'' : true'
1829+
- message: this policy can only have a targetRef.kind of Gateway or ListenerSet
1830+
rule: 'has(self.targetRef) ? self.targetRef.kind in [''Gateway'', ''ListenerSet'']
1831+
: true'
18311832
- message: this policy can only have a targetRefs[*].group of gateway.networking.k8s.io
18321833
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.group ==
18331834
''gateway.networking.k8s.io'') : true'
1834-
- message: this policy can only have a targetRefs[*].kind of Gateway
1835-
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind == ''Gateway'')
1836-
: true'
1835+
- message: this policy can only have a targetRefs[*].kind of Gateway or
1836+
ListenerSet
1837+
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in [''Gateway'',
1838+
''ListenerSet'']) : true'
18371839
status:
18381840
description: Status defines the current status of ClientTrafficPolicy.
18391841
properties:

0 commit comments

Comments
 (0)