-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
* Change: Add upgrade scripts for database files Postgres changes the format of the database files on disk between major versions. This means that in order to upgrade a postgres database, it is not sufficient to just bump the container versions. To help with this process, we now can use migration scripts that will take care of updating the database version without the need of a manual dump/restore. * Update README with warning
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.dockerignore | ||
LICENSE | ||
README.md | ||
tests/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,35 @@ | ||
ARG POSTGRES_VERSION=16 | ||
# This image was forked from the official PostgreSQL image, so it could be | ||
# signed and relied on as an internal dependency. | ||
# The image is modified to include an older version of PostgreSQL, which | ||
# allows us to upgrade the database from the old version to the new one. | ||
ARG POSTGRES_VERSION=17 | ||
FROM postgres:${POSTGRES_VERSION} | ||
|
||
# we need to redeclare the ARG here, otherwise it will not | ||
# be available in the section below the FROM statement. | ||
ARG POSTGRES_VERSION=17 | ||
ARG POSTGRES_OLD_VERSION=16 | ||
|
||
ENV POSTGRES_VERSION=${POSTGRES_VERSION} | ||
ENV POSTGRES_OLD_VERSION=${POSTGRES_OLD_VERSION} | ||
|
||
# Enable and install old version of PostgreSQL. | ||
RUN sed -i "s/\$/ ${POSTGRES_OLD_VERSION}/" /etc/apt/sources.list.d/pgdg.list | ||
RUN set -eux; \ | ||
apt-get update; \ | ||
apt-get install -y --no-install-recommends \ | ||
postgresql-${POSTGRES_OLD_VERSION} \ | ||
; \ | ||
rm -rf /var/lib/apt/lists/* | ||
|
||
# The old binaries will be in /usr/lib/postgresql/16/bin | ||
ENV PGBINOLD /usr/lib/postgresql/${POSTGRES_OLD_VERSION}/bin | ||
Check warning on line 26 in Dockerfile GitHub Actions / push-postgresLegacy key/value format with whitespace separator should not be used
Check warning on line 26 in Dockerfile GitHub Actions / push-postgresLegacy key/value format with whitespace separator should not be used
|
||
ENV PGBINNEW /usr/lib/postgresql/${POSTGRES_VERSION}/bin | ||
Check warning on line 27 in Dockerfile GitHub Actions / push-postgresLegacy key/value format with whitespace separator should not be used
Check warning on line 27 in Dockerfile GitHub Actions / push-postgresLegacy key/value format with whitespace separator should not be used
|
||
|
||
# we are usually using /var/lib/postgresql/data as the data directory | ||
# so this is why we are using it for the 'old' version instead of the | ||
# path that is customized for the version. | ||
ENV PGDATAOLD /var/lib/postgresql/data | ||
Check warning on line 32 in Dockerfile GitHub Actions / push-postgresLegacy key/value format with whitespace separator should not be used
Check warning on line 32 in Dockerfile GitHub Actions / push-postgresLegacy key/value format with whitespace separator should not be used
|
||
ENV PGDATANEW /var/lib/postgresql/${POSTGRES_VERSION}/data | ||
Check warning on line 33 in Dockerfile GitHub Actions / push-postgresLegacy key/value format with whitespace separator should not be used
Check warning on line 33 in Dockerfile GitHub Actions / push-postgresLegacy key/value format with whitespace separator should not be used
|
||
|
||
COPY bin/upgradeversion.sh /usr/local/bin/upgradeversion |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#!/bin/bash | ||
|
||
set -euo pipefail | ||
|
||
# POSTGRES_VERSION, POSTGRES_OLD_VERSION | ||
# PGDATAOLD, PGDATANEW, PGBINOLD, PGBINNEW | ||
# are available from the Dockerfile | ||
|
||
# If there is no initialized database, we do nothing | ||
if [ ! -s "${PGDATAOLD}/PG_VERSION" ]; then | ||
echo "No database found. Exiting." | ||
exit 0 | ||
fi | ||
|
||
# Check postgres version | ||
echo -n "Current database version is " | ||
cat ${PGDATAOLD}/PG_VERSION | ||
|
||
# if the version is already current, we don't need to do anything | ||
if [ "$(cat ${PGDATAOLD}/PG_VERSION)" == "${POSTGRES_VERSION}" ]; then | ||
echo "No need to update. exiting." | ||
exit 0 | ||
fi | ||
|
||
# Abort if the old version is not supported | ||
if [ "$(cat ${PGDATAOLD}/PG_VERSION)" != "${POSTGRES_OLD_VERSION}" ]; then | ||
echo "Only PostgreSQL ${POSTGRES_OLD_VERSION} is supported for migration with this image." | ||
exit 1 | ||
fi | ||
|
||
# Initialize the new database, if it doesn't exist | ||
if [ ! -s "${PGDATANEW}/PG_VERSION" ]; then | ||
initdb -D ${PGDATANEW} -U "${POSTGRES_USER}" | ||
|
||
# migrate auth settings as well | ||
cp --target-directory=${PGDATANEW}/ ${PGDATAOLD}/pg_hba.conf | ||
fi | ||
|
||
# mitigate: 'you must have read and write access in the current directory' | ||
cd /var/lib/postgresql | ||
|
||
pg_upgrade \ | ||
-U "${POSTGRES_USER}" \ | ||
--old-bindir ${PGBINOLD} \ | ||
--new-bindir ${PGBINNEW} \ | ||
--old-datadir ${PGDATAOLD} \ | ||
--new-datadir ${PGDATANEW} | ||
|
||
# Check postgres version | ||
echo -n "New migrated database version is " | ||
cat ${PGDATANEW}/PG_VERSION | ||
|
||
# if first parameter is 'inplace', we copy the new postgres version to | ||
# the old one. This is not an atomic operation, and therefore risky; | ||
# If the copy operation is not successful, we will end up with a | ||
# corrupted database. | ||
if [ "${1:-}" == "inplace" ]; then | ||
rm -rf ${PGDATAOLD}/* | ||
mv --target-directory=${PGDATAOLD}/ ${PGDATANEW}/* | ||
fi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#!/usr/bin/env bash | ||
set -euo pipefail | ||
|
||
# This script is used to test the upgradeversion script without spinning up the | ||
# whole OpenSight stack. It creates a new (outdated) PostgreSQL database, | ||
# attempts to upgrade it and checks if the version file was updated correctly. | ||
|
||
DOCKER_IMAGE=packages.greenbone.net/opensight/opensight-postgres | ||
PREVIOUS_VERSION=16.6 # released version to test the upgrade from | ||
|
||
tempdir=$(mktemp -d -t opensight-postgres-test-XXXXX) | ||
|
||
cleanup() { | ||
sudo rm -rf "${tempdir}" | ||
} | ||
trap cleanup ERR | ||
|
||
sudo chown -R 999:999 "${tempdir}" | ||
|
||
# Start a PostgreSQL container with an outdated version | ||
docker run -it --rm \ | ||
--user 999:999 \ | ||
-e POSTGRES_PASSWORD=password \ | ||
-e POSTGRES_DB=keycloak \ | ||
-e POSTGRES_USER=keycloak \ | ||
-v "${tempdir}":/var/lib/postgresql/data \ | ||
${DOCKER_IMAGE}:${PREVIOUS_VERSION} | ||
|
||
# Upgrade the database with the test version | ||
docker build -t ${DOCKER_IMAGE}:test . | ||
docker run -it --rm \ | ||
--user 999:999 -e POSTGRES_PASSWORD=password \ | ||
-e POSTGRES_DB=keycloak \ | ||
-e POSTGRES_USER=keycloak \ | ||
-v "${tempdir}":/var/lib/postgresql/data \ | ||
${DOCKER_IMAGE}:test upgradeversion inplace | ||
|
||
# did everything work as expected? | ||
sudo cat ${tempdir}/PG_VERSION | ||
|
||
cleanup |