#!/bin/bash {# Updated: 2023-12-05 #} # master: {{ common_mastering }} # 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_logfilename }} LOGEXT={{ vm_stack_logfileext }} HOSTNAME=$(hostname) SELF=$(realpath $0) SCRIPT=$(basename $SELF) CWD=$(dirname $SELF) STACKS=$CWD SETUP=$STACKS/_vm LOGFOLDER={{ vm_stack_logpath }} LOGFILE=$LOGFOLDER/$LOGNAME.$LOGEXT MASK="{{ vm_stack_backup_header}}${HOSTNAME}{{ vm_stack_backup_common }}NAME_DATE" OPTION=$1 OPTION="${OPTION:=help}" STACKNAME=$2 PROFILE=$3 cd $STACKS # Send notification (0=no, 1=yes) NOTIFY=1 # Rotate logfile doRotateLogfile() { if [ -f ${LOGFILE} ]; then NOW=`date +"%Y%m%d-%H%M%S"` mv ${LOGFILE} ${LOGFOLDER}/${LOGNAME}_${NOW}.${LOGEXT} fi touch ${LOGFILE} } # 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] [PROFILE]" echo echo "OPTION:" echo " help - Show this help" echo " up - Up the stacks" echo " down - Down the stacks" echo " recycle - Up/Down 1 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 " buildup - Build & Up the stack" 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 }}:6000/zogg \ >/dev/null 2>&1 fi } dockerCompose() { ACTION=$1 NAME=$2 FLAGS=$3 NOW=`date +"%Y/%m/%d %H:%M:%S"` echo "* { $ACTION: $1 }" echo "> $NOW" case $ACTION in BUILDUP) 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 --profile $PROFILE up --build -d ;; UP) 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 ;; PULL) docker compose pull --include-deps $2 ;; DOWN) docker compose down ;; START) docker compose start ;; STOP) docker compose stop -t 10 ;; PAUSE) docker compose pause ;; UNPAUSE) docker compose unpause ;; RESTART) docker compose restart ;; *) doHelp doNotify exit 1 ;; esac 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 buildup): dockerCompose "BUILDUP" "$name" "$FLAGS" "$PROFILE" ;; up): dockerCompose "UP" $name $FLAGS ;; down): dockerCompose "DOWN" $name $FLAGS ;; start): dockerCompose "START" $name $FLAGS ;; stop): dockerCompose "STOP" $name $FLAGS ;; pause): dockerCompose "PAUSE" $name $FLAGS ;; unpause): dockerCompose "UNPAUSE" $name $FLAGS ;; restart): dockerCompose "RESTART" $name $FLAGS ;; backup): dockerCompose "STOP" $name $FLAGS dockerBackupStack $name $FLAGS dockerCompose "START" $name $FLAGS ;; autostop): dockerCompose "STOP" $name $FLAGS ;; update): dockerCompose "DOWN" $name $FLAGS dockerCompose "PULL" $name $FLAGS dockerCompose "UP" $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 case $OPTION in recycle): doIterateFile down "$SETUP/{{ vm_stack_unitary }}" "" doIterateFile up "$SETUP/{{ vm_stack_unitary }}" "" ;; *) doIterateFile $OPTION "$SETUP/{{ vm_stack_unitary }}" "" ;; esac 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 buildup|up|start|pause | down|stop|unpause | update | restart|recycle | backup|self | autostop): doRotateLogfile doSync doIterate $OPTION $STACKNAME > >(tee -a $LOGFILE) 2>&1 doNotify doSync ;; help | *) doHelp doNotify exit 1 ;; esac exit 0