Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ linters:
alias: metav1
- pkg: k8s.io/api/batch/v1
alias: batchv1
- pkg: github.com/kgateway-dev/kgateway/v2/api/annotations
alias: apiannotations
misspell:
ignore-rules:
- kgateway
Expand Down
19 changes: 0 additions & 19 deletions api/annotations/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,4 @@ const (
// participates in a delegation chain to indicate that child route should inherit
// the route matcher from the parent route.
DelegationInheritMatcher = "delegation.kgateway.dev/inherit-parent-matcher"

// DelegationInheritedPolicyPriority is the annotation used on an HTTPRoute to specify
// the priority of policies attached to the route that are inherited by delegatee(child) routes.
DelegationInheritedPolicyPriority = "delegation.kgateway.dev/inherited-policy-priority"
)

// DelegationInheritedPolicyPriorityValue is the value for the DelegationInheritedPolicyPriority annotation
type DelegationInheritedPolicyPriorityValue string

const (
// DelegationInheritedPolicyPriorityPreferParent is the value for the DelegationInheritedPolicyPriority
// annotation to indicate that the delegatee(child) route should prefer policies attached to the parent route
// such that parent policies are prioritized over policies directly attached to child routes in case of conflicts.
DelegationInheritedPolicyPriorityPreferParent DelegationInheritedPolicyPriorityValue = "PreferParent"

// DelegationInheritedPolicyPriorityPreferChild is the value for the DelegationInheritedPolicyPriority
// annotation to indicate that the delegatee(child) route should prefer policies attached to the child route
// such that child policies are prioritized over policies attached to parent routes in case of conflicts.
DelegationInheritedPolicyPriorityPreferChild DelegationInheritedPolicyPriorityValue = "PreferChild"
)
30 changes: 30 additions & 0 deletions api/annotations/policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package annotations

// InheritedPolicyPriority is the annotation used on a Gateway or parent HTTPRoute to specify
// the priority of corresponding policies attached that are inherited by attached routes or child routes respectively.
const InheritedPolicyPriority = "kgateway.dev/inherited-policy-priority"

// InheritedPolicyPriorityValue is the value for the InheritedPolicyPriority annotation
type InheritedPolicyPriorityValue string

const (
// ShallowMergePreferParent is the value for the InheritedPolicyPriority annotation to indicate that
// inherited parent policies (attached to the Gateway or parent HTTPRoute) should be shallow merged and
// preferred over policies directly attached to child routes in case of conflicts.
ShallowMergePreferParent InheritedPolicyPriorityValue = "ShallowMergePreferParent"

// ShallowMergePreferChild is the value for the InheritedPolicyPriority annotation to indicate that
// policies attached to the child route should be shallow merged and preferred over inherited parent policies
// (attached to the Gateway or parent HTTPRoute) in case of conflicts.
ShallowMergePreferChild InheritedPolicyPriorityValue = "ShallowMergePreferChild"

// DeepMergePreferParent is the value for the InheritedPolicyPriority annotation to indicate that
// inherited parent policies (attached to the Gateway or parent HTTPRoute) should be deep merged and
// preferred over policies directly attached to child routes in case of conflicts.
DeepMergePreferParent InheritedPolicyPriorityValue = "DeepMergePreferParent"

// DeepMergePreferChild is the value for the InheritedPolicyPriority annotation to indicate that
// policies attached to the child route should be deep merged and preferred over inherited parent policies
// (attached to the Gateway or parent HTTPRoute) in case of conflicts.
DeepMergePreferChild InheritedPolicyPriorityValue = "DeepMergePreferChild"
)
8 changes: 5 additions & 3 deletions design/10943.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Route delegation is configured through the `backendRefs` field in HTTPRoute rule

In the simplest case, a parent route can delegate configuration for a specific path prefix to a child by reference. If the child route's namespace is not specified, it defaults to the parent route's namespace.

The parent and child matchers must adhere to the following rules (unless [matcher inheritance](#matcher-inheritance) is used):
The parent and child matchers must adhere to the following rules (unless [matcher inheritance](#matcher-inheritance) is used):
- The parent path matcher must be of type `PathPrefix`.
- The child's path matcher value must contain the parent's path matcher value as a prefix.

Expand Down Expand Up @@ -724,7 +724,7 @@ spec:
### TrafficPolicy inheritance and merging

Child routes can inherit TrafficPolicies that are attached to their ancestors. If a TrafficPolicy is attached to both an ancestor and a child, the TrafficPolicies will be merged. To merge policies, we need to consider both the hierarchy of routes (i.e. parent vs. child), and the ordering of attachment points (i.e. targetRef, extensionRef) within each level of the hierarchy:
- By default, policies attached to a parent take precedence over policies attached to a child. However, if the parent route sets the annotation `delegation.kgateway.dev/inherited-policy-priority: PreferChild`, then it allows the child policy to override fields on the parent policy.
- By default, policies attached to a child take precedence over policies attached to a parent. However, if the parent route sets the annotation `kgateway.dev/inherited-policy-priority` with value `ShallowMergePreferParent` or `DeepMergePreferParent`, then it allows the parent policy to override fields on the child policy. By default, the inherited policy priority is `ShallowMergePreferChild`, which implies that child policies take precedence over parent policies when the policies are shallow merged.
- Within a route, policy attachment has the following priority, from highest to lowest:
- Policy attached to HTTPRouteRule via `extensionRef`
- Policy attached to HTTPRouteRule via `targetRef`
Expand All @@ -742,6 +742,8 @@ kind: HTTPRoute
metadata:
name: parent-foo
namespace: infra
annotations:
kgateway.dev/inherited-policy-priority: ShallowMergePreferParent
spec:
parentRefs:
- name: example-gateway
Expand All @@ -764,7 +766,7 @@ metadata:
name: parent-bar
namespace: infra
annotations:
delegation.kgateway.dev/inherited-policy-priority: PreferChild
kgateway.dev/inherited-policy-priority: ShallowMergePreferChild
spec:
parentRefs:
- name: example-gateway
Expand Down
19 changes: 15 additions & 4 deletions design/11268.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,25 @@ Policies for a given GroupKind are implemented by a specific plugin. When applyi

#### Plugin Ordering

Built-in policies, implemented for the `VirtualBuiltInGK` GroupKind, are always applied last so that they can override other policies. Built-in policies correspond to policies that are a part of the upstream Gateway API spec, such as `HTTPRouteFilterURLRewrite`, `HTTPRouteTimeouts`, `HTTPRouteRetry`, etc., and are considered higher in priority than other forms of policy attachments (`ExtensionRef` or `TargetRefs`).
Built-in policies, implemented for the `VirtualBuiltInGK` GroupKind, are always applied first since they are higher in priority relative to other policies. Built-in policies correspond to policies that are a part of the upstream Gateway API spec, such as `HTTPRouteFilterURLRewrite`, `HTTPRouteTimeouts`, `HTTPRouteRetry`, etc., and are considered higher in priority than other forms of policy attachments (`ExtensionRef` or `TargetRefs`).

Plugin ordering is enforced by iterating `AttachedPolicies` on the targeted resource by invoking `ApplyOrderedGroupKinds()` that returns the list of GroupKinds in the order they should be processed. Currently, the ordering is limited to allow built-in policies to be applied last.
Plugin ordering is enforced by iterating `AttachedPolicies` on the targeted resource by invoking `ApplyOrderedGroupKinds()` that returns the list of GroupKinds in the order they should be processed. Currently, the ordering is limited to allow built-in policies to be applied first.


### Policy Merging

Currently, only the `TrafficPolicy` plugin supports policy merging. The merging ensures that lower priority policies can set top-level policy fields that are not set by higher priority policies.
Currently, the `TrafficPolicy` and `builtin` plugins support policy merging. The merging ensures that policies are merged within the same config hierarchy level and then are merged across levels.

Resources higher in the config hierarchy can define how policies attached to them should be inherited by child resources and merge with child policies. E.g., a parent `HTTPRoute` can specify whether a child/delegatee `HTTPRoute` policy may override conflicting policies attached to the parent `HTTPRoute` or not. This is done by setting the annotation `kgateway.dev/inherited-policy-priority` on the parent resource.

The annotation can have one of the following values:
- `ShallowMergePreferChild` (default): Child policies take precedence over parent policies and the policies are shallow merged.
- `ShallowMergePreferParent`: Parent policies take precedence over child policies and the policies are shallow merged.
- `DeepMergePreferChild`: Child policies take precedence over parent policies and the policies are deep merged.
- `DeepMergePreferParent`: Parent policies take precedence over child policies and the policies are deep merged.

*Shallow merging* means that the policies are merged at the top level, i.e., only the top-level fields of the policies are considered for merging. If a field is present in both policies, the value from the higher priority policy is used.
*Deep merging* means that the policies can be deep merged, i.e., if the same field is set in both policies, their values can be merged when appropriate. E.g., `transformation` policies can be deep merged, where the parent or child policy's transformations are given precedence when they are combined during a deep merge.

Consider [this example](/internal/kgateway/translator/gateway/testutils/inputs/traffic-policy/merge.yaml) were the `example-route` HTTPRoute has 3 TrafficPolicies attached to it:
1. `extensionref-policy` which is referenced in the `example-route` HTTPRoute and has the highest priority.
Expand All @@ -78,4 +89,4 @@ N/a

## Open Questions

Plugins that do not implement policy merging must ensure that lower priority policies do not override higher priority policies. This is a work in progress.
Plugins that do not implement `MergePolicies` must ensure that lower priority policies do not override higher priority policies. The `builtin` plugin is an example where policies are merged without using the `MergePolicies` function. This is a work in progress.
Loading