]> Frank Brehm's Git Trees - pixelpark/admin-tools.git/commitdiff
Adding bin/backup_pgsql.sh
authorFrank Brehm <frank.brehm@pixelpark.com>
Wed, 15 Nov 2017 17:47:57 +0000 (18:47 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Wed, 15 Nov 2017 17:47:57 +0000 (18:47 +0100)
bin/backup_pgsql.sh [new file with mode: 0755]

diff --git a/bin/backup_pgsql.sh b/bin/backup_pgsql.sh
new file mode 100755 (executable)
index 0000000..19127ab
--- /dev/null
@@ -0,0 +1,180 @@
+#!/usr/bin/env bash
+
+###########################
+# REQUIREMENTS
+###########################
+#
+#   * Required commands:
+#       + pg_dump
+#       + du
+#       + tee
+#       + bzip2     # If bzip2 is not available, change 'CMD_COMPRESS'
+#                   # to use 'gzip' or whatever compress command you want.
+#
+
+###########################
+# USAGE
+###########################
+#
+#   * It stores all backup copies in directory '/var/vmail/backup' by default,
+#     You can change it in variable $BACKUP_ROOTDIR below.
+#
+#   * Set correct values for below variables:
+#
+#       PGSQL_SYS_USER
+#       BACKUP_ROOTDIR
+#       DATABASES
+#
+#   * Add crontab job for root user (or whatever user you want):
+#
+#       # crontab -e -u root
+#       1   4   *   *   *   bash /path/to/backup_pgsql.sh
+#
+#   * Make sure 'crond' service is running.
+#
+
+set -e
+set -u
+
+export LC_ALL=C
+export LANG=C
+
+#########################################################
+# Modify below variables to fit your need ----
+#########################################################
+# Keep backup for how many days. Default is 90 days.
+KEEP_DAYS='90'
+
+# System user used to run PostgreSQL daemon.
+#   - On Linux, it's postgres.
+#   - On FreeBSD, it's pgsql.
+#   - On OpenBSD, it's _postgresql.
+export PGSQL_SYS_USER="postgres"
+
+# Where to store backup copies.
+export BACKUP_ROOTDIR="/var/backup"
+
+export SUDO=""
+if [[ "$( id -u -n )" != "${PGSQL_SYS_USER}" ]] ; then
+    export SUDO="sudo -i -u ${PGSQL_SYS_USER} "
+fi
+
+# Detect existing databases
+export DATABASES="$( ${SUDO}psql --list --tuples-only --no-align --no-readline --expanded --field-separator=',' | grep -i '^Name' | awk -F ',' '{print $2}' )"
+
+export PATH='/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin'
+
+# Commands.
+export CMD_DATE='/bin/date'
+export CMD_DU='du -sk'
+export CMD_COMPRESS='bzip2 -9'
+export COMPRESS_SUFFIX='bz2'
+export CMD_PG_DUMP='pg_dump'
+
+# Date.
+export YEAR="$(${CMD_DATE} +%Y)"
+export MONTH="$(${CMD_DATE} +%m)"
+export DAY="$(${CMD_DATE} +%d)"
+export TIME="$(${CMD_DATE} +%H:%M:%S)"
+export TIMESTAMP="${YEAR}-${MONTH}-${DAY}-${TIME}"
+
+# Pre-defined backup status
+export BACKUP_SUCCESS='YES'
+
+# Define, check, create directories.
+export BACKUP_DIR="${BACKUP_ROOTDIR}/pgsql/${YEAR}/${MONTH}/${DAY}"
+
+# Find the old backup which should be removed.
+export REMOVE_OLD_BACKUP='NO'
+if which python &>/dev/null; then
+    export REMOVE_OLD_BACKUP='YES'
+    py_cmd="import time; import datetime; t=time.localtime(); print datetime.date(t.tm_year, t.tm_mon, t.tm_mday) - datetime.timedelta(days=${KEEP_DAYS})"
+    shift_date=$(python -c "${py_cmd}")
+    shift_year="$(echo ${shift_date} | awk -F'-' '{print $1}')"
+    shift_month="$(echo ${shift_date} | awk -F'-' '{print $2}')"
+    shift_day="$(echo ${shift_date} | awk -F'-' '{print $3}')"
+    export REMOVED_BACKUP_DIR="${BACKUP_ROOTDIR}/pgsql/${shift_year}/${shift_month}/${shift_day}"
+fi
+
+# Log file
+export LOGFILE="${BACKUP_DIR}/${TIMESTAMP}.log"
+
+# Check and create directories.
+if [[ ! -d "${BACKUP_DIR}" ]] ; then
+    ${SUDO}mkdir -p "${BACKUP_DIR}"
+fi
+
+# Get HOME directory of PGSQL_SYS_USER
+export PGSQL_SYS_USER_HOME=$( getent passwd "${PGSQL_SYS_USER}" | awk -F':' '{print $6}' )
+
+# Initialize log file.
+echo "* Starting at: ${YEAR}-${MONTH}-${DAY}-${TIME}." | ${SUDO}tee ${LOGFILE}
+echo "* Backup directory: ${BACKUP_DIR}."  | ${SUDO}tee -a ${LOGFILE}
+
+TMP_DIR=$( ${SUDO}mktemp -d -p "${PGSQL_SYS_USER_HOME}" backup.XXXXXXXX.d )
+
+cleanup_tmp_dir() {
+    ${SUDO}rm -rf "${TMP_DIR}"
+}
+
+trap cleanup_tmp_dir INT TERM EXIT ABRT
+
+# Backup.
+echo "* Backing up databases: ${DATABASES}." | ${SUDO}tee -a ${LOGFILE}
+for db in ${DATABASES}; do
+
+    output_sql="${db}-${TIMESTAMP}.sql"
+    out_sql_tmp="${TMP_DIR}/${output_sql}"
+    out_sql_tgt="${BACKUP_DIR}/${output_sql}"
+
+#    # Check database existence
+#    if ${SUDO}"psql -d ${db} -c '\q' >/dev/null 2>&1" ; then
+#        :
+#    else
+#        echo "Database '${db}' does not exists." | ${SUDO}tee -a ${LOGFILE}
+#        continue
+#    fi
+
+    # Dump
+    ${SUDO}"${CMD_PG_DUMP}" ${db} | ${SUDO}tee "${out_sql_tmp}" >/dev/null
+
+    # Move to backup directory.
+    ${SUDO}mv "${out_sql_tmp}" ${BACKUP_DIR}
+
+    cd ${BACKUP_DIR}
+
+    # Get original SQL file size
+    original_size="$(${CMD_DU} ${output_sql} | awk '{print $1}')"
+    echo "  Original size ${output_sql}: ${original_size}" | ${SUDO}tee -a ${LOGFILE}
+
+    # Compress
+    ${SUDO}${CMD_COMPRESS} ${out_sql_tgt} 2>&1 | ${SUDO}tee -a ${LOGFILE}
+
+    ${SUDO}rm -f ${out_sql_tgt} | ${SUDO}tee -a ${LOGFILE}
+    echo -e "  + ${db} [DONE]" | ${SUDO}tee -a ${LOGFILE}
+
+done
+
+# Append file size of backup files.
+echo -e "* File size:\n----" | ${SUDO}tee -a ${LOGFILE}
+${SUDO}${CMD_DU} ${BACKUP_DIR}/*${TIMESTAMP}*sql* | ${SUDO}tee -a ${LOGFILE}
+echo "----" | ${SUDO}tee -a ${LOGFILE}
+
+echo "* Backup completed (Success? ${BACKUP_SUCCESS})." | ${SUDO}tee -a ${LOGFILE}
+
+if [[ "${BACKUP_SUCCESS}" == 'YES' ]]; then
+    echo -e "\n[OK] Backup successfully completed.\n"
+else
+    echo -e "\n[ERROR] Backup completed with ERRORS.\n" >&2
+fi
+
+if [[ "${REMOVE_OLD_BACKUP}" == 'YES' && -d "${REMOVED_BACKUP_DIR}" ]]; then
+    echo -e "* Delete old backup: ${REMOVED_BACKUP_DIR}." | ${SUDO}tee -a  ${LOGFILE}
+    echo -e "* Suppose to delete: ${REMOVED_BACKUP_DIR}" | ${SUDO}tee -a  ${LOGFILE}
+    ${SUDO}rm -rf ${REMOVED_BACKUP_DIR} 2>&1 | ${SUDO}tee -a ${LOGFILE}
+fi
+
+echo "* Backup log: ${LOGFILE}:"
+
+
+# vim: ts=4 et list