403Webshell
Server IP : 172.67.149.12  /  Your IP : 162.159.114.31
Web Server : Apache
System : Linux vm3310.eosdns.net 4.18.0-553.132.1.el8_10.x86_64 #1 SMP Thu Jun 11 14:27:43 UTC 2026 x86_64
User : carnalmedia ( 1000)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /mojo/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /mojo/migration_tool
#!/bin/bash
#
# Script: migration_tool
#
# Usage: migration_tool -a <action> -o <old host> [ -f <path> ]
#
# Description: Migration tool for MojoHost servers
#
# Author: Oliver Mikitiuk
#
# Changelog:
# * 12.06.2026: Oliver Mikitiuk
# - Initial write


confirmOrExit() {

    while true; do
        echo -n "Ready to continue? [y/n]: "
        read answer
        answer="${answer,,}"
        case "$answer" in
            y|yes)
                return 0
                ;;
            n|no)
                echo "Exiting..."
                exit
                ;;
            *)
                echo "Please enter 'y' or 'n'."
                ;;
        esac
    done

}

confirmOrSkip() {

    while true; do
        echo -n "Ready to continue? [y/n]: "
        read answer
        answer="${answer,,}"
        case "$answer" in
            y|yes)
                return 0
                ;;
            n|no)
                echo "Skipping..."
                return 1
                ;;
            *)
                echo "Please enter 'y' or 'n'."
                ;;
        esac
    done

}

sshExec () {

    ssh \
        -o BatchMode=yes \
        -o PreferredAuthentications=publickey \
        -o PasswordAuthentication=no \
        -o StrictHostKeyChecking=no \
        -o UserKnownHostsFile=/dev/null \
        -o ConnectTimeout=3 \
        -o LogLevel=ERROR \
        "$@"

}

rsyncExec() {

    rsync \
        -e "ssh \
        -o BatchMode=yes \
        -o PreferredAuthentications=publickey \
        -o PasswordAuthentication=no \
        -o StrictHostKeyChecking=no \
        -o UserKnownHostsFile=/dev/null \
        -o ConnectTimeout=3 \
        -o LogLevel=ERROR" \
        "$@"

}

checkSSHConnection() {

    if sshExec "$OLDHOSTNAME" true 2>/dev/null; then
        return 0
    else
	echo 
        echo "Cannot connect to $OLDHOSTNAME via SSH."
        echo
        echo "To fix SSH access, try to run these commands:"

        local pub_key
        pub_key=$(cat /root/.ssh/id_rsa.pub)
        echo "1) On $OLDHOSTNAME, add SSH public key:"
        echo "   echo '$pub_key' >> /root/.ssh/authorized_keys"
        echo

        echo "2) On $OLDHOSTNAME, whitelist IP:"
	echo " For CentOS 7:"
        echo " mjact_fw -a add -t migration -i $WAN_IP -p 22 -z"
        echo
	echo " For CentOS 8:"
        echo " mjact_fw -a add -i $WAN_IP"
        echo
    fi

    confirmOrExit
    if sshExec "$OLDHOSTNAME" true 2>/dev/null; then
        return 0
    else
        echo "[Error] Cannot connect to $OLDHOSTNAME via SSH. Please manually add the SSH access."
        exit 1
    fi
    echo

}	

createMigrationDir() {

    local hostname="$1"	

    sshExec "$hostname" "mkdir -p '$MIGRATION_DIR'"
    sshExec "$hostname" "mkdir -p '$DATABASES_DIR'"

}

prepareEnv() {

    validateHostnames
    checkSSHConnection
    createMigrationDir "$NEWHOSTNAME"
    createMigrationDir "$OLDHOSTNAME"
    cd "$MIGRATION_DIR"

}	

validateHostnames() {

    if [[ -z "$OLDHOSTNAME" ]]; then
        echo "[ERROR] Old Hostname must be provided"
        exit 1
    fi

    if checkHostPointsHere $(hostname); then
        NEWHOSTNAME=$(hostname)
    else 
        NEWHOSTNAME="$WAN_IP"
    fi

    if checkHostPointsHere "$OLDHOSTNAME"; then
        echo "[ERROR] Old Hostname should not pointing locally"
	exit 1
    fi

}

checkHostPointsHere() {

    local hostname="$1"
    local resolved_ip=$(getent ahostsv4 "$hostname" | head -n1 | awk '{print $1}')
    local local_ips=$(ip addr show | awk '/inet / {print $2}' | cut -d/ -f1)
    
    if [[ -z "$resolved_ip" ]]; then
        echo "[ERROR] Cannot resolve IPv4 for $hostname"
        exit 1
    fi
    
    if echo "$local_ips" | grep -qw "$resolved_ip"; then
        return 0
    else
        return 1
    fi

}

checkServiceActive() {

    local name="$1"
    local service="$2"
    local hostname="$3"

    if sshExec "$hostname" "systemctl is-active --quiet $service >/dev/null 2>&1 || pgrep -x $service >/dev/null 2>&1"; then
        echo "${name}: Yes"
        return 0
    else
        echo "${name}: No"
        return 1
    fi

}

checkActiveServices() {

    local hostname="$1"

    checkServiceActive "Apache" "httpd" "$hostname"
    checkServiceActive "Nginx" "nginx" "$hostname"
    checkServiceActive "Redis" "redis" "$hostname"
    checkServiceActive "Docker" "docker" "$hostname"

}

checkApacheModules() {

    local hostname="$1"

    local apache_modules_list
    local apache_modules=(
        prxp_module
        psso_module
    )

    if checkServiceActive "Apache" "httpd" "$hostname" >/dev/null 2>&1; then

        apache_modules_list=$(sshExec "$hostname" "httpd -M 2>/dev/null || apachectl -M 2>/dev/null")

        echo "Apache modules:"

        for module in "${apache_modules[@]}"; do

            if echo "$apache_modules_list" | grep -qw "$module"; then
                echo "  $module: Yes"
            else
                echo "  $module: No"
            fi

        done
    fi

}

checkNginxModules() {

    local hostname="$1"

    local nginx_modules_list
    local nginx_modules=(
        realip
	geoip2
    )

    if checkServiceActive "Nginx" "nginx" "$hostname" >/dev/null 2>&1; then

        nginx_modules_list=$(sshExec "$hostname" "nginx -V 2>&1")
    
        echo "Nginx modules:"
    
        for module in "${nginx_modules[@]}"; do
    
            if echo "$nginx_modules_list" | grep -q "$module"; then
                echo "  $module: Yes"
            else
                echo "  $module: No"
            fi
    
        done

    fi
}

checkFileExist() {

    local name="$1"
    local file="$2"
    local hostname="$3"

    if [[ "$locate_exist" == "true" ]]; then
        if sshExec "$hostname" "locate -b \\${file} | grep -q '.'"; then
            echo "${name}: Yes"
            return 0
        else
            echo "${name}: No"
            return 1
        fi
    else
        if sshExec "$hostname" "find /home/httpd/html /home -maxdepth 6 -type f -name $file 2>/dev/null | grep -q '.'"; then
            echo "${name}: Yes"
            return 0
        else
            echo "${name}: No"
            return 1
        fi
    fi

}

checkInstalledApplications() {

    local hostname="$1"

    if sshExec "$hostname" "command -v locate >/dev/null 2>&1"; then
        local locate_exist="true"
        sshExec "$hostname" "updatedb"
    else
        local locate_exist="false"
    fi
    echo "Applications:"
    checkFileExist "  WordPress" "wp-config.php" "$hostname"
    checkFileExist "  Nats" "nats.txt" "$hostname"
    checkFileExist "  ElevatedX" "cmsinclude.ini.php" "$hostname"
    checkFileExist "  KVS" "setup_db.php" "$hostname"
    checkFileExist "  Mechbunny" "functions.mb.php" "$hostname"

}

checkPHPVersions() {
	
    local hostname="$1"

    sshExec "$hostname" 'bash -s' <<'EOF'
        versions_list=()
        
        while IFS= read -r bin; do
            if [[ -x "$bin" ]]; then
                version=$("$bin" -v 2>/dev/null | head -1 | grep -oE "[0-9]+\.[0-9]+")
                [[ -n "$version" ]] && versions_list+=("$version")
            fi
        done < <(find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin /usr/local/php* /opt -type f \( -name "php" -o -name "php[0-9]*" \) 2>/dev/null)
        
        if [ ${#versions_list[@]} -gt 0 ]; then
            printf "%s\n" "${versions_list[@]}" | sort -uV | xargs echo "PHP versions:"
        else
            echo "PHP versions: Unknown"
        fi
EOF

}

checkPHPModulesAndSettings() {

    local hostname="$1"

    sshExec "$hostname" 'bash -s' <<'EOF'

        php_modules=(
            mbstring
            "ChartDirector PHP API"
        )

        php_settings=(
            memory_limit
            post_max_size
            upload_max_filesize
            short_open_tag
        )

        declare -A seen_versions

        while IFS= read -r bin; do

            if [[ ! -x "$bin" ]] ; then
                continue
            fi

            version=$("$bin" -v 2>/dev/null | head -1 | grep -oE "[0-9]+\.[0-9]+")
            if [[ -z "$version" ]] ; then
                continue
            fi

            if [[ -n "${seen_versions[$version]}" ]] ; then
                continue
	    fi
            seen_versions["$version"]=1

            echo "PHP $version:"
            
            echo "  Modules:"
            for module in "${php_modules[@]}"; do

                if "$bin" -m 2>/dev/null | grep -iq "^$module$"; then
                    echo "    $module: Yes"
                else
                    echo "    $module: No"
                fi

            done

            echo "  Settings:"
            for setting in "${php_settings[@]}"; do

		value=$("$bin" -i 2>/dev/null | grep "^$setting" | awk '{print $3}')

                if [[ -z "$value" ]]; then
                    echo "    $setting: Unknown"
                else
                    echo "    $setting: $value"
                fi

            done

            echo

        done < <(find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin /usr/local/php* /opt -type f \( -name "php" -o -name "php[0-9]*" \) 2>/dev/null)

EOF

}

checkMySQLVersion() {

    local hostname="$1"
    local version_output
    local version

    if checkServiceActive "MariaDB" "mariadb" "$hostname" >/dev/null 2>&1 || checkServiceActive "MySQL" "mysqld" "$hostname" >/dev/null 2>&1 || checkServiceActive "MySQL" "mysql" "$hostname" >/dev/null 2>&1 ; then
        version_output=$(sshExec "$hostname" 'mysql -e "SELECT VERSION();" 2>/dev/null' | grep -v VERSION)
        version=$(echo "$version_output" | grep -oE "[0-9]+\.[0-9]+(\.[0-9]+)?")

        if echo "$version_output" | grep -qi "mariadb"; then
            echo "MariaDB version: $version"
	    return 0
        else
            echo "MySQL version: $version"
	    return 0
        fi
    else
        echo "MySQL: No"
	return 1
    fi

}

checkMySQLSettings() {

    local hostname="$1"

    local mysql_settings=(
        read_only
        innodb_strict_mode
        sql_mode
    )

    if checkMySQLVersion "$hostname" >/dev/null 2>&1; then
        echo "MySQL Settings:"
        for setting in "${mysql_settings[@]}"; do
    
            value=$(sshExec "$hostname" "mysql -NBe \"SHOW GLOBAL VARIABLES LIKE '$setting';\" 2>/dev/null" | awk '{print $2}')
    
            if [[ -z "$value" ]]; then
                value="Unknown"
            fi
    
            if [[ "$setting" == "sql_mode" ]]; then
    	    value=$( echo "$value" | sed 's|,|\n            |g')
    	    echo "  $setting: $value"
            else
                echo "  $setting: $value"
            fi
    
        done
    fi

}

checkControlPanelActive() {

    local hostname="$1"

    if checkServiceActive "cPanel" "cpanel" "$hostname" >/dev/null 2>&1; then
        echo "Control panel (cPanel): Yes"
	return 0
    elif checkServiceActive "DirectAdmin" "directadmin" "$hostname" >/dev/null 2>&1; then
        echo "Control panel (DirectAdmin): Yes"
	return 0
    elif checkServiceActive "Webmin" "webmin" "$hostname" >/dev/null 2>&1; then
        echo "Control panel (Webmin): Yes"
	return 0
    else
        echo "Control panel: No"
	return 1
    fi

}

checkOSName() {

    local hostname="$1"
    local os_name

    os_name=$(sshExec "$hostname" '
        if [[ -f /etc/os-release ]]; then
            grep "^PRETTY_NAME=" /etc/os-release | cut -d= -f2- | tr -d "\""
        elif [[ -f /etc/centos-release ]]; then
            cat /etc/centos-release
        elif [[ -f /etc/system-release ]]; then
            cat /etc/system-release
        else
            uname -sr
        fi
    ')

    if [[ -z $os_name ]] ; then
        echo "OS: Unknown"
    else
        echo "OS: $os_name"
    fi

}

compareBlocks(){

    pr -m -t -w 140 "$@"

}

compareServers() {

    echo

    compareBlocks <(echo "====== $NEWHOSTNAME Installation Info ======") <(echo "====== $OLDHOSTNAME Installation Info ======")
    
    compareBlocks <(checkOSName "$NEWHOSTNAME") <(checkOSName "$OLDHOSTNAME")
    
    compareBlocks <(checkControlPanelActive "$NEWHOSTNAME") <(checkControlPanelActive "$OLDHOSTNAME")
    
    echo
    
    compareBlocks <(checkActiveServices "$NEWHOSTNAME") <(checkActiveServices "$OLDHOSTNAME")
    
    compareBlocks <(checkMySQLVersion "$NEWHOSTNAME") <(checkMySQLVersion "$OLDHOSTNAME")
    
    compareBlocks <(checkPHPVersions "$NEWHOSTNAME") <(checkPHPVersions "$OLDHOSTNAME")
    
    echo
    
    compareBlocks <(checkApacheModules "$NEWHOSTNAME") <(checkApacheModules "$OLDHOSTNAME")

    echo
    
    compareBlocks <(checkMySQLSettings "$NEWHOSTNAME") <(checkMySQLSettings "$OLDHOSTNAME")
    
    echo
    
    compareBlocks <(checkPHPModulesAndSettings "$NEWHOSTNAME") <(checkPHPModulesAndSettings "$OLDHOSTNAME")
    
    compareBlocks <(checkInstalledApplications "$NEWHOSTNAME") <(checkInstalledApplications "$OLDHOSTNAME")
    
    compareBlocks <(echo "==================================================") <(echo "==================================================")
    
    echo

}


migrateWebData() {

    echo
    echo "Web data migration func is currently under development"
    echo

}

isDomainEnabled() {

    local domain="$1"
    local file="$2"

    grep -Ev '^#|^$' "$file" | grep -Fxq "$domain"
}

migrateSSLCert() {

    local cert_name="$1"
    local le_account="$2"

    rsyncExec -a "$OLDHOSTNAME:/etc/letsencrypt/live/$cert_name/" "/etc/letsencrypt/live/$cert_name/" >/dev/null 2>&1 || {
        echo "[WARN] Failed to copy live cert directory: $cert_name"
        return 1
    }

    rsyncExec -a "$OLDHOSTNAME:/etc/letsencrypt/archive/$cert_name/" "/etc/letsencrypt/archive/$cert_name/" >/dev/null 2>&1 || {
        echo "[WARN] Failed to copy archive cert directory: $cert_name"
        return 1
    }

    rsyncExec -a "$OLDHOSTNAME:/etc/letsencrypt/renewal/$cert_name.conf" "/etc/letsencrypt/renewal/$cert_name.conf" >/dev/null 2>&1 || {
        echo "[WARN] Failed to copy renewal config: $cert_name"
        return 1
    }

    if [[ -n "$le_account" ]]; then
        sed -i "s|^account *=.*|account = $le_account|" "/etc/letsencrypt/renewal/$cert_name.conf"
    fi

}

recreateApacheConfigs() {

    local apache_vhost_files
    local file
    local block
    local servername
    local cert_name
    local le_account
    local apache_vhosts_list_file="$MIGRATION_DIR/apache_vhosts_list.txt"

    declare -A vhost_map

    if ! checkServiceActive "Apache" "httpd" "$OLDHOSTNAME" >/dev/null 2>&1; then
        echo "[INFO] Apache is not active on $OLDHOSTNAME, skipping"
        return 0
    fi

    if ! checkServiceActive "Apache" "httpd" "$NEWHOSTNAME" >/dev/null 2>&1; then
        echo "[INFO] Apache is not active on $NEWHOSTNAME, skipping"
        return 0
    fi

    apache_vhost_files=$(sshExec "$OLDHOSTNAME" "httpd -S 2>/dev/null" | awk '/\(/ {print $NF}' | tr -d '(' | cut -d: -f1 | sort -u)

    le_account=$(awk -F' *= *' '$1=="account" {print $2; exit}' "/etc/letsencrypt/renewal/${NEWHOSTNAME}.conf")    

    for file in $apache_vhost_files; do

        while IFS= read -r line; do

            if [[ "$line" =~ \<VirtualHost ]]; then
                block=""
                servername=""
            fi

            block+="$line"$'\n'

            if [[ "$line" =~ ServerName ]]; then
                servername=$(echo "$line" | awk '{print $2}' | tr -d '"')
		servername="${servername#www.}"
            fi

            if [[ "$line" =~ \<\/VirtualHost\> ]]; then

                if [[ -z "$servername" ]]; then
                    servername="unknown"
                fi

                vhost_map["$servername"]+="$block"$'\n'

                block=""
                servername=""
            fi

        done < <(sshExec "$OLDHOSTNAME" "cat $file 2>/dev/null")

    done

    if [[ ! -f "$apache_vhosts_list_file" ]]; then
    
        echo "# List of Apache vhosts to migrate. Edit it to exclude vhosts if needed." > "$apache_vhosts_list_file"
    
        for servername in "${!vhost_map[@]}"; do
    
            if [[ "$servername" == "$OLDHOSTNAME" ]]; then
                continue
            fi
    
            echo "$servername"
    
        done | sort -u >> "$apache_vhosts_list_file"
    
    fi

    echo "[INFO] Apache vhosts list saved to $apache_vhosts_list_file . Edit it to exclude vhosts if needed."
    confirmOrExit

    for servername in "${!vhost_map[@]}"; do
    
        if ! isDomainEnabled "$servername" "$apache_vhosts_list_file"; then
            continue
        fi

        local target_file="/etc/httpd/sites-available/${servername}.conf"
    
        if [[ -f "$target_file" ]]; then
            echo "[INFO] Config already exists, skipping: $servername"
            continue
        fi

        echo "${vhost_map[$servername]}" | \
        sed "s|/home/httpd/logs/|/var/log/httpd/domlog/|g" | \
        sed "s|<VirtualHost .*:80>|<VirtualHost $WAN_IP:80>|g" | \
        sed "s|<VirtualHost .*:443>|<VirtualHost $WAN_IP:443>|g" \
        > "$target_file"

        ln -sf "$target_file" "/etc/httpd/sites-enabled/${servername}.conf"

        echo "[OK] Config created: $servername"

        cert_name=$(echo "${vhost_map[$servername]}" | grep -v "#" | awk '/SSLCertificateFile/ {print $2}' | awk -F'/' '{print $(NF-1)}' | head -n1 )

        if [[ -n "$cert_name" ]]; then
            migrateSSLCert "$cert_name" "$le_account"
        fi
    
    done
    
}

recreateNginxConfigs() {

    local nginx_config
    local nginx_vhosts_list_file="$MIGRATION_DIR/nginx_vhosts_list.txt"
    local line
    local block
    local servername
    local cert_name
    local le_account


    local in_server=0
    local depth=0

    declare -A vhost_map

    if ! checkServiceActive "Nginx" "nginx" "$OLDHOSTNAME" >/dev/null 2>&1; then
        echo "[INFO] Nginx is not active on $OLDHOSTNAME, skipping"
        return 0
    fi

    if ! checkServiceActive "Nginx" "nginx" "$NEWHOSTNAME" >/dev/null 2>&1; then
        echo "[INFO] Nginx is not active on $NEWHOSTNAME, skipping"
        return 0
    fi

    le_account=$(awk -F' *= *' '$1=="account" {print $2; exit}' "/etc/letsencrypt/renewal/${NEWHOSTNAME}.conf")

    nginx_config=$(sshExec "$OLDHOSTNAME" "nginx -T 2>/dev/null")

    while IFS= read -r line; do

        if [[ "$line" =~ ^[[:space:]]*# ]]; then
            continue
        fi

        if [[ $in_server -eq 0 && "$line" =~ ^[[:space:]]*server[[:space:]]*\{ ]]; then

            in_server=1
            depth=1

            block="$line"$'\n'
            servername=""

            continue
        fi

        if [[ $in_server -eq 0 ]]; then
            continue
        fi

        block+="$line"$'\n'

        if [[ "$line" =~ ^[[:space:]]*server_name[[:space:]] ]]; then
            servername=$(echo "$line" | awk '{print $2}' | sed 's/;$//')
	    servername="${servername#www.}"
        fi

        opens=$(grep -o '{' <<< "$line" | wc -l)
        closes=$(grep -o '}' <<< "$line" | wc -l)

        ((depth += opens))
        ((depth -= closes))

        if [[ $depth -eq 0 ]]; then

            if [[ -n "$servername" ]]; then
                vhost_map["$servername"]+="$block"$'\n'
            fi

            in_server=0
            block=""
            servername=""
        fi

    done <<< "$nginx_config"

    if [[ ! -f "$nginx_vhosts_list_file" ]]; then

        echo "# List of Nginx vhosts to migrate. Edit it to exclude vhosts if needed." > "$nginx_vhosts_list_file"

        for servername in "${!vhost_map[@]}"; do

            if [[ -z "$servername" || "$servername" == "_" || "$servername" == "localhost" || "$servername" == "$OLDHOSTNAME" ]]; then
                continue
            fi

            echo "$servername"

        done | sort -u >> "$nginx_vhosts_list_file"

    fi

    echo "[INFO] Nginx vhosts list saved to $nginx_vhosts_list_file . Edit it to exclude vhosts if needed."
    confirmOrExit

    for servername in "${!vhost_map[@]}"; do

        if ! isDomainEnabled "$servername" "$nginx_vhosts_list_file"; then
            continue
        fi

        local target_file="/etc/nginx/sites-available/${servername}.conf"

        if [[ -f "$target_file" ]]; then
            echo "[INFO] Config already exists, skipping: $servername"
            continue
        fi

        echo "${vhost_map[$servername]}" | \
        sed "s|listen .*:80|listen $WAN_IP:80|g" | \
        sed "s|listen .*:443|listen $WAN_IP:443|g" \
        > "$target_file"

        ln -sf "$target_file" "/etc/nginx/sites-enabled/${servername}.conf"

        echo "[OK] Config created: $servername"

        cert_name=$(echo "${vhost_map[$servername]}" | grep -v "#" | awk '/ssl_certificate/ {print $2}' | awk -F'/' '{print $(NF-1)}' | head -n1 )

        if [[ -n "$cert_name" ]]; then
            migrateSSLCert "$cert_name" "$le_account"
        fi

    done

}

recreateWebConfigs() {

    recreateApacheConfigs
    recreateNginxConfigs

}

migrateDatabases() {

    if ! checkMySQLVersion "$OLDHOSTNAME" >/dev/null 2>&1 ; then
        echo "[WARN] MySQL is not active on the $OLDHOSTNAME"
        return 1
    elif ! checkMySQLVersion "$NEWHOSTNAME" >/dev/null 2>&1 ; then
        echo "[WARN] MySQL is not active on the $NEWHOSTNAME"
        return 1
    fi

    local databases_file="$DATABASES_DIR/databases.txt"
    local db_migration_log="$DATABASES_DIR/database_migration.log"
    local local_dump_file="$DATABASES_DIR/$(hostname)_dump.sql"
    local failed_db_move


    if [[ ! -f "$local_dump_file" ]]; then
        echo "[INFO] Creating full local dump file: $local_dump_file"
	mysqldump --all-databases > "$local_dump_file" 2>/dev/null
    fi

    if [[ ! -f "$databases_file" ]]; then
        echo "# List of databases to migrate. Edit this file to exclude any databases." > "$databases_file"        	    
        sshExec "$OLDHOSTNAME" 'mysql -N -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "^(mysql|information_schema|performance_schema|postfix|roundcube|sys$|mojotest)"' >> "$databases_file"  
    fi

    echo "[INFO] Please review the databases that will be migrated:"
    echo "======= Databases ======="
    cat "$databases_file" | grep -Ev "#"
    echo "========================="
    echo "[INFO] Database list saved to $databases_file . Edit it to exclude databases if needed."
    confirmOrExit

    echo 
    echo "[INFO] Migrating databases..."
    while IFS= read -r database; do
	if [[ -z "$database" || "$database" =~ ^# ]]; then
	    continue    	
        fi

	if sshExec -n "$OLDHOSTNAME" "mysqldump --databases '$database' > '$DATABASES_DIR/${database}_dump.sql'" >/dev/null 2> >(grep -v "Deprecated" >> "$db_migration_log") && 
	rsyncExec -a "$OLDHOSTNAME":"$DATABASES_DIR"/${database}_dump.sql "$DATABASES_DIR"/${database}_dump.sql >/dev/null 2>>"$db_migration_log" &&
	mysql < "$DATABASES_DIR"/${database}_dump.sql >/dev/null 2> >(grep -v "Deprecated" >> "$db_migration_log") ; then
            echo "[OK] $database"
        else
            echo "[ERROR] $database"
	    failed_db_move="true"
        fi	    
	
    done < "$databases_file"	
    echo

    if [[ "$failed_db_move" == "true" ]]; then
        echo "[ERROR] Some databases failed to migrate, please check the log file: $db_migration_log"
    else
        echo "[OK] Databases have been migrated"
    fi
    echo

}

recreateMySQLUsers() {

    if ! checkMySQLVersion "$OLDHOSTNAME" >/dev/null 2>&1 ; then
        echo "[WARN] MySQL is not active on the $OLDHOSTNAME"
        return 1
    elif ! checkMySQLVersion "$NEWHOSTNAME" >/dev/null 2>&1 ; then
        echo "[WARN] MySQL is not active on the $NEWHOSTNAME"
        return 1
    fi

    local users_file="$DATABASES_DIR/mysql_users.txt"
    local grants_file="$DATABASES_DIR/mysql_grants.sql"
    local bad_hash_users_file="$DATABASES_DIR/mysql_bad_hash_users.txt"
    local backup_file="$DATABASES_DIR/mysql_system_db_backup.sql"
    local mysql_password_column
    local bad_hash_count
    local has_password_column=$(sshExec "$OLDHOSTNAME" "mysql -N -B -e \"SHOW COLUMNS FROM mysql.user LIKE 'Password';\" 2>/dev/null")
    local mysql_users_exclude="(
        'PUBLIC',
        'debian-sys-maint',
        'root',
        'mysql',
        'mysql.sys',
        'mysql.session',
        'mariadb',
        'mariadb.sys',
        'postfix',
        'roundcube',
        'netdata',
        'mojotest',
        'repl',
        ''
        )"

    if [[ -n "$has_password_column" ]]; then
        mysql_password_column="password"
    else
        mysql_password_column="authentication_string"
    fi

    if [[ ! -f "$bad_hash_users_file" ]]; then
        sshExec "$OLDHOSTNAME" "
            mysql -B -N -e \"
            SELECT CONCAT('\'', user,'\'@\'', host, '\'')
            FROM mysql.user
            WHERE user NOT IN $mysql_users_exclude
            AND LENGTH($mysql_password_column) != 41
            \" 2>/dev/null
            " >> "$bad_hash_users_file"
    fi

    if [[ ! -f "$backup_file" ]]; then
        echo "[INFO] Creating local mysql database backup: $backup_file"
        mysqldump mysql > "$backup_file" 2>/dev/null
    fi

    if [[ ! -f "$users_file" ]]; then
        #echo "[INFO] MySQL users file not found, creating: $users_file"
	echo "# List of MySQL users to recreate. Edit this file to exclude any MySQL users." > "$users_file"

        sshExec "$OLDHOSTNAME" "
            mysql -B -N -e \"
            SELECT CONCAT('\'', user,'\'@\'', host, '\'')
            FROM mysql.user
            WHERE user NOT IN $mysql_users_exclude
            AND LENGTH($mysql_password_column) = 41
            \" 2>/dev/null
            " >> "$users_file"
    fi

    echo "[INFO] Please review the MySQL users that will be recreated:"
    echo
    echo "======= MySQL users ======="
    cat "$users_file" | grep -Ev "#"
    echo "==========================="
    echo
    echo "[INFO] MySQL users list saved to $users_file . Edit it to exclude users if needed."
    if [[ -s "$bad_hash_users_file" ]]; then
        echo "[WARN] Some MySQL users have invalid password hashes and will NOT be migrated. List saved to $bad_hash_users_file"
    fi
    confirmOrExit

    if [[ ! -f "$grants_file" ]]; then
        if [[ -z "$has_password_column"  ]]; then
            sshExec "$OLDHOSTNAME" "
                mysql -B -N -e \"
                SELECT user,host,authentication_string
                FROM mysql.user
                WHERE user NOT IN $mysql_users_exclude
		AND length(authentication_string) = 41
                 \" 2>/dev/null" | awk '{print "GRANT USAGE ON *.* TO '\`'" $1 "'\`'@'\`'" $2 "'\`' IDENTIFIED BY PASSWORD '\''" $3 "'\''"}' >> "$grants_file"
        fi

        while IFS= read -r line; do
            if [[ -z "$line" || "$line" =~ ^# ]]; then
                continue
            fi

            sshExec -n "$OLDHOSTNAME" "mysql -B -N -uroot -e 'SHOW GRANTS FOR $line;'"

        done < "$users_file" >> "$grants_file" 2>/dev/null
	sed -i 's/$/;/' "$grants_file"
    fi

    echo
    echo "[INFO] MySQL users grants saved to $grants_file . It will be imported on the next step. Edit it if needed."
    confirmOrExit
    echo

    if mysql < "$grants_file" >/dev/null 2>&1 ; then
        echo "[OK] MySQL users have been recreated"
    else
        echo "[ERROR] Failed to recreate MySQL users"
    fi


}	

createMailUsersFile() {

    local users_file="$1"

    echo "[INFO] Mail users file not found, creating template: $users_file"

    cat > "$users_file" <<EOF
# Format: [email protected] olduser oldpassword [newpassword]
# If newpassword is not provided, oldpassword will be used
#
# Example: [email protected] olduser_domcom password
# Example: [email protected] olduser_domcom old_password new_password
#
EOF

}

migrateMails() {

    local users_file="$MIGRATION_DIR/mail_users.txt"
    local failed_mails_move

    if ! command -v imapsync >/dev/null 2>&1; then
        echo "[INFO] Installing imapsync..."
        if yum install -y imapsync >/dev/null 2>&1; then
	    echo "[OK] imapsync installed"
        else
            echo "[ERROR] Failed to install imapsync"
	    return 1
        fi	    
    fi	

    if [[ ! -f "$users_file" ]]; then
        createMailUsersFile "$users_file"
	return 0
    fi

    while read -r newuser olduser oldpass newpass; do
        if [[ -z "$newuser" || "$newuser" =~ ^# ]]; then
            continue
        elif [[ -z "$olduser" || -z "$oldpass" ]]; then
            echo "[WARN] Skipping invalid line: NewUser: $newuser OldUser: $olduser Password:$oldpass"
            continue
        fi

        if [[ -z "$newpass" ]]; then
            newpass="$oldpass"
        fi

        if imapsync --host1 "$OLDHOSTNAME" --user1 "$olduser" --password1 "$oldpass" --host2 "$NEWHOSTNAME" --user2 "$newuser" --password2 "$newpass" --automap --skipcrossduplicates --maxsleep 0 >/dev/null 2>&1; then
            echo "[OK] $olduser -> $newuser"
        else
            echo "[ERROR] $olduser -> $newuser"
	    failed_mails_move="true"
        fi

    done < "$users_file"

    echo
    if [[ "$failed_mails_move" == "true" ]]; then
        echo "[ERROR] Some mails failed to migrate, please check the log files: $MIGRATION_DIR/LOG_imapsync/"
    else
        echo "[OK] Mails have been migrated"
    fi
    echo


}

recreateMailboxes() {

    local domains
    local aliases
    local newserver_postfixadmin_cli
    local oldserver_postfixadmin_cli
    local oldserver_mjact_mail
    local users_file="$MIGRATION_DIR/mail_users.txt"
    local mailboxes_list_file="$MIGRATION_DIR/mailboxes_list.txt"
    
    if ! checkServiceActive "Postfix" "postfix" "$NEWHOSTNAME" >/dev/null 2>&1; then
        echo "[ERROR] Postfix is NOT active on $NEWHOSTNAME, please recreate mailboxes manually"
        return 1
    fi
    
    if [[ ! -f "$users_file" ]]; then
        createMailUsersFile "$users_file"
    fi
    
    if ! grep -qxF "# Automatically generated by Recreate Mailboxes" "$users_file"; then
        echo >> "$users_file"
        echo "# Automatically generated by Recreate Mailboxes" >> "$users_file"
    fi
    
    if test -x /usr/share/postfixadmin/scripts/postfixadmin-cli >/dev/null 2>&1; then
        newserver_postfixadmin_cli="/usr/share/postfixadmin/scripts/postfixadmin-cli"
    elif command -v postfixadmin-cli >/dev/null 2>&1; then
        newserver_postfixadmin_cli="postfixadmin-cli"
    else
        echo "[ERROR] postfixadmin-cli not found on $NEWHOSTNAME, please install it or recreate mailboxes manually"
        return 1
    fi
    
    if checkServiceActive "Postfix" "postfix" "$OLDHOSTNAME" >/dev/null 2>&1; then
    
        echo "[INFO] Recreating Domains for Postfix..."
        domains=$(sshExec "$OLDHOSTNAME" "mysql -N -B -e 'SELECT domain FROM postfix.domain WHERE active=1 AND domain != \"ALL\" ;'" 2>/dev/null)
    
        if [[ -z "$domains" ]]; then
            echo "[WARN] No Domains found in PostfixAdmin database on $OLDHOSTNAME"
            return 1
        fi
    
        echo "$domains" | while IFS= read -r domain; do
            if [[ -z "$domain" ]] ;then
                continue
            elif "$newserver_postfixadmin_cli" domain view "$domain" >/dev/null 2>&1; then
                echo "[INFO] Domain already exists: $domain"
                continue
            fi
            
            if "$newserver_postfixadmin_cli" domain add "$domain" --aliases 30 --mailboxes 30 >/dev/null 2>&1; then
                echo "[OK] Domain created: $domain"
                continue
            else 
                echo "[ERROR] Failed to recreate domain: $domain"
            fi
        done
        echo
    
        echo "[INFO] Recreating Mail Aliases..."
        aliases=$(sshExec "$OLDHOSTNAME" "mysql -N -B -e 'SELECT address, goto FROM postfix.alias WHERE active=1 AND address != goto;'" 2>/dev/null)
        echo "$aliases" | while IFS=$'\t' read -r address goto; do
            if [[ -z "$address" || -z "$goto" ]]; then
                continue
            elif "$newserver_postfixadmin_cli" alias view "$address" >/dev/null 2>&1; then
                echo "[INFO] Alias already exists: $address -> $goto"
                continue
            fi
    
            if "$newserver_postfixadmin_cli" alias add "$address" --goto "$goto" >/dev/null 2>&1; then
                echo "[OK] Alias recreated: $address -> $goto"
                continue
            else
                echo "[ERROR] Failed to recreate alias: $address -> $goto"
            fi
        done
        echo
    
        if sshExec "$OLDHOSTNAME" "test -x /usr/share/postfixadmin/scripts/postfixadmin-cli" >/dev/null 2>&1; then
            oldserver_postfixadmin_cli="/usr/share/postfixadmin/scripts/postfixadmin-cli"
        elif sshExec "$OLDHOSTNAME" "command -v postfixadmin-cli" >/dev/null 2>&1; then
            oldserver_postfixadmin_cli="postfixadmin-cli"
        else
            echo "[ERROR] postfixadmin-cli not found on $OLDHOSTNAME, please install it or recreate mailboxes manually"
            return 1
        fi
        
        if [[ ! -f "$mailboxes_list_file" ]]; then
            echo "# List of mailboxes to recreate. Edit this file to exclude any mailboxes." > "$mailboxes_list_file"
            sshExec "$OLDHOSTNAME" "mysql -N -B -e 'SELECT username FROM postfix.mailbox WHERE active=1;'" 2>/dev/null >> "$mailboxes_list_file"
        fi
    
        echo "[INFO] Please review the Mailboxes that will be recreated:"
        echo
        echo "======== Mailboxes ========"
        cat "$mailboxes_list_file" | grep -Ev "#"
        echo "==========================="
        echo
        echo "[INFO] Mailboxes list saved to $mailboxes_list_file . Edit it to exclude mailboxes if needed."
        echo "[WARN] If a mailbox is missing on $NEWHOSTNAME, its password on $OLDHOSTNAME will be changed during recreation."
        echo 
        confirmOrExit
        
        echo
        echo "[INFO] Recreating Mailboxes for Postfix..."
        while IFS= read -r mailbox; do
    
            if [[ -z "$mailbox" || "$mailbox" =~ ^# ]] ;then
                continue
            elif $oldserver_postfixadmin_cli mailbox view "$mailbox" >/dev/null 2>&1; then
                echo "[INFO] Mailbox already exists: $mailbox"
                continue
            fi
            
            while true; do
                password=$(cat /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 16)
            
                if [[ $(echo "$password" | grep -o '[0-9]' | wc -l) -ge 2 ]]; then
                    break
                fi
            done
            
            if ! sshExec -n "$OLDHOSTNAME" "$oldserver_postfixadmin_cli mailbox update '$mailbox' --password '$password' --password2 '$password' "  >/dev/null 2>&1; then
                echo "[ERROR] Failed to reset password on $OLDHOSTNAME: $mailbox"
                continue
            fi
            
            if "$newserver_postfixadmin_cli" mailbox add "$mailbox" --password "$password" --password2 "$password" >/dev/null 2>&1; then
                echo "$mailbox $mailbox $password" >> "$users_file"
                echo "[OK] Mailbox recreated: $mailbox"
            else
                echo "[ERROR] Failed to recreate mailbox: $mailbox"
            fi
        done < "$mailboxes_list_file"
    
        echo "[INFO] Mailboxes and passwords saved to $users_file for future mails migration."
        return 0
    
    elif checkServiceActive "Sendmail" "sendmail" "$OLDHOSTNAME" >/dev/null 2>&1; then
    
        if sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/sbin/mjact_mail" >/dev/null 2>&1; then
            oldserver_mjact_mail="/usr/local/mojo/sbin/mjact_mail"
        elif sshExec "$OLDHOSTNAME" "command -v mjact_mail" >/dev/null 2>&1; then
            oldserver_mjact_mail="mjact_mail"
        else
            echo "[ERROR] mjact_mail not found on $OLDHOSTNAME, please recreate mailboxes manually"
            return 1
        fi
        
        echo "[INFO] Recreating Domains for Postfix..."
        domains=$(sshExec "$OLDHOSTNAME" "$oldserver_mjact_mail -a list 2>/dev/null" | awk '!/^#/ && /@/ && !/Forward\/Alias/ && !/Account/ {print $1}' | awk -F@ '{print $2}' | sort -u)
        
        if [[ -z "$domains" ]]; then
            echo "[WARN] No Domains found in Sendmail configuration on $OLDHOSTNAME"
            return 1
        fi
        
        echo "$domains" | while IFS= read -r domain; do
            if [[ -z "$domain" ]] ;then
                continue
            elif "$newserver_postfixadmin_cli" domain view "$domain" >/dev/null 2>&1; then
                echo "[INFO] Domain already exists: $domain"
                continue
            fi
        
            if "$newserver_postfixadmin_cli" domain add "$domain" --aliases 30 --mailboxes 30 >/dev/null 2>&1; then
                echo "[OK] Domain created: $domain"
                continue
            else
                echo "[ERROR] Failed to recreate domain: $domain"
            fi
        done
        echo
        
        echo "[INFO] Recreating Mail Aliases..."
        aliases=$(sshExec "$OLDHOSTNAME" "$oldserver_mjact_mail -a list 2>/dev/null" | awk '!/^#/ && /@/ && $2 ~ /@/ {print $1, $2}')
        
        echo "$aliases" | while read -r address goto; do
            if [[ -z "$address" || -z "$goto" ]]; then
                continue
            elif "$newserver_postfixadmin_cli" alias view "$address" >/dev/null 2>&1; then
                echo "[INFO] Alias already exists: $address -> $goto"
                continue
            fi
        
            if "$newserver_postfixadmin_cli" alias add "$address" --goto "$goto" >/dev/null 2>&1; then
                echo "[OK] Alias recreated: $address -> $goto"
            else
                echo "[ERROR] Failed to recreate alias: $address -> $goto"
            fi
        
        done
        echo
        
        if [[ ! -f "$mailboxes_list_file" ]]; then
            echo "# List of mailboxes to recreate. Edit this file to exclude any mailboxes." > "$mailboxes_list_file"
            sshExec "$OLDHOSTNAME" "$oldserver_mjact_mail -a list 2>/dev/null " | awk '/Email Addy[[:space:]]+Account/ {found=1; next} found && $1 ~ /@/ && $1 !~ /^#/ {print $1,$2}' | column -t >> "$mailboxes_list_file"
        fi
        
        echo "[INFO] Please review the Mailboxes that will be recreated:"
        echo
        echo "======== Mailboxes ========"
        cat "$mailboxes_list_file" | grep -Ev "#" | awk '{print $1}'
        echo "==========================="
        echo
        echo "[INFO] Mailboxes list saved to $mailboxes_list_file . Edit it to exclude mailboxes if needed."
        echo "[WARN] If a mailbox is missing on $NEWHOSTNAME, its password on $OLDHOSTNAME will be changed during recreation."
        echo
        confirmOrExit
        
        while IFS= read -r line; do
            if [[ -z "$line" || "$line" =~ ^# ]] ; then
                continue
            fi
            
            mailbox=$(echo "$line" | awk '{print $1}')
            account=$(echo "$line" | awk '{print $2}')
            
            if [[ -z "$mailbox" || -z "$account" ]] ; then
                continue
            fi
            
            if "$newserver_postfixadmin_cli" mailbox view "$mailbox" >/dev/null 2>&1; then
                echo "[INFO] Mailbox already exists: $mailbox"
                continue
            fi
            
            while true; do
                password=$(cat /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 16)
            
                if [[ $(echo "$password" | grep -o '[0-9]' | wc -l) -ge 2 ]]; then
                    break
                fi
            done
            
            if ! sshExec "$OLDHOSTNAME" "export PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/mojo/sbin; export TERM=xterm; $oldserver_mjact_mail -a changepassword -t 000000 -n $account -e $mailbox -p" <<< $password >/dev/null 2>&1; then
                echo "[ERROR] Failed to reset password on $OLDHOSTNAME: $mailbox"
                continue
            fi
            
            if "$newserver_postfixadmin_cli" mailbox add "$mailbox" --password "$password" --password2 "$password" >/dev/null 2>&1; then
                echo "$mailbox $account $password" >> "$users_file"
                echo "[OK] Mailbox recreated: $mailbox"
            else
                echo "[ERROR] Failed to recreate mailbox: $mailbox"
            fi
        done < "$mailboxes_list_file"
    
        echo "[INFO] Mailboxes and passwords saved to $users_file for future mails migration."
        return 0
    else
        echo "[WARN] Unsupported mail service on $OLDHOSTNAME. Mailbox recreation is only supported for Postfix and Sendmail servers."
        return 1
    fi

}

recreateFTPUsers() {

    local newserver_mjact_ftp
    local oldserver_mjact_ftp
    local ftp_users_list_file="$MIGRATION_DIR/ftp_users_list.txt"
    local ftp_users_file="$MIGRATION_DIR/ftp_users.txt"
    local add_output
    
    
    if test -x /usr/local/mojo/bin/mjact_ftp >/dev/null 2>&1; then
        newserver_mjact_ftp="/usr/local/mojo/bin/mjact_ftp"
    elif command -v mjact_ftp >/dev/null 2>&1; then
        newserver_mjact_ftp="mjact_ftp"
    else
        echo "[WARN] mjact_ftp not found on $NEWHOSTNAME, skipping FTP users recreation"
        return 1
    fi
    
    if checkServiceActive "vsftpd" "vsftpd" "$OLDHOSTNAME" >/dev/null 2>&1; then
    
        if sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/bin/mjact_ftp" >/dev/null 2>&1; then
            oldserver_mjact_ftp="/usr/local/mojo/bin/mjact_ftp"
        elif sshExec "$OLDHOSTNAME" "command -v mjact_ftp" >/dev/null 2>&1; then
            oldserver_mjact_ftp="mjact_ftp"
        else
            echo "[WARN] mjact_ftp not found on $OLDHOSTNAME, skipping FTP users recreation"
            return 1
        fi
    
        if [[ ! -f "$ftp_users_list_file" ]]; then
            echo "# List of FTP users to recreate. Edit this file to exclude any FTP users." > "$ftp_users_list_file"
    
            sshExec "$OLDHOSTNAME" "$oldserver_mjact_ftp -a list 2>/dev/null" | grep -v "Local path" | awk 'NF>1 && $2 !~ /^#/ && $1 !~ /(_wp|_wp_autoftp)$/ {print $1,$3}' | column -t >> "$ftp_users_list_file"
        fi
    
    elif checkServiceActive "proftpd" "proftpd" "$OLDHOSTNAME" >/dev/null 2>&1; then
    
        if sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/sbin/mjact_ftp" >/dev/null 2>&1; then
            oldserver_mjact_ftp="/usr/local/mojo/sbin/mjact_ftp"
        elif sshExec "$OLDHOSTNAME" "command -v mjact_ftp" >/dev/null 2>&1; then
            oldserver_mjact_ftp="mjact_ftp"
        else
            echo "[WARN] mjact_ftp not found on $OLDHOSTNAME, skipping FTP users recreation"
            return 1
        fi
    
        if [[ ! -f "$ftp_users_list_file" ]]; then
            echo "# List of FTP users to recreate. Edit this file to exclude any FTP users." > "$ftp_users_list_file"
    
    	sshExec "$OLDHOSTNAME" "$oldserver_mjact_ftp -a list 2>/dev/null" | grep -Ev "FTP Accounts|Any accounts" | awk 'NF>1 && $2 !~ /^#/ && $2 !~ /(_wp_autoftp|_wp)$/ {print $2,$3}' | column -t >> "$ftp_users_list_file"
        fi
    
    else
        echo "[WARN] FTP users recreation is only supported for ProFTPD and vsftpd servers."
        return 1
    fi
    
    echo "[INFO] Please review the FTP users that will be recreated:"
    echo
    echo "=============== FTP Users ==============="
    cat "$ftp_users_list_file" | grep -Ev "^#"
    echo "========================================="
    echo
    echo "[INFO] FTP users list saved to $ftp_users_list_file . Edit it to exclude FTP users if needed."
    echo
    confirmOrExit
    
    echo
    echo "[INFO] Recreating FTP Users..."
    while IFS= read -r line; do
        if [[ -z "$line" || "$line" =~ ^# ]] ; then
            continue
        fi
    
        ftp_user=$(echo "$line" | awk '{print $1}')
        ftp_path=$(echo "$line" | awk '{print $2}')
    
        if "$newserver_mjact_ftp" -a list 2>/dev/null | awk '{print $1}' | grep -qx "$ftp_user"; then
            echo "[INFO] FTP user already exists: $ftp_user"
            continue
        fi
    
        if [[ ! -d "$ftp_path" ]]; then
            echo "[WARN] FTP path does not exist, skipping user: $ftp_user ($ftp_path)"
            continue
        fi
    
        if add_output=$($newserver_mjact_ftp -a add -n "$ftp_user" -f "$ftp_path" 2>/dev/null); then
    
            {
                echo "$add_output"
                echo
            } >> "$ftp_users_file"
    
            echo "[OK] FTP user recreated: $ftp_user"
    
        else
            echo "[ERROR] Failed to recreate FTP user: $ftp_user"
        fi
    
    done < "$ftp_users_list_file"
    
    echo
    echo "[INFO] FTP users and passwords saved to $ftp_users_file"

}

recreateSSHUsers() {

    local newserver_mjact_ssh
    local oldserver_mjact_ssh
    local ssh_users_list_file="$MIGRATION_DIR/ssh_users_list.txt"
    local ssh_users_file="$MIGRATION_DIR/ssh_users.txt"
    local mjact_ssh_list_output
    local add_output
    
    
    if test -x /usr/local/mojo/bin/mjact_ssh >/dev/null 2>&1; then
        newserver_mjact_ssh="/usr/local/mojo/bin/mjact_ssh"
    elif command -v mjact_ssh >/dev/null 2>&1; then
        newserver_mjact_ssh="mjact_ssh"
    else
        echo "[WARN] mjact_ssh not found on $NEWHOSTNAME, skipping SSH users recreation"
        return 1
    fi
    
    if sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/bin/mjact_ssh" >/dev/null 2>&1; then
        oldserver_mjact_ssh="/usr/local/mojo/bin/mjact_ssh"
    elif sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/sbin/mjact_ssh" >/dev/null 2>&1; then
        oldserver_mjact_ssh="/usr/local/mojo/sbin/mjact_ssh"
    elif sshExec "$OLDHOSTNAME" "command -v mjact_ssh" >/dev/null 2>&1; then
        oldserver_mjact_ssh="mjact_ssh"
    else
        echo "[WARN] mjact_ssh not found on $OLDHOSTNAME, skipping SSH users recreation"
        return 1
    fi
    
    mjact_ssh_list_output=$(sshExec "$OLDHOSTNAME" "$oldserver_mjact_ssh -a list 2>/dev/null")
    
    if [[ ! -f "$ssh_users_list_file" ]]; then
        echo "# List of SSH users to recreate. Edit this file to exclude any SSH users." > "$ssh_users_list_file"
        if echo "$mjact_ssh_list_output" | grep -q "Client SSH Users"; then
            echo "$mjact_ssh_list_output" | awk '/Client SSH Users/ {p=1; next}/Mojo SSH Users/ && p {exit}p && $1 !~ /^(USRNAME|-+|backuppc)/ && NF {print $1}' >> "$ssh_users_list_file"
    
        elif echo "$mjact_ssh_list_output" | grep -q "(uid="; then
    	echo "$mjact_ssh_list_output" | sed 's/^ *//g' | awk -F '(' '$1 !~ /^(rocky|backuppc)$/ {print $1}' >> "$ssh_users_list_file"
        else
            echo "[WARN] Unknown mjact_ssh format"
            return 1
        fi
    fi
    
    echo "[INFO] Please review the SSH users that will be recreated:"
    echo
    echo "======= SSH Users ======="
    cat "$ssh_users_list_file" | grep -Ev "^#"
    echo "========================="
    echo
    echo "[INFO] SSH users list saved to $ssh_users_list_file . Edit it to exclude SSH users if needed."
    echo
    confirmOrExit
    
    echo
    echo "[INFO] Recreating SSH Users..."
    while IFS= read -r ssh_user; do
        if [[ -z "$ssh_user" || "$ssh_user" =~ ^# ]] ; then
            continue
        fi
    
        if "$newserver_mjact_ssh" -a list 2>/dev/null | sed 's/^ *//g' | awk -F '(' '{print $1}' | grep -qx "$ssh_user"; then
            echo "[INFO] SSH user already exists: $ssh_user"
            continue
        fi
    
        if add_output=$($newserver_mjact_ssh -a add -n "$ssh_user" 2>/dev/null); then
    
            {
                echo "$add_output"
                echo
            } >> "$ssh_users_file"
    
            echo "[OK] SSH user recreated: $ssh_user"
    
        else
            echo "[ERROR] Failed to recreate SSH user: $ssh_user"
        fi
    
    done < "$ssh_users_list_file"
    
    echo
    echo "[INFO] SSH users and passwords saved to $ssh_users_file"

}

createHostsFile() {

    local livedomains_cmd    
    local output_file="$MIGRATION_DIR/hosts.txt"

    if [[ ! -f "$output_file" ]]; then
        if sshExec "$OLDHOSTNAME" "test -x /mojo/livedomains" >/dev/null 2>&1; then
            livedomains_cmd="/mojo/livedomains"
        elif sshExec "$OLDHOSTNAME" "command -v livedomains >/dev/null 2>&1" >/dev/null 2>&1; then
            livedomains_cmd="livedomains"
        else
            echo "[ERROR] livedomains command not found, cannot create file $output_file"
            return 1
        fi

        echo "#Live Domains:" > "$output_file"
        sshExec "$OLDHOSTNAME" "$livedomains_cmd 2>&1 | grep -E 'is live here' | sed -r 's/\x1b\[[0-9;]*m//g'" | awk -v ip="$WAN_IP" '{print ip, $1, "www."$1}' | grep -v "$OLDHOSTNAME" >> "$output_file"
	echo >> "$output_file"
	echo "#CloudFlare Domains:" >> "$output_file"
	sshExec "$OLDHOSTNAME" "$livedomains_cmd 2>&1 | grep -E 'is using CloudFlare' | sed -r 's/\x1b\[[0-9;]*m//g'" | awk -v ip="$WAN_IP" '{print ip, $1, "www."$1}' | grep -v "$OLDHOSTNAME" >> "$output_file"
        echo "[OK] File $output_file has been created"
	return 0
    else 
        echo "[INFO] File $output_file already exists"
        return 0
    fi	
    echo

}

checkDomainsNameservers(){

    local hosts_file="$MIGRATION_DIR/hosts.txt"
    local nameservers_output_file="$MIGRATION_DIR/domains_nameservers.txt"
    local domains_list
    local domain
    local root_domain
    local nameservers
    local nameservers_output
    
    if [[ ! -f "$nameservers_output_file" ]]; then
        if ! createHostsFile >/dev/null 2>&1 ; then
            echo "[ERROR] Failed to create hosts file $hosts_file . Please create it manually - it is required for nameservers checks."
            return 1
        fi
    
        domains_list=$(awk '!/^#/ && NF {print $2}' "$hosts_file")
        
        nameservers_output=$(
            echo "$domains_list" | while IFS= read -r domain; do
                if [[ -z "$domain" || "$domain" =~ ^# ]]; then
                    continue
                fi
            
                root_domain=$(echo "$domain" | awk -F. '{if(NF>=2) print $(NF-1)"."$NF}')
                nameservers=$(dig +short NS "$root_domain" 2>/dev/null | sort -u | sed 's|\.$||' | tr '\n' ' | ')
                
                echo -e "$domain\t( zone: $root_domain )\t- $nameservers"
            
            done | sort -k4,4 | column -t -s $'\t' -o ' '
        )
    
        echo "#File Format: domain ( DNS zone ) - nameservers" > "$nameservers_output_file"
        echo >> "$nameservers_output_file" 
        echo "MojoHost Nameservers:" >> "$nameservers_output_file"
        echo "$nameservers_output" | grep -E "mojohost.com|mojohost.eu|mjhst.com|eosdns.net" >> "$nameservers_output_file"
        echo >> "$nameservers_output_file"
        echo "CloudFlare Nameservers:" >> "$nameservers_output_file"
        echo "$nameservers_output" | grep "cloudflare.com" >> "$nameservers_output_file"
        echo >> "$nameservers_output_file"
        echo "Others Nameservers:" >> "$nameservers_output_file"
        echo "$nameservers_output" | grep -Ev "mojohost.com|mojohost.eu|mjhst.com|eosdns.net|cloudflare.com" >> "$nameservers_output_file"
    
        echo "[OK] Nameservers list saved to $nameservers_output_file"
        return 0
    
    else
        echo "[INFO] File $nameservers_output_file already exists"
        return 0
    fi


}

HELP() {

    echo "===================================================================================================="
    echo "Migration Tool"
    echo
    echo "Usage:"
    echo "  $0 -a <action> -o <old host> [ -f <path> ]"
    echo "===================================================================================================="
    echo "Options:"
    echo "  -a ACTION     Action to perform"
    echo "  -o HOST       Old Hostname"
    echo "  -f DIR        Working directory for migration files (default: /root/migration)"
    echo "  -h            Show help"
    echo
    echo "Actions:"
    echo "  webdata       Migrate web data (In development)"
    echo "  db            Migrate databases"
    echo "  mail          Migrate mails"
    echo "  vhosts        Recreate Apache and Nginx vhosts"
    echo "  mysqlusers    Recreate MySQL users"
    echo "  mailboxes     Recreate Mailboxes and Aliases (WARNING: Passwords will be reset on the old server)"
    echo "  ftpusers      Recreate FTP users"
    echo "  sshusers      Recreate SSH users"
    echo "  hosts         Generate hosts file"
    echo "  checkns       Generate nameservers list file"
    echo "  compare       Compare servers"
    echo "===================================================================================================="

}


if [ "$(whoami)" != 'root' ]; then
    echo "[ERROR] You must execute this script as the root user!"
    exit 1
fi

if [[ -z "$1" || "$1" == "-h" || "$1" == "--help" ||  "$1" == "help" ]]; then
    HELP
    exit 0
fi

while getopts ":a:o:f:" OPTION; do
    case "${OPTION}" in
        a) ACTION="${OPTARG}" ;;
        o) OLDHOSTNAME="${OPTARG}" ;;
	f) MIGRATION_DIR="${OPTARG}" ;;
        \?) echo "[ERROR] Unknown option: -$OPTARG"; exit 1 ;;
        :) echo "[ERROR] Option -$OPTARG requires argument"; exit 1 ;;
    esac
done

if [ -z "$MIGRATION_DIR" ]; then
    MIGRATION_DIR="/root/migration"
fi

DATABASES_DIR="$MIGRATION_DIR"/dbs
WAN_IP=$(curl -s https://api.ipify.org)
ACTION_LOWER="${ACTION,,}"

case "$ACTION_LOWER" in
    webdata) prepareEnv; migrateWebData ;;
    vhosts) prepareEnv; recreateWebConfigs ;;
    db) prepareEnv; migrateDatabases ;;
    mail) prepareEnv; migrateMails ;;
    mysqlusers) prepareEnv; recreateMySQLUsers ;;
    mailboxes) prepareEnv; recreateMailboxes ;;
    ftpusers) prepareEnv; recreateFTPUsers ;;
    sshusers) prepareEnv; recreateSSHUsers ;;
    hosts) prepareEnv; createHostsFile ;;
    checkns) prepareEnv; checkDomainsNameservers ;;
    compare) prepareEnv; compareServers ;;
    *) echo "[ERROR] Unknown Option: $ACTION"; exit 1 ;;
esac



Youez - 2016 - github.com/yon3zu
LinuXploit