Configurable revisionHistoryLimit — local kind validation PASS
End-to-end validation for apache/druid-operator#24 — exposing an optional revisionHistoryLimit on the Druid node spec and wiring it into the generated Deployment and StatefulSet.
Cluster
kind — single node, Kubernetes v1.35.0 (arm64)
Operator
built from this PR branch and deployed on the cluster
druids.druid.apache.org (regenerated to include the new field)
Result matrix
#
Assertion
Expected
Observed
1
CRD exposes revisionHistoryLimit; the value set on the CR is accepted (not pruned)
field present; CR stores the value
present; CR stored 4
PASS
2
Field unset on the node spec → Kubernetes default preserved
10
Deployment revisionHistoryLimit = 10
PASS
3
Set revisionHistoryLimit: 4 on the node spec → reflected on the generated Deployment
Deployment = 4
10 → 4 within ~3s
PASS
4
Repeated rollouts → retained ReplicaSets garbage-collected to the configured limit
total ≤ 5 (1 active + 4 retained)
capped at 5 across 6 rollouts (vs. climbing toward 10)
PASS
1 & 2 & 3 — the field is configurable and CR-driven
$ kubectl get crd druids.druid.apache.org -o yaml | grep -c revisionHistoryLimit
2 # field present in the CRD schema
# Field UNSET on the node spec -> Kubernetes default (10)
$ kubectl -n druid get deploy druid-tiny-cluster-routers -o jsonpath='{.spec.revisionHistoryLimit}'
10
# Set it on the node spec
$ kubectl -n druid patch druid tiny-cluster --type merge \
-p '{"spec":{"nodes":{"routers":{"revisionHistoryLimit":4}}}}'
druid.druid.apache.org/tiny-cluster patched
$ kubectl -n druid get druid tiny-cluster -o jsonpath='{.spec.nodes.routers.revisionHistoryLimit}'
4 # stored on the CR (not pruned)
# Operator reconciles -> generated Deployment carries the value
$ kubectl -n druid get deploy druid-tiny-cluster-routers -o jsonpath='{.spec.revisionHistoryLimit}'
4 # 10 -> 4 within ~3s
4 — Kubernetes garbage-collects superseded ReplicaSets to the limit
# Roll the router repeatedly (each change cuts a new ReplicaSet); revisionHistoryLimit = 4
starting router ReplicaSets = 3 (limit 4 -> expect cap at 5 = 1 active + 4 retained)
rollout 1: total router RS = 4
rollout 2: total router RS = 5
rollout 3: total router RS = 5
rollout 4: total router RS = 5
rollout 5: total router RS = 5
rollout 6: total router RS = 5 # capped at the limit; does NOT climb toward the default of 10
$ kubectl -n druid get rs -o custom-columns=NAME:.metadata.name,DESIRED:.spec.replicas,CURRENT:.status.replicas | grep routers
druid-tiny-cluster-routers-645f9b5c57 0 0 # retained
druid-tiny-cluster-routers-6489dd7dbb 0 0 # retained
druid-tiny-cluster-routers-697485cdb8 0 0 # retained
druid-tiny-cluster-routers-7db87b4dc4 1 1 # active
druid-tiny-cluster-routers-b75fbd9d5 0 0 # retained
# 1 active + 4 retained = revisionHistoryLimit (4) + 1
Conclusion
The operator reads spec.nodes.<node>.revisionHistoryLimit from the Druid CR and applies it to the generated workload's spec.revisionHistoryLimit. When unset, the Kubernetes default (10) is preserved; when set, the value is honored within seconds, and Kubernetes then garbage-collects superseded ReplicaSets (for Deployment node types) down to that limit. This bounds the retained pod-template history so superseded container image tags do not linger in image inventories and scanners. Backward-compatible (opt-in, nil → default), and validated alongside the PR's unit tests covering set / unset on both Deployment and StatefulSet node types.