Skip to content

feat(agent): add optional PodDisruptionBudget to Agent CRD - #2393

Open
anthonyhaussman wants to merge 2 commits into
kagent-dev:mainfrom
anthonyhaussman:feat/agent-poddisruptionbudget
Open

feat(agent): add optional PodDisruptionBudget to Agent CRD#2393
anthonyhaussman wants to merge 2 commits into
kagent-dev:mainfrom
anthonyhaussman:feat/agent-poddisruptionbudget

Conversation

@anthonyhaussman

@anthonyhaussman anthonyhaussman commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

What

Adds an optional podDisruptionBudget to SharedDeploymentSpec, so Declarative, BYO, and SandboxAgent all inherit it.

spec:
  declarative:
    deployment:
      replicas: 3
      podDisruptionBudget:
        maxUnavailable: 1
        unhealthyPodEvictionPolicy: AlwaysAllow

Presence of the block enables the budget. Removing it prunes the object rather than orphaning it, which is why policyv1.PodDisruptionBudget is registered unconditionally in GetOwnedResourceTypes (that list drives the prune pass, not just the watches).

No effect in Sandbox workload mode, where no Deployment is created.

Two things worth reviewer attention

1. The policy API group needed an explicit RBAC grant

The writer and getter roles wildcard "", apps, batch, and gateway.networking.k8s.io. None of those cover policy, so without the new blocks in writer-role.yaml and getter-role.yaml the controller could not have created the budget at all.

2. MutateFuncFor needed a dedicated case, not the mergo fallback

minAvailable and maxUnavailable are mutually exclusive and the API server rejects a spec setting both. The generic mergeWithOverride path cannot express the transition: mergo only writes keys present in the desired object, so the field being switched away from survives and the update fails.

This was verified rather than assumed. Removing the new case makes three tests in mutate_test.go fail.

Validation

CEL enforces the XOR at admission time, mirroring the existing serviceAccountName / serviceAccountConfig marker on the same struct:

exactly one of minAvailable or maxUnavailable must be set
rule: has(self.minAvailable) != has(self.maxUnavailable)

Testing

  • pod_disruption_budget_test.go: 9 translator tests covering both resolve paths, omission, percentage thresholds, eviction policy, owned-type registration, and no aliasing of the agent spec
  • mutate_test.go: 5 tests, 3 of which fail without the new mutate case
  • Golden fixtures for the Declarative and BYO paths. Only the two new outputs were created; no existing golden changed, confirming the change is purely additive
  • make -C go lint: 0 issues
  • make controller-manifests is idempotent, so manifests-check passes

The strongest assertion is that the budget selector deep-equals the Deployment selector. A PDB whose selector does not match protects nothing while still looking correct in kubectl get pdb.

New podDisruptionBudget field on SharedDeploymentSpec, so
Declarative, BYO and SandboxAgent inherit it. Presence of the
block enables the budget; removing it prunes the object.

The policy API group is not covered by the core/apps/batch/gateway
wildcards in the writer and getter roles, so both need an explicit
poddisruptionbudgets grant or the controller cannot manage one.

MutateFuncFor needs a dedicated case rather than the mergo
fallback: minAvailable and maxUnavailable are mutually exclusive,
and mergo cannot unset the field being switched away from, which
leaves a spec the API server rejects for setting both.

Assisted-by: Claude Opus 5
Signed-off-by: Anthony Hausman <ahausman@tf1.fr>
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Aug 4, 2026
@anthonyhaussman
anthonyhaussman marked this pull request as ready for review August 4, 2026 17:58
@anthonyhaussman
anthonyhaussman requested a review from a team as a code owner August 4, 2026 17:58
…gent-poddisruptionbudget

Signed-off-by: Anthony Hausman <ahausman@tf1.fr>

# Conflicts:
#	go/core/internal/controller/translator/agent/deployments.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant