#!/bin/bash # master: {{ vm_mastering }} # edited: 2023-09-25 # updated: {{ ansible_date_time.date }} doBuildSystem() { echo "v{{ vm_mastering }}" } # Display introduction doIntro() { echo echo "Docker Stacks Managment: $HOSTNAME {$OPTION}" doBuildSystem echo } # Show date/time header doHeader() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "- $NOW" echo "" } if [ "$(id -u)" != "0" ]; then doIntro doHeader echo echo "This script must be run as root" 1>&2 echo exit 1 fi WORK={{ vm_docker_work }} BACKUPS={{ vm_docker_backups }} LOGNAME={{ vm_stack_logfile }} HOSTNAME=$(hostname) SELF=$(realpath $0) SCRIPT=$(basename $SELF) CWD=$(dirname $SELF) STACKS=$CWD SETUP=$STACKS/_vm LOGFILE={{ vm_stack_logpath }}/$LOGNAME MASK="{{ vm_stack_backup_header}}${HOSTNAME}{{ vm_stack_backup_common }}NAME_DATE" OPTION=$1 OPTION="${OPTION:=help}" STACKNAME=$2 cd $STACKS # Send notification (0=no, 1=yes) NOTIFY=1 # Force sync & flush doSync() { sync echo 3 > /proc/sys/vm/drop_caches } doHead() { doIntro doHeader } # Display help doHelp() { doIntro doHeader if [ $OPTION != "help" ]; then echo ">>> Unspecified, unknown or invalid option specified !" echo fi echo "Usage: $SCRIPT OPTION [STACK]" echo echo "OPTION:" echo " help - Show this help" echo " up - Up the stacks" echo " down - Down the stacks" echo " start - Start stacks" echo " stop - Stop the stacks" echo " pause - Pause stacks" echo " unpause - Unpause the stacks" echo " restart - Restart the stacks" echo " update - Update the stacks" echo " backup - Backup the stacks" echo " self - Backup self system" echo " autostop - Auto-Stop specified stacks" echo echo "STACK: (optional)" echo " name of a stack to process" echo } # Send notification doNotify() { if [ $NOTIFY == 1 ]; then curl \ -H "Title: Docker Stacks: $HOSTNAME" \ -T $LOGFILE \ -H "Filename: $LOGNAME" \ -H "Tags: heavy_check_mark" \ {{ vm_network_range }}.{{ vm_ip_master }}:8050/zogg \ >/dev/null 2>&1 fi } # UP dockerComposeUp() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { UP: $1 }" echo "> $NOW" if [[ ! (-L .env && -e .env) ]]; then echo "> Recreate .env" rm -rf .env ln -s ../_vm/.env .env chown {{ vm_puid }}:{{ vm_pgid }} .env fi docker compose up --remove-orphans --quiet-pull --pull missing $2 -d NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # PULL dockerComposePull() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { PULL: $1 }" echo "> $NOW" echo " Pulling" docker compose pull --include-deps $2 NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # DOWN dockerComposeDown() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { DOWN: $1 }" echo "> $NOW" docker compose down NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # START dockerComposeStart() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { START: $1 }" echo "> $NOW" echo ">> start" docker compose start NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # STOP dockerComposeStop() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { STOP: $1 }" echo "> $NOW" docker compose stop -t 10 NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # PAUSE dockerComposePause() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { PAUSE: $1 }" echo "> $NOW" docker compose pause NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # UNPAUSE dockerComposeUnpause() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { UNPAUSE: $1 }" echo "> $NOW" docker compose unpause NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # RESTART dockerComposeRestart() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { RESTART: $1 }" echo "> $NOW" docker compose restart NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # BACKUP backupStack() { FLDR=$(realpath $(pwd)) DATE=$(date +"%Y%m%d%H%M") NAME=$1 FNAME=${MASK/NAME/$NAME} FNAME=${FNAME/DATE/$DATE} TOTAL=$(du -hs -B 1 $FLDR | cut -f1 | tail -n 1) TOTALH=$(echo $TOTAL | awk ' BEGIN { split("bytes,KB,MB,GB,TB,PB,EB,ZB,YB",SZ,",") } { p=1;for(i=0;$1/p>1024;i++) p*=1024; printf "%4.2f %s\n", $1/p, SZ[i+1]}') WRK=$WORK/$FNAME MAXSIZE=1073741824 # 1 Go echo " > Flush" doSync echo " > TAR" tar --create --dereference --file=$WRK.tar -X $SETUP/excluded.txt $FLDR/ 2>/dev/null TARSIZE=$(stat -c%s "$WRK.tar") if (( TARSIZE < MAXSIZE)); then echo " > Compress" pigz --fast $WRK.tar echo " > Move" mv $WRK.tar.gz $BACKUPS/ else echo " > Move" mv $WRK.tar $BACKUPS/ fi echo " > Flush" doSync echo " > Done!" } # Do: backup a stack dockerBackupStack() { NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { BACKUP: $1 }" echo "> $NOW" backupStack $1 NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "> $NOW" echo } # Do: backup self system backupSelf() { FLDR=$(realpath $(pwd)) DATE=$(date +"%Y%m%d%H%M") NAME="self-system" FNAME=${MASK/NAME/$NAME} FNAME=${FNAME/DATE/$DATE} WRK=$WORK/$FNAME MAXSIZE=524288000 # 500 Mo echo " > Flush" doSync echo " > TAR" tar --create --dereference --file=$WRK.tar -X $SETUP/excluded.txt $(realpath $SELF) $SETUP/ 2>/dev/null TARSIZE=$(stat -c%s "$WRK.tar") if (( TARSIZE < MAXSIZE)); then echo " > Compress" pigz --fast $WRK.tar echo " > Move" mv $WRK.tar.gz $BACKUPS/ else echo " > Move" mv $WRK.tar $BACKUPS/ fi echo " > Flush" doSync echo " > Done!" } # Iterate stacks from file doIterateFile() { OPTION=$1 FILENAME=$2 FLAGS=$3 case $OPTION in up | start | pause | restart | backup | autostop | update): stacks=`cat -v $FILENAME` ;; down | stop | unpause): stacks=`cat -v $FILENAME | tac` ;; *) doHelp doNotify exit 1 ;; esac for stack in $stacks; do if [[ (-n $stack) # if not null && (${stack:0:1} != ';') # skip when starting with ';' (comment) && ( (${stack:0:1} == '+') || "$1" == "backup" ) # use when start with '+' or when asked to backup ]]; then name=${stack:1} cd $STACKS/$name case $OPTION in up): dockerComposeUp $name $FLAGS ;; down): dockerComposeDown $name $FLAGS ;; start): dockerComposeStart $name $FLAGS ;; stop): dockerComposeStop $name $FLAGS ;; pause): dockerComposePause $name $FLAGS ;; unpause): dockerComposeUnpause $name $FLAGS ;; restart): dockerComposeRestart $name $FLAGS ;; backup): dockerComposeStop $name $FLAGS dockerBackupStack $name $FLAGS dockerComposeStart $name $FLAGS ;; autostop): dockerComposeStop $name $FLAGS ;; update): dockerComposeDown $name $FLAGS dockerComposePull $name $FLAGS dockerComposeUp $name $FLAGS ;; *) doHelp doNotify exit 1 ;; esac cd $CWD fi done cd $CWD } # Proceedd operations on stacks doIterate() { OPTION=$1 STACKNAME=$2 if [ ! -z $STACKNAME ]; then echo "+$STACKNAME" > "$SETUP/{{ vm_stack_unitary }}" else rm -rf "$SETUP/{{ vm_stack_unitary }}" fi if [ -f "$SETUP/{{ vm_stack_unitary }}" ]; then doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_unitary }}" "" rm -rf "$SETUP/{{ vm_stack_unitary }}" else case $OPTION in start): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" ;; stop): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "" ;; up): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "--wait" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" doIterateFile autostop "$SETUP/{{ vm_stack_stop }}" "" ;; down): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "" ;; restart): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "" doIterateFile autostop "$SETUP/{{ vm_stack_stop }}" "" ;; pause): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "" ;; unpause): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" ;; update): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "" doIterateFile autostop "$SETUP/{{ vm_stack_stop }}" "" ;; backup): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_after }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_current }}" "" doIterateFile $OPTION "$SETUP/{{ vm_stack_before }}" "" doIterateFile autostop "$SETUP/{{ vm_stack_stop }}" "" $SELF self ;; self): doHead backupSelf ;; autostop): doHead doIterateFile $OPTION "$SETUP/{{ vm_stack_stop }}" "" ;; esac fi } # Entrypoint of operations case $OPTION in up|start|pause | down|stop|unpause | update | restart | backup|self | autostop): doIterate $OPTION $STACKNAME > >(tee -a $LOGFILE) 2>&1 doNotify doSync ;; help | *) doHelp doNotify exit 1 ;; esac exit 0