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.

Clusterkind — single node, Kubernetes v1.35.0 (arm64)
Operatorbuilt from this PR branch and deployed on the cluster
Workload under testDruid CR tiny-cluster → router node (kind: Deployment) → druid-tiny-cluster-routers
CRDdruids.druid.apache.org (regenerated to include the new field)

Result matrix

#AssertionExpectedObserved
1CRD exposes revisionHistoryLimit; the value set on the CR is accepted (not pruned)field present; CR stores the valuepresent; CR stored 4PASS
2Field unset on the node spec → Kubernetes default preserved10Deployment revisionHistoryLimit = 10PASS
3Set revisionHistoryLimit: 4 on the node spec → reflected on the generated DeploymentDeployment = 410 → 4 within ~3sPASS
4Repeated rollouts → retained ReplicaSets garbage-collected to the configured limittotal ≤ 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.