#! /bin/bash
# Afrihost - cpanel mysqlupgrade with backups

# cpanel check
if ! [ -f "/usr/local/cpanel/cpanel" ]; then
       echo "-" 
       exit
fi

pscript=$(basename $0)
TODAY=$(date  +"%Y-%b-%d")
YESTERDAY=$(date -d yesterday +"%Y-%b-%d")
PWDIR="/root/.preports/"$pscript""
OUTFILE="$PWDIR/`hostname`.sql_upgrade"
MYSQL_DIR="/var/lib/mysql"
LOG="/var/log/mysql-maintenance-backup.log"
LOCK="/run/lock/mysql-maintenance-backup.lock"
BACKUP_CANDIDATES=(
    "/backup"
    "/home" 
    "/"
)
DUMP_SCRIPT="/bin/bash /usr/local/afribin/maintanence/mysldumpall"
DUMP_SPACE_PATH="/home"

mysql_running()
{
    pgrep -x mysqld >/dev/null 2>&1 ||
    pgrep -x mariadbd >/dev/null 2>&1
}


log()
{
    echo "[$(date '+%F %T')] $*" | tee -a "$LOG"
}



## initial safety and run checks checks
if [[ $EUID -ne 0 ]]; then
    echo "ERROR: This script must be run as root."
    exit 1
fi

CONTROL="/tmp/mup2"
single_run_check()
{
      if [[ -f "$CONTROL" ]] ; then
          echo -e ${bldred}"Note: Script is already running or didn't exit correctly previously.${txtrst}
          - Check ps log and kill already running script or remove file and re-run script "$CONTROL""
          exit 2
      fi
      touch "$CONTROL"
}
single_run_check

if [[ ! -d "$MYSQL_DIR" ]]; then
    log "ERROR: MySQL directory does not exist: $MYSQL_DIR"
    exit 1
fi

if ! mysql_running; then
    log "ERROR: MySQL does not appear to be running. Aborting."
    exit 1
fi


# Define the valid options for the argument  
valid_options=("mariadb11.8" "mariadb11.4" "mariadb10.11" "mariadb10.5" "mariadb10.6" "mysql8" "mysql5.7")

# Check if the argument is provided
if [ $# -lt 1 ]; then
  echo -e "\n====== Afrihost Mysql/Mariadb upgrade - with backups ======"
  echo -e "\n[ ERROR ] Requires mysql/maria version to upgrade to as first argument."
  echo -e "\\nUSAGE: $0 ${valid_options[@]}"
  echo -e "\nexample: $0 mariadb10.11"
  echo -e "\n===================================================\n"
  exit 1
fi
  
# Check if the argument is a valid option
if [[ ! " ${valid_options[@]} " =~ " $1 " ]]; then
  echo "Error: Invalid argument. Valid options are: ${valid_options[*]}"
  exit 1
fi

#setting environment
env_set() 
{
if [ ! -d "$PWDIR" ]; then
                mkdir -p "$PWDIR" ;
        else
        rm -f $PWDIR/*
fi
}
env_set

sql_mode_check () {
if egrep  '\[client\]|\[mysql\]' /etc/my.cnf ; 
 then sed -i '/\[mysqld\]/a sql-mode=""' /etc/my.cnf ; 
fi
if ! egrep -q 'sql-mode' /etc/my.cnf  ;then
 echo "sql-mode=\"\"" >> /etc/my.cnf
 service mysql stop ; service mysqld stop ; /scripts/restartsrv_mysql
fi
}

# Check if the argument is a MariaDB version
if [[ $1 == mariadb* ]]; then
  { grep -q  MariaDB  /etc/yum.conf && echo -e "\n=== ERROR: MariaDB is excluded in yum.conf.Remove entry and re-run script===\n" && exit 1 ;  }
  if ! {  mysql --version  | grep -i maria || mysql --version  | grep -i "mysql  Ver 8" ; }  ; then
   installed_version=10.0
  else
   installed_version=$(mysql --version | awk '{print $5}' | awk -F "-"   '{print $1}' | awk -F "."   '{print $1"."$2}')
  fi
  required_version=$(echo $1 | awk -F'mariadb' '{print $2}')
  echo "Installed_version=$installed_version"
  echo "Required_version=$required_version"
if [ "$required_version" > "$installed_version" ] ; then
    echo "Requested version is higher than installed version"
    echo "Upgrading MariaDB to $1"
    echo -e "[INFO] This script would run \n[INFO] whmapi1 start_background_mysql_upgrade version="$required_version""
    echo "You have 10 seconds to press ctrl+c is something appears off!"
    sleep 20
    touch /root/.mysql_ugrade_start_$(date +"%Y"_"%m_%d_%R")
    sed -i '/innodb_force_recovery/d' /etc/my.cnf
    /scripts/restartsrv_mysql
    mysql -e  "SHOW ENGINES" | grep -i "innoDB.*YES"  | awk  '{print $1,$1}' || { echo "innodb_broken" ; touch /root/.mysqlupgrade_innodb_precheck.fail ; exit ; }
    rm -fv /etc/yum.repos.d/MariaDB*
    [ -d /var/softaculous ] && rm -rf /var/softaculous/

    MYSQLCHECK_RUN_FILE="/var/log/mysqlcheck.run.log"
if [[ ! -f "$MYSQLCHECK_RUN_FILE" ]] || [[ "$MYSQLCHECK_RUN_FILE" -ot "$(date -d '24 hours ago' '+%Y-%m-%d %H:%M:%S')" ]]; then
    echo "[$(date '+%F %T')] Starting mysqlcheck..." >> "$MYSQLCHECK_RUN_FILE"

    mysqlcheck --all-databases -r >> "$MYSQLCHECK_RUN_FILE" 2>&1
    rc=$?

    if [[ $rc -eq 0 ]]; then
        echo "[$(date '+%F %T')] mysqlcheck completed successfully." >> "$MYSQLCHECK_RUN_FILE"
    else
        echo "[$(date '+%F %T')] mysqlcheck failed with exit code $rc." >> "$MYSQLCHECK_RUN_FILE"
    fi
else
    echo "[$(date '+%F %T')] Skipping mysqlcheck; run file is less than 24 hours old."
fi

GIB=$((1024 * 1024 * 1024))
MYSQL_SIZE=$(du -s -B1 "$MYSQL_DIR" 2>/dev/null | awk '{print $1}')
[[ "$MYSQL_SIZE" =~ ^[0-9]+$ ]] && (( MYSQL_SIZE > 0 )) || { log "ERROR: Cannot determine MySQL directory size."; exit 1; }

REQUIRED=$((MYSQL_SIZE + 20 * GIB))
BACKUP_BASE=""
BEST_FREE=0

for path in /backup /home /; do
    [[ -d "$path" ]] || continue
    FREE=$(df -P -B1 "$path" 2>/dev/null | awk 'END {print $4}')
    [[ "$FREE" =~ ^[0-9]+$ ]] || continue
    log "$path: $((FREE / GIB)) GiB available"
    if (( FREE >= REQUIRED && FREE > BEST_FREE )); then
        BACKUP_BASE="$path"
        BEST_FREE="$FREE"
    fi
done

if [[ -n "$BACKUP_BASE" ]]; then
    DESTINATION=""
    for attempt in {1..65}; do
        SUFFIX=$((RANDOM % 65 + 499))
        CANDIDATE="${BACKUP_BASE%/}/mysql_orig_${SUFFIX}"
        [[ "$BACKUP_BASE" == "/" ]] && CANDIDATE="/mysql_orig_${SUFFIX}"
        if mkdir "$CANDIDATE" 2>/dev/null; then DESTINATION="$CANDIDATE"; break; fi
    done
    [[ -n "$DESTINATION" ]] || { log "ERROR: Cannot create backup destination."; exit 1; }

    log "Using rsync backup: $DESTINATION"
    whmapi1 configureservice service=mysql enabled=1 monitored=0 >> "$LOG" 2>&1 ||
        { log "ERROR: WHM service configuration failed."; exit 1; }

    MYSQL_STOP_ATTEMPTED=1
    /scripts/restartsrv_mysql --stop >> "$LOG" 2>&1
    for ((i=0; i<120; i++)); do
        if ! pgrep -x mysqld >/dev/null 2>&1 && ! pgrep -x mariadbd >/dev/null 2>&1; then break; fi
        sleep 1
    done
    if pgrep -x mysqld >/dev/null 2>&1 || pgrep -x mariadbd >/dev/null 2>&1; then
        log "ERROR: MySQL did not stop."; exit 1
    fi

    if rsync -avP "$MYSQL_DIR/" "$DESTINATION/" >> "$LOG" 2>&1; then
        log "Rsync completed: $DESTINATION"
    else
        RC=$?
        log "ERROR: Rsync failed ($RC)."
        /scripts/restartsrv_mysql --start >> "$LOG" 2>&1 && MYSQL_STOP_ATTEMPTED=0
        exit "$RC"
    fi

    /scripts/restartsrv_mysql --start >> "$LOG" 2>&1 || { log "CRITICAL: MySQL failed to start."; exit 1; }
    MYSQL_STOP_ATTEMPTED=0

else
    FREE=$(df -P -B1 /home 2>/dev/null | awk 'END {print $4}')
    if [[ ! "$FREE" =~ ^[0-9]+$ ]] || (( FREE < MYSQL_SIZE )); then
        log "ERROR: Insufficient space for rsync or dump fallback."; exit 1
    fi
    log "Insufficient rsync space; running dump fallback."
    "$DUMP_SCRIPT" >> "$LOG" 2>&1 || { RC=$?; log "ERROR: Dump failed ($RC)."; exit "$RC"; }
    log "MySQL dump completed."
fi

#    /scripts/restartsrv_mysql --stop ; /scripts/restartsrv_mysql --stop
#    rsync -avP /var/lib/mysql/ /backup/mysql_orig_"$(echo $((RANDOM % 65 + 499)))"/
#    /scripts/restartsrv_mysql --start
    mysql -e  "SHOW ENGINES" | grep -i "innoDB.*YES"  | awk  '{print $1,$1}' || { echo "innodb_broken" ; touch /root/.mysqlupgrade_innodb_precheck.fail ; exit ; }
    whmapi1 start_background_mysql_upgrade version="$required_version"
    sql_mode_check
    echo "== $TODAY [ mysql upgrade running in the background - check if it's busy with  #ps auwfx| grep mysql ; mysql V   ]" >> $OUTFILE
    touch /root/.mysql_ugrade_end_$(date +"%Y"_"%m_%d_%R")
  else
    echo "MariaDB already seems to be set to upgrade version or there's some other error"
    exit 0
  fi
fi

# Check if the argument is a MySQL version
if [[ $1 == mysql* ]]; then
  if [[ $(mysql --version | awk '{print $5}' | cut -d, -f1) == *"mariadb"* ]]; then
    echo "Error: Cannot upgrade to MySQL while running MariaDB."
    exit 1
  fi
  installed_version=$(mysql --version | awk '{print $5}' | awk -F "." '{print $1"."$2}')
  required_version=$(echo "$1" | awk -F'mysql' '{print $2}')
  if [[ "$required_version" > "$installed_version" ]]; then
    echo -e "Upgrading Mysql $installed_version to $1"
    if echo $required_version | grep 8 ; then required_version_fmt=8.0 ; fi
    echo -e "[INFO] This script would run \n[INFO] whmapi1 start_background_mysql_upgrade version="$required_version_fmt""
    echo -e "You have 10 seconds to press ctrl+c is something appears off!"
    sleep 20
    touch /root/.mysql_ugrade_start_$(date +"%Y"_"%m_%d_%R")
    sed -i '/innodb_force_recovery/d' /etc/my.cnf
    /scripts/restartsrv_mysql
    mysql -e  "SHOW ENGINES" | grep -i "innoDB.*YES"  | awk  '{print $1,$1}' || { echo "innodb_broken" ; touch /root/.mysqlupgrade_innodb_precheck.fail ; exit ; }
    rm -fv /etc/yum.repos.d/MariaDB*
    [ -d /var/softaculous ] && rm -rf /var/softaculous/

    MYSQLCHECK_RUN_FILE="/var/log/mysqlcheck.run.log"
if [[ ! -f "$MYSQLCHECK_RUN_FILE" ]] || [[ "$MYSQLCHECK_RUN_FILE" -ot "$(date -d '24 hours ago' '+%Y-%m-%d %H:%M:%S')" ]]; then
    echo "[$(date '+%F %T')] Starting mysqlcheck..." >> "$MYSQLCHECK_RUN_FILE"

    mysqlcheck --all-databases -r >> "$MYSQLCHECK_RUN_FILE" 2>&1
    rc=$?

    if [[ $rc -eq 0 ]]; then
        echo "[$(date '+%F %T')] mysqlcheck completed successfully." >> "$MYSQLCHECK_RUN_FILE"
    else
        echo "[$(date '+%F %T')] mysqlcheck failed with exit code $rc." >> "$MYSQLCHECK_RUN_FILE"
    fi
else
    echo "[$(date '+%F %T')] Skipping mysqlcheck; run file is less than 24 hours old."
fi

    /scripts/restartsrv_mysql --stop ; /scripts/restartsrv_mysql --stop
    rsync -avP /var/lib/mysql/ /backup/mysql_orig_"$(echo $((RANDOM % 65 + 499)))"/
    /scripts/restartsrv_mysql --start
    mysql -e  "SHOW ENGINES" | grep -i "innoDB.*YES"  | awk  '{print $1,$1}' || { echo "innodb_broken" ; touch /root/.mysqlupgrade_innodb_precheck.fail ; exit ; }
    whmapi1 start_background_mysql_upgrade version="$required_version_fmt"
    sql_mode_check
    echo "== $TODAY [  mysql upgrade running in the background - check if it's busy with  #ps auwfx| grep mysql ; mysql V   ]" >> $OUTFILE
    touch /root/.mysql_ugrade_end_$(date +"%Y"_"%m_%d_%R")
  else
    echo "No need to upgrade MySQL"
    exit 0
  fi
fi
