Skip to content

Queue a sync when a cluster's controller ID changes to this operator - #3195

Open
omkar619-dev wants to merge 1 commit into
zalando:masterfrom
omkar619-dev:fix/controller-id-change-skips-update
Open

omkar619-dev wants to merge 1 commit into
zalando:masterfrom
omkar619-dev:fix/controller-id-change-skips-update

Conversation

@omkar619-dev

@omkar619-dev omkar619-dev commented Oct 2, 2026 •

Copy link
Copy Markdown

Changing a cluster's acid.zalan.do/controller annotation to this operator's ID queues nothing at all, so the cluster is only picked up by the next resync.

postgresqlCheck returns nil when hasOwnership fails, and postgresqlUpdate only acts when both manifests pass it:

pgOld := c.postgresqlCheck(prev)
pgNew := c.postgresqlCheck(cur)
if pgOld != nil && pgNew != nil {
    ...
}

On adoption the previous manifest still names the other controller, so pgOld is nil, there is no else, and the function returns silently.

The change

An explicit branch for that case, queueing a sync:

if pgOld == nil && pgNew != nil {
    c.queueClusterEvent(nil, pgNew, EventSync)
    return
}

Sync rather than update, and a nil old spec, because this is the shape the surrounding code already uses: queueClusterEvent's nil-old-spec branch is commented // add, sync, Clone() returns nil for a nil receiver, and postgresqlAdd already calls queueClusterEvent(nil, pg, EventAdd). There is also no old spec worth diffing here — the Kubernetes objects may have been created by another operator, so reconciling to the desired state is the only thing that makes sense.

This does not close the race @baarde raised on the issue: we cannot know whether the previous operator has finished with the cluster. Resync has exactly the same exposure today, so this narrows the window rather than opening a new one.

Deliberately not included

The mirror case is broken in the same way. When a cluster moves away (pgOld != nil, pgNew == nil) the missing else means this operator never sees the handover and keeps whatever it had until the next resync. I left it out, because stopping management is a different decision from starting it, and TestPostgresqlUpdateQueuesNothingWhenOwnershipIsLost pins the current behaviour so it reads as a choice rather than an oversight. Happy to handle it here if you would rather the two were symmetric.

Tests

Three cases in postgresql_test.go, with a small helper that sets up a single-worker event queue — initController builds those in the real operator, but it also reads infrastructure roles and starts the API server.

  • TestPostgresqlUpdateQueuesSyncWhenClusterIsAdopted asserts one SYNC event with a nil OldSpec. Without the branch above it fails with queued 0, which is the reported symptom.
  • TestPostgresqlUpdateStillQueuesUpdateForOwnedCluster guards the ordinary path, since the new branch adds an early return in front of it.
  • TestPostgresqlUpdateQueuesNothingWhenOwnershipIsLost pins the mirror case described above.

go test ./pkg/controller/ passes in full, including the pre-existing TestControllerOwnershipOnPostgresql.

Closes #3151

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Operator skips cluster update when changing controller ID

1 participant