#!/bin/bash printf "Backup service ready\n" postgres_cluster=9.6/main if ! which chunked >/dev/null; then printf "Installing chunked en-/decoder\n" >&2 # Install signing key for debian repo 'deb2.dogcraft.de' where 'chunked' is hosted. Downloadable from "http://deb.dogcraft.de/signer.gpg". apt-key add - >&2 <&2 apt-get update >&2 apt-get install -y chunked >&2 fi while :; do read -r command || break if [[ $command == base ]]; then sudo lxc-attach -n postgres-primary -- su -c 'pg_basebackup -Ft -z -D - -P' postgres | chunked printf "base backup done\n" elif [[ $command == incremental ]]; then read -e req_name read -e req_hash if ! grep -qi -- '^[A-Z0-9]\{24\}$' <<< $req_name; then printf "Error: invalid WAL-name.\n" >&2 printf "Error\n" fi real_hash="$(sha256sum "/data/postgres/data/archive/$req_name" | cut -d" " -f1)" if [[ $req_hash != "-" ]] && [[ $real_hash != $req_hash ]]; then printf "Error: hash mismatch on expected %s != provided %s\n" "$real_hash" "$req_hash" >&2 printf "Error\n" exit 1 fi printf "Ready\n" files=( /data/postgres/data/archive/* ) for i in "${files[@]}"; do name="$(basename $i)" if ( [[ "$name" != "$req_name".* ]] && [[ $name > $req_name ]] ) || ( ( [[ "$name" == "$req_name".* ]] || [[ $req_name == $name ]] ) && [[ $req_hash == "-" ]] ); then printf "%s\n" "$name" fi done | tar cz -C /data/postgres/data/archive -T - | chunked printf "incremental backup done, confirm cleanup!\n" read -e confirmation if [[ $confirmation == "y" ]]; then printf "Cleaning up archive\n" >&2 lxc-attach -n postgres-primary -- pg_archivecleanup /var/lib/postgresql/archive/ "$req_name" else printf "Not doing cleanup\n" >&2 fi elif [[ $command == restore ]]; then # for now (and quick development) we override rm -R /data/postgres/data if [[ -d /data/postgres/data ]]; then printf "error\n" exit 1 fi printf "postgres base\n" mkdir -p "/data/postgres/data/${postgres_cluster}" chunked decode > /data/postgres/data/pg_base.tar.gz mkdir -p /data/postgres/data/restore while :; do printf "incremental?\n" read -e inc if [[ $inc != "y" ]]; then break fi chunked decode | tar xvz -C /data/postgres/data/restore >&2 done cat > "/data/postgres/data/${postgres_cluster}/recovery.conf" < "/data/postgres/conf/${postgres_cluster}/start.conf" touch "/data/postgres/conf/${postgres_cluster}/postgresql.conf" elif [[ $command == journal ]]; then read -e from action=$(date -u -d '00:00 today' +%s) if [[ $action == $from ]]; then printf "no journals\n" continue fi printf "Until: %s\n" "$action" for i in $(sudo lxc-ls); do [[ $i == "base-image" ]] && continue printf "journal: %s\n" "$i" if [[ $from == - ]]; then lxc-attach -n "$i" -- journalctl --utc --until="@$action" -o export | chunked else lxc-attach -n "$i" -- journalctl --utc --since="@$from" --until="@$action" -o export | chunked fi done printf "end-of-journals\n" elif [[ $command == end ]]; then printf "end\n" fi done