Files
cozystack/internal/backupcontroller/bootstrap_disable_patch_test.go
Alexey Artamonov 70dcd9daed fix(backups): let a restored Postgres app converge its credentials
A restore sets bootstrap.enabled on the target app, which skips the
init-job, so the recovered roles keep the source's password hashes while
the target's credentials Secret holds generated ones and every
application login fails. Once recovery converges, the driver records
RecoveryConverged and then clears bootstrap.enabled, so the next
HelmRelease reconcile runs the init-job and applies the passwords. Ready
carries RestoreCompletedCredentialsPending and an Event says the
convergence is still pending. A clear that keeps failing is retried
under BootstrapDisablePending within a fixed grace window after
convergence and then fails the restore. bootstrap.enabled is serialized
without omitempty so the patch sends false instead of dropping the key.

Running the init-job on a restored cluster exposes its delete pass to a
catalog the spec does not describe: the driver sets spec.databases to
the Backup's snapshot, but recovery replays WAL past it, so a database
created after the Backup comes back still marked as managed and would
be dropped with its data. The first run after a restore, told apart by
the per-RestoreJob bootstrap.newServerName that the cluster has not yet
recorded, releases such a database and its roles from management
instead, and the run records the value once every pass has succeeded.

Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io>
2026-09-24 18:11:07 +03:00

42 lines
1.6 KiB
Go

package backupcontroller
import (
"bytes"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/cozystack/cozystack/internal/backupcontroller/postgresapp"
)
// disablePostgresAppBootstrap flips Bootstrap.Enabled from true to false through
// a client.MergeFrom merge patch. If the field keeps `json:"...,omitempty"`, the
// false zero value is dropped from the patched object, so the computed merge
// patch DELETES the key (`{"enabled":null}`) instead of setting it false — the
// exact trap the sibling Backup.UseSystemBucket field carries a comment against.
// It only converges today because the chart default for bootstrap.enabled is
// false; if that ever changes the restore reports Succeeded while recovery stays
// wedged. Pin that the wire patch sets enabled:false. Re-adding omitempty to the
// Enabled field turns this red.
func TestDisableBootstrapMergePatchSetsEnabledFalse(t *testing.T) {
app := &postgresapp.Postgres{
ObjectMeta: metav1.ObjectMeta{Name: "pg-target", Namespace: "tenant-root"},
}
app.Spec.Bootstrap.Enabled = true
patched := app.DeepCopy()
patched.Spec.Bootstrap.Enabled = false
data, err := client.MergeFrom(app).Data(patched)
if err != nil {
t.Fatalf("build merge patch: %v", err)
}
if bytes.Contains(data, []byte(`"enabled":null`)) {
t.Fatalf("merge patch deletes the enabled key instead of setting false; the server would fall back to a default: %s", data)
}
if !bytes.Contains(data, []byte(`"enabled":false`)) {
t.Fatalf("merge patch must carry enabled:false so the server clears bootstrap; got: %s", data)
}
}