envoyproxy / envoyproxy/gateway

BackendTrafficPolicy status becomes stale when targetSelectors change from matching routes to matching no routes

Open
#8,927 3 comments 0 reactions 0 assignees View on GitHub
stale
Dominant language
Go
Stars
3k
Forks
864
Avg merge
2d 2h
Merged PRs (30d)
140

Description

### Description

A `BackendTrafficPolicy` using `targetSelectors` can become stale in status when the selector is changed from matching an existing route to matching no routes.

After the selector update:
- the policy `metadata.generation` increments
- status still shows the old `Accepted=True` condition
- `observedGeneration` remains stale
- no condition indicates that the selector now matches zero resources

This makes the policy appear attached/valid even after it no longer selects any targets.

### Environment

- Envoy Gateway repo: `main`
- Reproduced at commit: `69b1dde32fdb44cca7eb3ee880064e36f90492f4`

### Reproducer

1. Install Envoy Gateway from current `main`
2. Apply the quickstart example
3. Label the quickstart `HTTPRoute`
4. Create a `BackendTrafficPolicy` using `targetSelectors` that matches that route
5. Update the same policy so the selector matches no routes

### Route setup

Label the quickstart route:

```bash
kubectl -n default label httproute backend app=selector-demo --overwrite
```

### Initial policy that matches

```yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: quickstart-btp-selector-flip
namespace: default
spec:
targetSelectors:
- group: gateway.networking.k8s.io
kind: HTTPRoute
matchLabels:
app: selector-demo
retry:
numRetries: 3
perRetry:
backOff:
baseInterval: 100ms
maxInterval: 1s
timeout: 250ms
retryOn:
triggers:
- 5xx
- gateway-error
- connect-failure
```

Observed status after create:

```yaml
status:
ancestors:
- ancestorRef:
group: gateway.networking.k8s.io
kind: Gateway
name: eg
namespace: default
conditions:
- type: Accepted
status: "True"
reason: Accepted
message: Policy has been accepted.
observedGeneration: 1
```

### Updated policy that matches nothing

```yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: quickstart-btp-selector-flip
namespace: default
spec:
targetSelectors:
- group: gateway.networking.k8s.io
kind: HTTPRoute
matchLabels:
app: selector-demo-no-match
retry:
numRetries: 3
perRetry:
backOff:
baseInterval: 100ms
maxInterval: 1s
timeout: 250ms
retryOn:
triggers:
- 5xx
- gateway-error
- connect-failure
```

The route labels remain:

```bash
kubectl -n default get httproute backend --show-labels
# NAME HOSTNAMES AGE LABELS
# backend ["www.example.com"] ... app=selector-demo
```

So the updated selector no longer matches any route.

### Observed behavior

After the update:
- `metadata.generation` increments from `1` to `2`
- status still shows:
- `Accepted=True`
- `observedGeneration=1`
- no condition indicates:
- zero selected resources
- detachment / unattached policy
- selector resolution result for the new generation

Example:

```yaml
metadata:
generation: 2
status:
ancestors:
- ancestorRef:
group: gateway.networking.k8s.io
kind: Gateway
name: eg
namespace: default
conditions:
- type: Accepted
status: "True"
reason: Accepted
message: Policy has been accepted.
observedGeneration: 1
```

### Expected behavior

When a selector-based policy changes from matching resources to matching none, I’d expect status to reflect the new state, for example by:
- updating `observedGeneration` to the latest generation
- surfacing a condition that zero resources are selected / attached
- or otherwise making it clear that the policy is no longer effectively attached

### Why this matters

This is misleading operationally:
- the initial status looks correct when the selector matches
- after the update, the policy still appears accepted and attached
- but it no longer selects any resources
- stale `observedGeneration` makes it unclear whether reconciliation completed

This makes selector-based policy debugging harder and can hide unintended detachments.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.