From 318b4194c785bb90065deac5a970260088f915ac Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Mon, 22 Sep 2025 16:33:57 -0500 Subject: [PATCH] Proceed with major upgrade when data directory lacks checksums This can happen when a data directory is imported from an external system. Issue: PGO-619 --- internal/controller/pgupgrade/jobs.go | 22 +++++++++++++++++++++- internal/controller/pgupgrade/jobs_test.go | 7 +++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/internal/controller/pgupgrade/jobs.go b/internal/controller/pgupgrade/jobs.go index 9dbf76ea5..6f6379b8e 100644 --- a/internal/controller/pgupgrade/jobs.go +++ b/internal/controller/pgupgrade/jobs.go @@ -117,8 +117,28 @@ func upgradeCommand(spec *v1beta1.PGUpgradeSettings, fetchKeyCommand string) []s // steps used and command flag specifics can be found in the documentation: // - https://www.postgresql.org/docs/current/pgupgrade.html + // Examine the old data directory. + `control=$(LC_ALL=C PGDATA="${old_data}" "${old_bin}/pg_controldata")`, + `read -r checksums <<< "${control##*page checksum version:}"`, + + // Data checksums on the old and new data directories must match. + // Configuring these checksums depends on the version of initdb: + // + // - PostgreSQL v17 and earlier: disabled by default, enable with "--data-checksums" + // - PostgreSQL v18: enabled by default, enable with "--data-checksums", disable with "--no-data-checksums" + // + // https://www.postgresql.org/docs/release/18#RELEASE-18-MIGRATION + // + // Data page checksum version zero means checksums are disabled. + // Produce an initdb argument that enables or disables data checksums. + // + // https://git.postgresql.org/gitweb/?p=postgresql.git;hb=refs/tags/REL_11_0;f=src/bin/pg_verify_checksums/pg_verify_checksums.c#l303 + // https://git.postgresql.org/gitweb/?p=postgresql.git;hb=refs/tags/REL_12_0;f=src/bin/pg_checksums/pg_checksums.c#l523 + // https://git.postgresql.org/gitweb/?p=postgresql.git;hb=refs/tags/REL_18_0;f=src/bin/pg_checksums/pg_checksums.c#l571 + `checksums=$(if [[ "${checksums}" -gt 0 ]]; then echo '--data-checksums'; elif [[ "${new_version}" -ge 18 ]]; then echo '--no-data-checksums'; fi)`, + `section 'Step 3 of 7: Initializing new data directory...'`, - `PGDATA="${new_data}" "${new_bin}/initdb" --allow-group-access --data-checksums` + argEncryptionKeyCommand, + `PGDATA="${new_data}" "${new_bin}/initdb" --allow-group-access ${checksums}` + argEncryptionKeyCommand, // Read the configured value then quote it; every single-quote U+0027 is replaced by two. // diff --git a/internal/controller/pgupgrade/jobs_test.go b/internal/controller/pgupgrade/jobs_test.go index 9c9e00063..cd96a4a3e 100644 --- a/internal/controller/pgupgrade/jobs_test.go +++ b/internal/controller/pgupgrade/jobs_test.go @@ -222,8 +222,11 @@ spec: (set -x && [[ "$("${old_bin}/postgres" --version)" =~ ") ${old_version}"($|[^0-9]) ]]) (set -x && [[ "$("${new_bin}/initdb" --version)" =~ ") ${new_version}"($|[^0-9]) ]]) cd "${data_volume}" + control=$(LC_ALL=C PGDATA="${old_data}" "${old_bin}/pg_controldata") + read -r checksums <<< "${control##*page checksum version:}" + checksums=$(if [[ "${checksums}" -gt 0 ]]; then echo '--data-checksums'; elif [[ "${new_version}" -ge 18 ]]; then echo '--no-data-checksums'; fi) section 'Step 3 of 7: Initializing new data directory...' - PGDATA="${new_data}" "${new_bin}/initdb" --allow-group-access --data-checksums + PGDATA="${new_data}" "${new_bin}/initdb" --allow-group-access ${checksums} section 'Step 4 of 7: Copying shared_preload_libraries parameter...' value=$(LC_ALL=C PGDATA="${old_data}" "${old_bin}/postgres" -C shared_preload_libraries) echo >> "${new_data}/postgresql.conf" "shared_preload_libraries = '${value//$'\''/$'\'\''}'" @@ -272,7 +275,7 @@ status: {} tdeJob := reconciler.generateUpgradeJob(ctx, upgrade, startup, "echo testKey") assert.Assert(t, cmp.MarshalContains(tdeJob, - `PGDATA="${new_data}" "${new_bin}/initdb" --allow-group-access --data-checksums --encryption-key-command='echo testKey'`)) + `PGDATA="${new_data}" "${new_bin}/initdb" --allow-group-access ${checksums} --encryption-key-command='echo testKey'`)) } func TestGenerateRemoveDataJob(t *testing.T) {