zulip/scripts/setup/upgrade-postgres

75 lines
2.6 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env bash
set -e
if [ "$EUID" -ne 0 ]; then
echo "Error: This script must be run as root" >&2
exit 1
fi
UPGRADE_TO=${1:-12}
UPGRADE_FROM=$(crudini --get /etc/zulip/zulip.conf postgresql version)
ZULIP_PATH="$(dirname "$0")/../.."
if [ "$UPGRADE_TO" = "$UPGRADE_FROM" ]; then
echo "Already running PostgreSQL $UPGRADE_TO!"
exit 1
fi
set -x
"$ZULIP_PATH"/scripts/lib/setup-apt-repo
apt-get install -y "postgresql-$UPGRADE_TO"
if pg_lsclusters -h | grep -qE "^$UPGRADE_TO\s+main\b"; then
pg_dropcluster "$UPGRADE_TO" main --stop
fi
(
# Two-stage application of puppet; we apply the bare-bones
# postgresql configuration first, so that FTS will be configured
# prior to the pg_upgradecluster.
TEMP_CONF_DIR=$(mktemp -d)
cp /etc/zulip/zulip.conf "$TEMP_CONF_DIR"
ZULIP_CONF="${TEMP_CONF_DIR}/zulip.conf"
crudini --set "$ZULIP_CONF" postgresql version "$UPGRADE_TO"
crudini --set "$ZULIP_CONF" machine puppet_classes zulip::base,zulip::postgres_appdb_base
touch "/usr/share/postgresql/$UPGRADE_TO/pgroonga_setup.sql.applied"
"$ZULIP_PATH"/scripts/zulip-puppet-apply -f --config "$ZULIP_CONF"
rm -rf "$TEMP_CONF_DIR"
)
upgrade: Use the in-place pg_upgrade, not a full dump/restore. pg_upgradecluster has two possibilities for `--method`: `dump`, and `upgrade`. The former is the default, and does a `pg_dump` of all of the databases in the old cluster and feeds them into the new cluster. This is a sure-fire way of getting the same information in both databases, but may be extremely slow on large databases, and is guaranteed to fail on servers whose databases take up >50% of their disk. The `--method=upgrade` method, by contrast, uses pg_upgrade to copy the raw database data file over to the new cluster, and then fiddles with their internal structure as needed by the upgrade to let them be correct for the new version[1]. This is slightly faster than the dump/load method, since it skips the serialization step, but still requires that there be enough space on disk for both old and new versions at once. `pg_upgrade` is currently supported for all versions of PostgreSQL from 8.4 to 12. Using `pg_upgrade` incurs slightly more risk, but since the it is widely used by now, using it in the relatively-controlled Zulip server environment is reasonable. The expected worst failure is failure to upgrade, not corruption or data loss. Additionally passing `--link` uses hardlinks to link the data files into both the old and new directories simultaneously. This resolve both the runtime of the operation, as well as the disk space usage. The only potential downside to this is that as soon as writes have occurred on the upgraded cluster, the old cluster can no longer be started. Since this tooling intends to remove the old cluster immediately after the upgrade completes successfully, this is not a significant drawback. Switch to using `--method=upgrade --link`. This technique spits out two shell scripts which are expected to be run after completion of the upgrade; one re-analyzes the statistics, the other does an `rm -rf` of the data where it is still hardlinked in the old cluster. Extract the location of these scripts from parsing the `pg_upgradecluster` output; since the path is not static, we must rely on it being relatively easy to parse. The risk of the path changing is lower, and has more obvious failure modes, than inserting the current contents of these upgrade steps into the overall `upgrade-postgres`. [1] https://www.postgresql.org/docs/12/pgupgrade.html
2020-07-10 01:24:46 +02:00
# Capture the output so we know where the path to the post-upgrade scripts is
UPGRADE_LOG=$(mktemp "/var/log/zulip/postgres-upgrade-$UPGRADE_FROM-$UPGRADE_TO.XXXXXXXXX.log")
pg_upgradecluster "$UPGRADE_FROM" main --method=upgrade --link | tee "$UPGRADE_LOG"
SCRIPTS_PATH=$(grep -o "/var/log/postgresql/pg_upgradecluster-$UPGRADE_FROM-$UPGRADE_TO-main.*" "$UPGRADE_LOG" || true)
2020-07-10 01:41:18 +02:00
# If the upgrade completed successfully, lock in the new version in
# our configuration immediately
crudini --set /etc/zulip/zulip.conf postgresql version "$UPGRADE_TO"
upgrade: Use the in-place pg_upgrade, not a full dump/restore. pg_upgradecluster has two possibilities for `--method`: `dump`, and `upgrade`. The former is the default, and does a `pg_dump` of all of the databases in the old cluster and feeds them into the new cluster. This is a sure-fire way of getting the same information in both databases, but may be extremely slow on large databases, and is guaranteed to fail on servers whose databases take up >50% of their disk. The `--method=upgrade` method, by contrast, uses pg_upgrade to copy the raw database data file over to the new cluster, and then fiddles with their internal structure as needed by the upgrade to let them be correct for the new version[1]. This is slightly faster than the dump/load method, since it skips the serialization step, but still requires that there be enough space on disk for both old and new versions at once. `pg_upgrade` is currently supported for all versions of PostgreSQL from 8.4 to 12. Using `pg_upgrade` incurs slightly more risk, but since the it is widely used by now, using it in the relatively-controlled Zulip server environment is reasonable. The expected worst failure is failure to upgrade, not corruption or data loss. Additionally passing `--link` uses hardlinks to link the data files into both the old and new directories simultaneously. This resolve both the runtime of the operation, as well as the disk space usage. The only potential downside to this is that as soon as writes have occurred on the upgraded cluster, the old cluster can no longer be started. Since this tooling intends to remove the old cluster immediately after the upgrade completes successfully, this is not a significant drawback. Switch to using `--method=upgrade --link`. This technique spits out two shell scripts which are expected to be run after completion of the upgrade; one re-analyzes the statistics, the other does an `rm -rf` of the data where it is still hardlinked in the old cluster. Extract the location of these scripts from parsing the `pg_upgradecluster` output; since the path is not static, we must rely on it being relatively easy to parse. The risk of the path changing is lower, and has more obvious failure modes, than inserting the current contents of these upgrade steps into the overall `upgrade-postgres`. [1] https://www.postgresql.org/docs/12/pgupgrade.html
2020-07-10 01:24:46 +02:00
# Update the statistics
[ -n "$SCRIPTS_PATH" ] && su postgres -c "$SCRIPTS_PATH/analyze_new_cluster.sh"
2020-07-10 01:41:18 +02:00
# Start the database up cleanly
"$ZULIP_PATH"/scripts/zulip-puppet-apply -f
2020-07-10 01:41:18 +02:00
# Drop the old data, binaries, and scripts
pg_dropcluster "$UPGRADE_FROM" main
apt remove -y "postgresql-$UPGRADE_FROM"
upgrade: Use the in-place pg_upgrade, not a full dump/restore. pg_upgradecluster has two possibilities for `--method`: `dump`, and `upgrade`. The former is the default, and does a `pg_dump` of all of the databases in the old cluster and feeds them into the new cluster. This is a sure-fire way of getting the same information in both databases, but may be extremely slow on large databases, and is guaranteed to fail on servers whose databases take up >50% of their disk. The `--method=upgrade` method, by contrast, uses pg_upgrade to copy the raw database data file over to the new cluster, and then fiddles with their internal structure as needed by the upgrade to let them be correct for the new version[1]. This is slightly faster than the dump/load method, since it skips the serialization step, but still requires that there be enough space on disk for both old and new versions at once. `pg_upgrade` is currently supported for all versions of PostgreSQL from 8.4 to 12. Using `pg_upgrade` incurs slightly more risk, but since the it is widely used by now, using it in the relatively-controlled Zulip server environment is reasonable. The expected worst failure is failure to upgrade, not corruption or data loss. Additionally passing `--link` uses hardlinks to link the data files into both the old and new directories simultaneously. This resolve both the runtime of the operation, as well as the disk space usage. The only potential downside to this is that as soon as writes have occurred on the upgraded cluster, the old cluster can no longer be started. Since this tooling intends to remove the old cluster immediately after the upgrade completes successfully, this is not a significant drawback. Switch to using `--method=upgrade --link`. This technique spits out two shell scripts which are expected to be run after completion of the upgrade; one re-analyzes the statistics, the other does an `rm -rf` of the data where it is still hardlinked in the old cluster. Extract the location of these scripts from parsing the `pg_upgradecluster` output; since the path is not static, we must rely on it being relatively easy to parse. The risk of the path changing is lower, and has more obvious failure modes, than inserting the current contents of these upgrade steps into the overall `upgrade-postgres`. [1] https://www.postgresql.org/docs/12/pgupgrade.html
2020-07-10 01:24:46 +02:00
if [ -n "$SCRIPTS_PATH" ]; then
su postgres -c "$SCRIPTS_PATH/delete_old_cluster.sh"
rm -rf "$SCRIPTS_PATH"
else
set +x
echo
echo
echo ">>>>> pg_upgradecluster succeeded, but post-upgrade scripts path could not"
echo " be parsed out! Please read the pg_upgradecluster output to understand"
echo " the current status of your cluster:"
echo " $UPGRADE_LOG"
echo " and report this bug with the Postgres $UPGRADE_FROM -> $UPGRADE_TO upgrade to:"
echo " https://github.com/zulip/zulip/issues"
echo
echo
fi