pgroonga: Run upgrade SQL when pgroonga package is updated.

Updating the pgroonga package is not sufficient to upgrade the
extension in PostgreSQL -- an `ALTER EXTENSION pgroonga UPDATE` must
explicitly be run[^1].  Failure to do so can lead to unexpected behavior,
including crashes of PostgreSQL.

Expand on the existing `pgroonga_setup.sql.applied` file, to track
which version of the PostgreSQL extension has been configured.  If the
file exists but is empty, we run `ALTER EXTENSION pgroonga UPDATE`
regardless -- if it is a no-op, it still succeeds with a `NOTICE`:

```
zulip=# ALTER EXTENSION pgroonga UPDATE;
NOTICE:  version "3.0.8" of extension "pgroonga" is already installed
ALTER EXTENSION
```

The simple `ALTER EXTENSION` is sufficient for the
backwards-compatible case[^1] -- which, for our usage, is every
upgrade since 0.9 -> 1.0.  Since version 1.0 was released in 2015,
before pgroonga support was added to Zulip in 2016, we can assume for
the moment that all pgroonga upgrades are backwards-compatible, and
not bother regenerating indexes.

Fixes: #25989.

[^1]: https://pgroonga.github.io/upgrade/
This commit is contained in:
Alex Vandiver 2023-06-21 21:53:00 +00:00 committed by Tim Abbott
parent dc2726c814
commit c8ec3dfcf6
3 changed files with 46 additions and 10 deletions

View File

@ -83,18 +83,20 @@ class zulip::postgresql_base {
} }
package{"${postgresql}-pgdg-pgroonga": package{"${postgresql}-pgdg-pgroonga":
ensure => installed, ensure => latest,
require => [Package[$postgresql], require => [
Exec[$setup_system_deps]], Package[$postgresql],
Exec[$setup_system_deps]
],
} }
exec { 'pgroonga-config':
$dbname = zulipconf('postgresql', 'database_name', 'zulip')
exec{'create_pgroonga_extension':
require => Package["${postgresql}-pgdg-pgroonga"], require => Package["${postgresql}-pgdg-pgroonga"],
# lint:ignore:140chars unless => @("EOT"/$),
command => "bash -c 'echo \"CREATE EXTENSION PGROONGA\" | su postgres -c \"psql -v ON_ERROR_STOP=1 ${dbname}\" && touch ${pgroonga_setup_sql_path}.applied'", test -f ${pgroonga_setup_sql_path}.applied &&
# lint:endignore test "$(dpkg-query --show --showformat='\${Version}' "${postgresql}-pgdg-pgroonga")" \
creates => "${pgroonga_setup_sql_path}.applied", = "$(cat ${pgroonga_setup_sql_path}.applied)"
| EOT
command => "${::zulip_scripts_path}/setup/pgroonga-config ${postgresql_sharedir}",
} }
} }

View File

@ -28,6 +28,7 @@ from scripts.lib.zulip_tools import (
DEPLOYMENTS_DIR, DEPLOYMENTS_DIR,
assert_running_as_root, assert_running_as_root,
get_config, get_config,
get_config_bool,
get_config_file, get_config_file,
get_zulip_pwent, get_zulip_pwent,
listening_publicly, listening_publicly,
@ -205,6 +206,7 @@ def shutdown_server() -> None:
# postgresql.version is required for database servers, but wasn't # postgresql.version is required for database servers, but wasn't
# previously; fill it in based on what the OS provides. # previously; fill it in based on what the OS provides.
postgresql_version = None
if os.path.exists("/etc/init.d/postgresql"): if os.path.exists("/etc/init.d/postgresql"):
postgresql_version = get_config(config_file, "postgresql", "version") postgresql_version = get_config(config_file, "postgresql", "version")
django_pg_version = subprocess.check_output( django_pg_version = subprocess.check_output(
@ -269,9 +271,20 @@ if glob.glob("/usr/share/postgresql/*/extension/tsearch_extras.control"):
subprocess.check_call(["apt-get", "remove", "-y", "postgresql-*-tsearch-extras"]) subprocess.check_call(["apt-get", "remove", "-y", "postgresql-*-tsearch-extras"])
if not (minimal_change or args.skip_puppet): if not (minimal_change or args.skip_puppet):
# We need to temporarily hold pgroonga, if installed -- upgrading
# it without running the appropriate upgrade SQL can cause
# PostgreSQL to crash
if postgresql_version is not None and get_config_bool(config_file, "machine", "pgroonga"):
subprocess.check_call(
["apt-mark", "hold", f"postgresql-{postgresql_version}-pgdg-pgroonga"]
)
logging.info("Upgrading system packages...") logging.info("Upgrading system packages...")
subprocess.check_call(["apt-get", "update"]) subprocess.check_call(["apt-get", "update"])
subprocess.check_call(["apt-get", "-y", "--with-new-pkgs", "upgrade"]) subprocess.check_call(["apt-get", "-y", "--with-new-pkgs", "upgrade"])
if postgresql_version is not None and get_config_bool(config_file, "machine", "pgroonga"):
subprocess.check_call(
["apt-mark", "unhold", f"postgresql-{postgresql_version}-pgdg-pgroonga"]
)
# To bootstrap zulip-puppet-apply, we need to install the system yaml # To bootstrap zulip-puppet-apply, we need to install the system yaml
# package; new installs get this, but old installs may not have it. # package; new installs get this, but old installs may not have it.

21
scripts/setup/pgroonga-config Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -eux
dbversion=$(crudini --get /etc/zulip/zulip.conf postgresql version)
dbname=$(crudini --get /etc/zulip/zulip.conf postgresql database_name 2>/dev/null || echo zulip)
dbuser=$(crudini --get /etc/zulip/zulip.conf postgresql database_user 2>/dev/null || echo zulip)
sharedir="${1:-/usr/share/postgresql/$dbversion}"
applied_file="$sharedir/pgroonga_setup.sql.applied"
installed_version=$(dpkg-query --show --showformat='${Version}' "postgresql-$dbversion-pgdg-pgroonga")
if [ ! -f "$applied_file" ]; then
sql="CREATE EXTENSION PGROONGA; GRANT USAGE ON SCHEMA pgroonga TO $dbuser"
else
sql="ALTER EXTENSION pgroonga UPDATE"
fi
echo "$sql" | su postgres -c "psql -v ON_ERROR_STOP=1 $dbname"
echo "$installed_version" >"$applied_file"