provisioning tool for building opinionated architecture
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

215 lines
5.5 KiB

#!/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 <DB_NAME>\n"
printf "\t lookup <DB_NAME> <TERM>\n"
printf "\t create <DB_NAME> [PASSWORD]\n"
printf "\t ---------------------------\n"
printf "\t backup <DB_NAME> [FOLDER]\n"
printf "\t restore <DB_NAME> <FILE> [--yes]\n"
printf "\t ---------------------------\n"
printf "\t rename <DB_NAME> <NEW_NAME>\n"
if [[ "$TARGET" != 'prod' ]]; then
printf "\t drop <DB_NAME> # 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