Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upgrade: Container upgrades existing data on start #24

Merged
merged 1 commit into from
Apr 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ ENV POSTGRES_USER docker
ENV POSTGRES_PASSWORD docker

COPY create-resin-db.sh /docker-entrypoint-initdb.d/
COPY balena-entrypoint.sh /balena-entrypoint.sh

CMD [ "postgres" ]
ENTRYPOINT [ "/balena-entrypoint.sh" ]
118 changes: 118 additions & 0 deletions balena-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/bin/bash

set -e

# creates a backup archive of the dir $1...
backup_data () {
gosu postgres tar --exclude backup.tar.gz -zcf /tmp/backup.tar.gz -C "$1" .
mv /tmp/backup.tar.gz "${1}/backup.tar.gz"
}

# copies all the data from $1 to $2...
restore_volume () {
echo "=== Restoring data volume structure"
find "$1" -maxdepth 1 \
! -path "$1" \
| xargs mv -t "$2"
}

# install the old version of Postgres, required when doing an upgrade...
install_old_version () {
if [ ! -d "/usr/lib/postgresql/$1/bin" ]; then
sed -i 's/$/ '"$1"'/' /etc/apt/sources.list.d/pgdg.list

apt-get -qq update \
&& apt-get install -qq -y --no-install-recommends \
"postgresql-$1" \
&& rm -rf /var/lib/apt/lists/*
fi
}

# creates a dir at $1 which is valid for Postgres data to live in...
create_postgres_data_dir () {
echo "=== Creating data dir $1"
mkdir -p "$1"
chmod 700 "$1"
chown -R postgres:postgres "$1"
}

# echo a message and die...
die_with_message () {
echo "[FATAL] $1"
exit 2
}

# check that this is running from within a valid Postgres container environment...
[ ! -z "$PG_MAJOR" ] || die_with_message "Not a compatible Postgres runtime environment"

# set our target version...
TARGET_VERSION="$PG_MAJOR"

# ensure we have a versioned data directory...
[ -d "${PGDATA}/${TARGET_VERSION}" ] || create_postgres_data_dir "${PGDATA}/${TARGET_VERSION}"

# check for Postgres data in the root of the $PGDATA directory...
if [ -f "${PGDATA}/PG_VERSION" ]; then
SOURCE_VERSION="$(cat ${PGDATA}/PG_VERSION)"

# does the data need upgrading...
if [ "$SOURCE_VERSION" -ne "$TARGET_VERSION" ]; then
echo "=== Upgrading data from v${SOURCE_VERSION} to v${TARGET_VERSION}"

# define our directories...
PGDATAOLD="${PGDATA}/${SOURCE_VERSION}"
PGDATANEW="${PGDATA}/${TARGET_VERSION}"
PGBINOLD="/usr/lib/postgresql/$SOURCE_VERSION/bin"
PGBINNEW="/usr/lib/postgresql/$TARGET_VERSION/bin"

echo "=== Installing tools for Postgres v${SOURCE_VERSION}"
install_old_version "$SOURCE_VERSION"

echo "=== Moving extisting data to ${PGDATAOLD}"
create_postgres_data_dir "${PGDATAOLD}"
find "$PGDATA" -maxdepth 1 \
! -path "$PGDATA" \
! -path "$PGDATAOLD*" \
| xargs mv -t "${PGDATAOLD}"

trap "restore_volume ${PGDATAOLD} ${PGDATA}" ERR

echo "=== Initialising new data directory ${PGDATANEW}"
rm -rf "${PGDATANEW}"
create_postgres_data_dir "${PGDATANEW}"
gosu postgres initdb -D "$PGDATANEW" -U "$POSTGRES_USER" $POSTGRES_INITDB_ARGS

echo "=== Beginning pg_upgrade"
cd /tmp
gosu postgres pg_upgrade \
-U "$POSTGRES_USER" \
--old-datadir="$PGDATAOLD" \
--new-datadir="$PGDATANEW" \
--old-bindir="$PGBINOLD" \
--new-bindir="$PGBINNEW" \
--check

gosu postgres pg_upgrade \
-U "$POSTGRES_USER" \
--old-datadir="$PGDATAOLD" \
--new-datadir="$PGDATANEW" \
--old-bindir="$PGBINOLD" \
--new-bindir="$PGBINNEW"

echo "=== Restoring configuration files"
cp "${PGDATAOLD}/pg_hba.conf" "${PGDATANEW}/pg_hba.conf"
cp "${PGDATAOLD}/pg_ident.conf" "${PGDATANEW}/pg_ident.conf"
else
echo "=== Moving extisting data to directory "${PGDATA}/${TARGET_VERSION}""
find "$PGDATA" -maxdepth 1 \
! -path "$PGDATA" \
| xargs mv -t "${PGDATA}/${TARGET_VERSION}"
fi
fi

# set our runtime data directory to the versioned one...
export PGDATA="${PGDATA}/${TARGET_VERSION}"

# run the existing Postgres entrypoint script...
. /docker-entrypoint.sh
_main "$@"