Skip to content

Commit cdbdad4

Browse files
committed
Look in more directories for upgrade binaries
This makes upgrades compatible with images from other distros. Issue: PGO-864
1 parent 2a94e25 commit cdbdad4

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

internal/controller/pgupgrade/jobs.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/crunchydata/postgres-operator/internal/feature"
2222
"github.com/crunchydata/postgres-operator/internal/initialize"
2323
"github.com/crunchydata/postgres-operator/internal/naming"
24+
"github.com/crunchydata/postgres-operator/internal/postgres"
2425
"github.com/crunchydata/postgres-operator/internal/shell"
2526
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
2627
)
@@ -80,11 +81,14 @@ func upgradeCommand(spec *v1beta1.PGUpgradeSettings, fetchKeyCommand string) []s
8081
// - https://cwrap.org/nss_wrapper.html
8182
`export LD_PRELOAD='libnss_wrapper.so' NSS_WRAPPER_GROUP NSS_WRAPPER_PASSWD`,
8283

83-
// Expect Postgres executables at the Red Hat paths.
84+
// Find directories that contain the desired Postgres executables.
85+
`old_bin=$(` + postgres.ShellPath(oldVersion) + ` && command -v postgres)`,
86+
`old_bin="${old_bin%/postgres}"`,
87+
`new_bin=$(` + postgres.ShellPath(newVersion) + ` && command -v initdb)`,
88+
`new_bin="${new_bin%/initdb}"`,
89+
8490
`old_data="${data_volume}/pg${old_version}"`,
8591
`new_data="${data_volume}/pg${new_version}"`,
86-
`old_bin="/usr/pgsql-${old_version}/bin"`,
87-
`new_bin="/usr/pgsql-${new_version}/bin"`,
8892

8993
// Below is the pg_upgrade script used to upgrade a PostgresCluster from
9094
// one major version to another. Additional information concerning the
@@ -243,7 +247,7 @@ func removeDataCommand(upgrade *v1beta1.PGUpgrade) []string {
243247
`delete() (set -x && rm -rf -- "$@")`,
244248

245249
`old_data="${data_volume}/pg${old_version}"`,
246-
`control=$(LC_ALL=C /usr/pgsql-${old_version}/bin/pg_controldata "${old_data}")`,
250+
`control=$(` + postgres.ShellPath(oldVersion) + ` && LC_ALL=C pg_controldata "${old_data}")`,
247251
`read -r state <<< "${control##*cluster state:}"`,
248252

249253
// We expect exactly one state for a replica that has been stopped.

internal/controller/pgupgrade/jobs_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,12 @@ spec:
209209
(sed "/^postgres:x:/ d; /^[^:]*:x:${uid}:/ d" /etc/passwd
210210
echo "postgres:x:${uid}:${gid%% *}::${data_volume}:") > "${NSS_WRAPPER_PASSWD}"
211211
export LD_PRELOAD='libnss_wrapper.so' NSS_WRAPPER_GROUP NSS_WRAPPER_PASSWD
212+
old_bin=$(PATH="/usr/lib/postgresql/19/bin:/usr/libexec/postgresql19:/usr/pgsql-19/bin${PATH+:${PATH}}" && command -v postgres)
213+
old_bin="${old_bin%/postgres}"
214+
new_bin=$(PATH="/usr/lib/postgresql/25/bin:/usr/libexec/postgresql25:/usr/pgsql-25/bin${PATH+:${PATH}}" && command -v initdb)
215+
new_bin="${new_bin%/initdb}"
212216
old_data="${data_volume}/pg${old_version}"
213217
new_data="${data_volume}/pg${new_version}"
214-
old_bin="/usr/pgsql-${old_version}/bin"
215-
new_bin="/usr/pgsql-${new_version}/bin"
216218
cd "${data_volume}" || exit
217219
section 'Initializing new data directory...'
218220
PGDATA="${new_data}" "${new_bin}/initdb" --data-checksums
@@ -347,7 +349,7 @@ spec:
347349
printf 'Removing PostgreSQL %s data...\n\n' "$@"
348350
delete() (set -x && rm -rf -- "$@")
349351
old_data="${data_volume}/pg${old_version}"
350-
control=$(LC_ALL=C /usr/pgsql-${old_version}/bin/pg_controldata "${old_data}")
352+
control=$(PATH="/usr/lib/postgresql/19/bin:/usr/libexec/postgresql19:/usr/pgsql-19/bin${PATH+:${PATH}}" && LC_ALL=C pg_controldata "${old_data}")
351353
read -r state <<< "${control##*cluster state:}"
352354
[[ "${state}" == 'shut down in recovery' ]] || { printf >&2 'Unexpected state! %q\n' "${state}"; exit 1; }
353355
delete "${old_data}/pg_wal/"

internal/postgres/config.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,17 @@ func Environment(cluster *v1beta1.PostgresCluster) []corev1.EnvVar {
264264
}
265265
}
266266

267+
// ShellPath returns a POSIX shell command that prepends typical Postgres executable paths to the PATH variable.
268+
func ShellPath(postgresVersion int32) string {
269+
return fmt.Sprintf(`PATH="`+
270+
strings.Join([]string{
271+
`/usr/lib/postgresql/%[1]d/bin`, // Debian
272+
`/usr/libexec/postgresql%[1]d`, // Alpine
273+
`/usr/pgsql-%[1]d/bin`, // Red Hat
274+
}, ":")+
275+
`${PATH+:${PATH}}"`, postgresVersion)
276+
}
277+
267278
// reloadCommand returns an entrypoint that convinces PostgreSQL to reload
268279
// certificate files when they change. The process will appear as name in `ps`
269280
// and `top`.

internal/postgres/config_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,37 @@ func TestBashSafeLink(t *testing.T) {
547547
})
548548
}
549549

550+
func TestShellPath(t *testing.T) {
551+
t.Parallel()
552+
553+
script := ShellPath(11)
554+
555+
assert.Assert(t, cmp.Contains(script, `/usr/lib/postgresql/11/bin`))
556+
assert.Assert(t, cmp.Contains(script, `/usr/libexec/postgresql11`))
557+
assert.Assert(t, cmp.Contains(script, `/usr/pgsql-11/bin`))
558+
559+
t.Run("ShellCheckPOSIX", func(t *testing.T) {
560+
shellcheck := require.ShellCheck(t)
561+
562+
dir := t.TempDir()
563+
file := filepath.Join(dir, "script.sh")
564+
assert.NilError(t, os.WriteFile(file, []byte(script), 0o600))
565+
566+
// Expect ShellCheck for "sh" to be happy.
567+
// - https://www.shellcheck.net/wiki/SC2148
568+
cmd := exec.CommandContext(t.Context(), shellcheck, "--enable=all", "--shell=sh", file)
569+
output, err := cmd.CombinedOutput()
570+
assert.NilError(t, err, "%q\n%s", cmd.Args, output)
571+
})
572+
573+
t.Run("PrettyYAML", func(t *testing.T) {
574+
b, err := yaml.Marshal(script)
575+
assert.NilError(t, err)
576+
assert.Assert(t, !strings.Contains(string(b), `\n`), "expected literal flow scalar, got:\n%s", b)
577+
assert.Equal(t, 1, strings.Count(string(b), "\n"), "expected one trailing newline, got: \n%s", b)
578+
})
579+
}
580+
550581
func TestStartupCommand(t *testing.T) {
551582
shellcheck := require.ShellCheck(t)
552583
t.Parallel()

0 commit comments

Comments
 (0)