Files
Myasnikov Daniil 955f7ccaa6 fix(opensearch-operator): use RollingUpdate maxSurge=0 instead of Recreate
#3040 set the single-replica operator Deployment to strategy.type:
Recreate to avoid two uncoordinated managers overlapping during a
rollout while leader election is gated off. That breaks Helm upgrades of
existing releases: the upgrade fails validation immediately,
helm-controller retries it (x19 over 11m in Actions run 29480724982),
and the HelmRelease never becomes Ready:

  Deployment.apps "opensearch-operator-controller-manager" is invalid:
  spec.strategy.rollingUpdate: Forbidden: may not be specified when
  strategy type is Recreate

The trigger is server-side apply. A v1.5.x release shipped no strategy
at all, so the apiserver defaulted spec.strategy.rollingUpdate to
25%/25%, and the helm-controller field manager never owned that block.
helm-controller applies server-side by default (Install.ServerSideApply
defaults to true, Upgrade.ServerSideApply to "auto"; the operator's
package_reconciler.go sets neither), and SSA does not remove a field the
applier never owned merely because the new intent omits it -- so sending
type: Recreate leaves the defaulted rollingUpdate in place and the
apiserver rejects the merged object.

The client-side path is unaffected: DeploymentSpec.Strategy carries
patchStrategy:"retainKeys", so a 3-way merge emits
{"$retainKeys":["type"],"type":"Recreate"} and does clear rollingUpdate.
That is why this surfaces through helm-controller's server-side apply
but not a local 'helm upgrade'.

Keep type: RollingUpdate and set rollingUpdate.maxSurge: 0 /
maxUnavailable: 1 on the single-replica path instead. maxSurge: 0 caps
total pods at replicas, so the old manager is scaled down before the new
one is scaled up, rather than starting a surge pod while the old manager
is still fully live as the default 25% would. It is not Recreate's
exclusivity -- the deployment controller orders the ReplicaSet desired
counts, not the pod lifecycles, so a draining old manager can still
overlap the new pod -- but it keeps the type transition legal on every
apply path, and recovers releases already on an rc build with Recreate.
This matches the existing kube-ovn idiom (central-deploy.yaml).

Also add a 'test' target to the package Makefile:
hack/helm-unit-tests.sh runs a package's suite only when its Makefile
defines one, so tests/leader_election_test.yaml had never executed.

Multi-replica installs keep the default RollingUpdate (leader election
on), unchanged. The change is carried in patches/leaderElection.diff so
it survives 'make update'.

Verified on kind v1.33.1: SSA of the v1.5.x manifest followed by SSA of
the Recreate manifest reproduces the error, while the same pair applied
client-side succeeds; SSA of the maxSurge:0 manifest succeeds both from
v1.5.x and from a live Recreate Deployment.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-07-20 11:33:35 +05:00
..