#!/bin/bash confirm() { read -p "$1 ([y]es or [N]o): " case $(echo $REPLY | tr '[A-Z]' '[a-z]') in y | yes) echo "yes" ;; *) echo "no" ;; esac } synopsis() { echo "usage: " printf "\t list | console | connections\n" printf "\t ---------------------------\n" printf "\t use \n" printf "\t lookup \n" printf "\t create [PASSWORD]\n" printf "\t ---------------------------\n" printf "\t backup [FOLDER]\n" printf "\t restore [--yes]\n" printf "\t ---------------------------\n" printf "\t rename \n" if [[ "$TARGET" != 'prod' ]]; then printf "\t drop # unless PROD!\n" fi } list() { lxc exec ct1 -- su - postgres -c "psql -Atc \"SELECT datname FROM pg_database WHERE datistemplate=false AND datname<>'postgres';\"" } console() { if [[ -z $1 ]]; then lxc exec ct1 -- su - postgres else lxc exec ct1 -- su - postgres -c "$1" fi } connections() { PROCESSES=$(console "psql -c \"select pid as process_id, usename as username, datname as database_name, client_addr as client_address, application_name, backend_start, state, state_change from pg_stat_activity WHERE datname<>'postgres' ORDER BY datname, usename;\"") printf "$PROCESSES\n" } use() { echo >&2 "about to connect to <${DB_NAME}> ..." if [[ -z $1 ]]; then lxc exec ct1 -- su - postgres -c "psql $DB_NAME" else local sql="psql -A -t $DB_NAME -c \\\"$1;\\\"" local command="su - postgres -c \"$sql\"" lxc exec ct1 -- sh -c "$command" fi } create() { echo >&2 "about to create to <${DB_NAME}> ..." source /opt/miaou-bash/lib/functions.sh local DBs=($(list)) if ! $(containsElement DBs $DB_NAME); then local SQL="CREATE USER \\\\\\\"$DB_NAME\\\\\\\" WITH PASSWORD '$DB_PASSWORD'" local command="su - postgres sh -c \"psql -c \\\"$SQL\\\"\" && su - postgres sh -c \"createdb -O $DB_NAME $DB_NAME\" && echo CREATE DB" # echo $command lxc exec ct1 -- sh -c "$command" else echo $DB_NAME already exists! fi } lookup() { if [[ ${#TERM} -ge 4 ]]; then echo >&2 "about to lookup term <${TERM}> over all tables of database <$DB_NAME> ..." local command="pg_dump --data-only --inserts $DB_NAME 2>/dev/null | grep --color \"$TERM\"" lxc exec ct1 -- su - postgres -c "$command" else echo "term <$TERM> should contain 4 chars minimum!" && exit 2 fi } backup() { if [[ ! -d "$FOLDER" ]]; then echo "error: Folder required!" file $FOLDER exit 2 fi DATE=$(date '+%F') ARCHIVE="$FOLDER"/$DB_NAME-$DATE.postgres.gz if [[ -f $ARCHIVE ]]; then VERSION_CONTROL=numbered mv -b $ARCHIVE "$FOLDER"/$DB_NAME-$DATE-daily.postgres.gz fi echo "backup $DB_NAME $FOLDER" PGPASSWORD=$DB_NAME pg_dump -U $DB_NAME $DB_NAME -h ct1.lxd | gzip >"$ARCHIVE" echo "archive file created: $ARCHIVE" } restore() { echo "restore $DB_NAME $FILE" if [[ ! -f "$FILE" ]]; then echo "error: Backup file (*.postgres.gz) required!" file $FILE exit 2 fi PROCESSES=$(console "psql -c \"select pid as process_id, usename as username, datname as database_name, client_addr as client_address, application_name, backend_start, state, state_change from pg_stat_activity WHERE datname='$DB_NAME';\"") PROCESS_COUNT=$(echo "$PROCESSES" | wc -l) if [[ $PROCESS_COUNT -gt 3 ]]; then echo "FAILURE: There are some connections to database, please consider stopping bound services" echo printf "$PROCESSES\n" exit 2 fi if [[ $YES == "true" || "yes" == $(confirm "RESTORATION will drop DATABASE, please acknowledge with care!!!") ]]; then FOLDER="$HOME/RECOVERY_POSTGRES" mkdir -p "$FOLDER" backup echo "backup successful, now drop and restore" lxc exec ct1 -- su - postgres -c "dropdb $DB_NAME && createdb -O $DB_NAME $DB_NAME" gunzip -c "$FILE" | grep -v "^CREATE DATABASE" | PGPASSWORD=$DB_NAME PGOPTIONS='--client-min-messages=warning' psql -X -q -1 -v ON_ERROR_STOP=1 --pset pager=off -U $DB_NAME -h ct1.lxd $DB_NAME 2>&1 >/dev/null else exit 1 fi } rename() { echo "rename <$DB_NAME> to <$DB_NEW_NAME>" mapfile -t LIST <<<"$(list)" found=false for db in "${LIST[@]}"; do [[ "$db" == "$DB_NEW_NAME" ]] && echoerr "destination database <$DB_NEW_NAME> already exists! Please provide another name." && exit 11 [[ "$db" == "$DB_NAME" ]] && found=true done $found || (echoerr "source database <$DB_NAME> not found!" && exit 12) console "psql -c \"ALTER DATABASE \\\"$DB_NAME\\\" RENAME TO \\\"$DB_NEW_NAME\\\" \"" console "psql -c \"ALTER USER \\\"$DB_NAME\\\" RENAME TO \\\"$DB_NEW_NAME\\\" \"" console "psql -c \"ALTER USER \\\"$DB_NEW_NAME\\\" PASSWORD '$DB_NEW_NAME' \"" } drop() { console "dropdb $DB_NAME" console "dropuser $DB_NAME" echo "$DB_NAME dropped!" } # MAIN . "$MIAOU_BASEDIR/lib/init.sh" TARGET=$(grep -Es "^target:" /etc/miaou/defaults.yaml | cut -d ' ' -f2) [[ $# -lt 1 ]] && synopsis && exit 1 ACTION=$1 case $ACTION in console) shift TAIL="$@" console "$TAIL" ;; list) list ;; connections) connections ;; use) [[ $# -lt 2 ]] && synopsis && exit 1 DB_NAME=$2 shift 2 TAIL="$@" use "$TAIL" ;; create) [[ $# -lt 2 ]] && synopsis && exit 1 DB_NAME=$2 DB_PASSWORD=${3:-$DB_NAME} create ;; lookup) [[ $# -lt 3 ]] && synopsis && exit 1 DB_NAME=$2 TERM=$3 lookup ;; backup) [[ $# -lt 2 ]] && synopsis && exit 1 DB_NAME=$2 FOLDER=${3:-.} backup ;; restore) [[ $# -lt 3 ]] && synopsis && exit 1 DB_NAME=$2 FILE=$3 YES=true restore ;; rename) [[ $# -lt 3 ]] && synopsis && exit 1 DB_NAME=$2 DB_NEW_NAME=$3 rename ;; drop) [[ $# -lt 2 ]] && synopsis && exit 1 [[ "$TARGET" = 'prod' ]] && synopsis && exit 2 DB_NAME=$2 drop ;; *) synopsis exit 1 ;; esac