Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
123 changes: 108 additions & 15 deletions internal/gatewayapi/backendtrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ func (t *Translator) ProcessBackendTrafficPolicies(

handledPolicies := make(map[types.NamespacedName]*egv1a1.BackendTrafficPolicy, policyMapSize)

// Tracks policies that were successfully attached to at least one real target
// during this pass, so we can report the rest (zero targets) as TargetNotFound.
attachedPolicies := make(map[types.NamespacedName]bool, policyMapSize)

// Translate
// 1. First translate Policies targeting RouteRules
// 2. Next translate Policies targeting xRoutes
Expand All @@ -286,8 +290,10 @@ func (t *Translator) ProcessBackendTrafficPolicies(
res = append(res, policy)
}

t.processBackendTrafficPolicyForRoute(xdsIR,
routeMap, gatewayRouteMap, gatewayPolicyMerged, gatewayPolicyMap, policy, currTarget)
if t.processBackendTrafficPolicyForRoute(xdsIR,
routeMap, gatewayRouteMap, gatewayPolicyMerged, gatewayPolicyMap, policy, currTarget) {
attachedPolicies[policyName] = true
}
}
}
}
Expand All @@ -312,8 +318,10 @@ func (t *Translator) ProcessBackendTrafficPolicies(
res = append(res, policy)
}

t.processBackendTrafficPolicyForRoute(xdsIR,
routeMap, gatewayRouteMap, gatewayPolicyMerged, gatewayPolicyMap, policy, currTarget)
if t.processBackendTrafficPolicyForRoute(xdsIR,
routeMap, gatewayRouteMap, gatewayPolicyMerged, gatewayPolicyMap, policy, currTarget) {
attachedPolicies[policyName] = true
}
}
}
}
Expand All @@ -331,8 +339,10 @@ func (t *Translator) ProcessBackendTrafficPolicies(
handledPolicies[policyName] = policy
res = append(res, policy)
}
t.processBackendTrafficPolicyForGateway(xdsIR,
gatewayMap, gatewayRouteMap, gatewayPolicyMerged, policy, currTarget)
if t.processBackendTrafficPolicyForGateway(xdsIR,
gatewayMap, gatewayRouteMap, gatewayPolicyMerged, policy, currTarget) {
attachedPolicies[policyName] = true
}
}
}
}
Expand All @@ -356,12 +366,50 @@ func (t *Translator) ProcessBackendTrafficPolicies(
handledPolicies[policyName] = policy
res = append(res, policy)
}
t.processBackendTrafficPolicyForGateway(xdsIR,
gatewayMap, gatewayRouteMap, gatewayPolicyMerged, policy, currTarget)
if t.processBackendTrafficPolicyForGateway(xdsIR,
gatewayMap, gatewayRouteMap, gatewayPolicyMerged, policy, currTarget) {
attachedPolicies[policyName] = true
}
}
}
}

// Report policies that did not attach to any target so their status does not
// go stale. This covers two distinct cases that both resolve to zero targets:
// - targetRef/targetRefs pointing at an object that does not exist (#8926)
// - targetSelectors that match no objects (#8927)
// In both cases we set Accepted=False with reason TargetNotFound and the current
// generation, so a policy that stops matching any target no longer keeps a stale
// Accepted=True condition with an out-of-date observedGeneration.
for i, currPolicy := range backendTrafficPolicies {
policyName := utils.NamespacedName(currPolicy)
if attachedPolicies[policyName] {
continue
}
policy, found := handledPolicies[policyName]
if !found {
// Never matched any target (e.g. targetSelectors matched nothing), so the
// policy was never added to res. Add it now so its status is published.
policy = policyCopies[i]
handledPolicies[policyName] = policy
res = append(res, policy)
}
// The policy attached to no target. Drop any ancestor status carried over from
// a previous generation (which would otherwise remain stale) and report
// TargetNotFound with the current generation.
policy.Status.Ancestors = nil
ancestorRef := ancestorRefForUnattachedBackendTrafficPolicy(policy)
status.SetConditionForPolicyAncestor(&policy.Status,
&ancestorRef,
t.GatewayControllerName,
gwapiv1.PolicyConditionAccepted,
metav1.ConditionFalse,
gwapiv1.PolicyReasonTargetNotFound,
backendTrafficPolicyTargetNotFoundMessage(policy),
policy.Generation,
)
}

for _, policy := range res {
// Truncate Ancestor list of longer than 16
if len(policy.Status.Ancestors) > 16 {
Expand All @@ -371,6 +419,47 @@ func (t *Translator) ProcessBackendTrafficPolicies(
return res
}

// ancestorRefForUnattachedBackendTrafficPolicy builds the ancestor reference used to
// report status for a BackendTrafficPolicy that could not be attached to any target.
// When the policy uses an explicit targetRef/targetRefs, the (unresolved) target is
// used as the ancestor so the status clearly points at the missing object. When the
// policy only uses targetSelectors, which name no specific object, the policy itself
// is used as the ancestor.
func ancestorRefForUnattachedBackendTrafficPolicy(policy *egv1a1.BackendTrafficPolicy) gwapiv1.ParentReference {
if refs := policy.Spec.GetTargetRefs(); len(refs) > 0 {
ref := refs[0]
group := ref.Group
kind := ref.Kind
ns := gwapiv1.Namespace(policy.Namespace)
return gwapiv1.ParentReference{
Group: &group,
Kind: &kind,
Namespace: &ns,
Name: ref.Name,
SectionName: ref.SectionName,
}
}

ns := gwapiv1.Namespace(policy.Namespace)
return gwapiv1.ParentReference{
Group: GroupPtr(egv1a1.GroupName),
Kind: KindPtr(egv1a1.KindBackendTrafficPolicy),
Namespace: &ns,
Name: gwapiv1.ObjectName(policy.Name),
}
}

// backendTrafficPolicyTargetNotFoundMessage returns a human-readable message explaining
// why an unattached BackendTrafficPolicy resolved to zero targets.
func backendTrafficPolicyTargetNotFoundMessage(policy *egv1a1.BackendTrafficPolicy) string {
if refs := policy.Spec.GetTargetRefs(); len(refs) > 0 {
ref := refs[0]
return fmt.Sprintf("The BackendTrafficPolicy target %s %s/%s was not found",
ref.Kind, policy.Namespace, ref.Name)
}
return "The BackendTrafficPolicy targetSelectors did not match any target"
}

func (t *Translator) buildGatewayPolicyMap(
backendTrafficPolicies []*egv1a1.BackendTrafficPolicy,
gateways []*GatewayContext,
Expand Down Expand Up @@ -431,7 +520,7 @@ func (t *Translator) processBackendTrafficPolicyForRoute(
gatewayPolicyMap map[NamespacedNameWithSection]*egv1a1.BackendTrafficPolicy,
policy *egv1a1.BackendTrafficPolicy,
currTarget policyTargetReferenceWithSectionName,
) {
) bool {
var (
targetedRoute RouteContext
resolveErr *status.PolicyResolveError
Expand All @@ -443,7 +532,7 @@ func (t *Translator) processBackendTrafficPolicyForRoute(
// reconciled by multiple controllers. And the other controller may
// have the target route.
if targetedRoute == nil {
return
return false
}

// Find the Gateway that the route belongs to and add it to the
Expand Down Expand Up @@ -493,7 +582,7 @@ func (t *Translator) processBackendTrafficPolicyForRoute(
policy.Generation,
resolveErr,
)
return
return true
}

if policy.Spec.MergeType == nil {
Expand Down Expand Up @@ -595,7 +684,7 @@ func (t *Translator) processBackendTrafficPolicyForRoute(
// Check if this policy is overridden by other policies targeting at route rule levels
// If policy target is route rule, we can skip the check
if currTarget.SectionName != nil {
return
return true
}

key := policyTargetRouteKey{
Expand All @@ -615,6 +704,8 @@ func (t *Translator) processBackendTrafficPolicyForRoute(
policy.Generation,
)
}

return true
}

func (t *Translator) processBackendTrafficPolicyForGateway(
Expand All @@ -624,7 +715,7 @@ func (t *Translator) processBackendTrafficPolicyForGateway(
gatewayPolicyMergedMap *GatewayPolicyRouteMap,
policy *egv1a1.BackendTrafficPolicy,
currTarget policyTargetReferenceWithSectionName,
) {
) bool {
var (
targetedGateway *GatewayContext
resolveErr *status.PolicyResolveError
Expand All @@ -633,7 +724,7 @@ func (t *Translator) processBackendTrafficPolicyForGateway(
// Negative statuses have already been assigned so it's safe to skip
targetedGateway, resolveErr = resolveBackendTrafficPolicyGatewayTargetRef(currTarget, gatewayMap)
if targetedGateway == nil {
return
return false
}

// Find its ancestor reference by resolved gateway, even with resolve error
Expand All @@ -648,7 +739,7 @@ func (t *Translator) processBackendTrafficPolicyForGateway(
policy.Generation,
resolveErr,
)
return
return true
}

// Set conditions for translation error if it got any
Expand Down Expand Up @@ -694,6 +785,8 @@ func (t *Translator) processBackendTrafficPolicyForGateway(
policy.Generation,
)
}

return true
}

func resolveBackendTrafficPolicyGatewayTargetRef(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: listener-1
protocol: HTTP
port: 8081
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1
labels:
app: real-label
spec:
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: listener-1
rules:
- matches:
- path:
value: "/foo"
backendRefs:
- name: service-1
port: 8080
backendTrafficPolicies:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: default
name: policy-with-unmatched-selector
spec:
targetSelectors:
- group: gateway.networking.k8s.io
kind: HTTPRoute
matchLabels:
app: no-such-label
timeout:
tcp:
connectTimeout: 15s
Loading