backup: Call the pg_dump binary whose version we are running.

`/usr/bin/pg_dump` on Ubuntu and Debian is actually a tool which
attempts to choose which `pg_dump` binary from all of the
`postgresql-client-*` packages that are installed to run.  However,
its logic is confused by passing empty `--host` and `--port` options
-- instead of looking at the running server instance on the server, it
instead assumes some remote host and chooses the highest versioned
`pg_dump` which is installed.

Because Zulip writes binary database backups, they are sensitive to
the version of the client `pg_dump` binary is used -- and the output
may not be backwards compatible.  Using a PostgreSQL 16 `pg_dump`
writes archive format 1.15, which cannot be read by a PostgreSQL 15
`pg_restore`.

Zulip does not currently support PostgreSQL 16 as a server.  This
means that backups on servers with `postgresql-client-16` installed
did not successfully round-trip Zulip backups -- their backups are
written using PostgreSQL 16's client, and the `pg_restore` chosen on
restore was correctly chosen as the one whose version matched the
server (PostgreSQL 15 or below), and thus did not understand the new
archive format.

Existing `./manage.py backups` taken since `postgresql-client-16` were
installed are thus not directly usable by the `restore-backup` script.
They are not useless, however, since they can theoretically be
converted into a format readable by PostgreSQL 15 -- by importing into
a PostgreSQL 16 instance, and re-dumping with a PostgreSQL 15
`pg_dump`.

Fix this issue by hard-coding path to the binary whose version matches
the version of the server we are connected to.  This may theoretically
fail if we are connected to a remote PostgreSQL instance and we do not
have a `postgresql-client` package locally installed which matches the
remote PostgreSQL server's version.  However, choosing a matching
version is the only way to ensure that it will be able to be imported
cleanly -- and it is preferable that we fail the backup process rather
than write backups that we cannot easily restore from.

Fixes: #27160.
This commit is contained in:
Alex Vandiver 2023-10-10 20:53:31 +00:00 committed by Tim Abbott
parent 9d46b41e25
commit 3a8b4b0205
1 changed files with 2 additions and 1 deletions

View File

@ -52,6 +52,7 @@ class Command(ZulipBaseCommand):
with open(os.path.join(tmp, "zulip-backup", "postgres-version"), "w") as f: with open(os.path.join(tmp, "zulip-backup", "postgres-version"), "w") as f:
pg_server_version = connection.cursor().connection.server_version pg_server_version = connection.cursor().connection.server_version
major_pg_version = pg_server_version // 10000
print(pg_server_version, file=f) print(pg_server_version, file=f)
members.append("zulip-backup/postgres-version") members.append("zulip-backup/postgres-version")
@ -68,7 +69,7 @@ class Command(ZulipBaseCommand):
if not options["skip_db"]: if not options["skip_db"]:
pg_dump_command = [ pg_dump_command = [
"pg_dump", f"/usr/lib/postgresql/{major_pg_version}/bin/pg_dump",
"--format=directory", "--format=directory",
"--file=" + os.path.join(tmp, "zulip-backup", "database"), "--file=" + os.path.join(tmp, "zulip-backup", "database"),
"--host=" + settings.DATABASES["default"]["HOST"], "--host=" + settings.DATABASES["default"]["HOST"],