#!/bin/bash
# Fix password setup failure: Set MySQL password via socket authentication
# All files unified in /opt + cleanup legacy files
# Automatically update system packages
# 颜色定义
RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
BLUE='\033[34m'
NC='\033[0m'
###########################################################################
# User Input Configuration Parameters
###########################################################################
echo -e "${BLUE}🔧 Step 0: Configure Installation Parameters <<<${NC}"
# Installation option selection
echo -e "${YELLOW}Please select installation mode:${NC}"
echo -e " ${GREEN}1)${NC} Install ODBC only"
echo -e " ${GREEN}2)${NC} Install MySQL + ODBC + Redis"
read -p "Enter option (1 or 2): " install_mode
if [ "$install_mode" != "1" ] && [ "$install_mode" != "2" ]; then
echo -e "${RED}❌ Invalid option, please enter 1 or 2!${NC}"
exit 1
fi
# Zone count selection
echo -e "${YELLOW}Please select zone configuration:${NC}"
echo -e " ${GREEN}1)${NC} Single Zone (创建3个数据库: tlbbdb_main, tlbbdb_11, web)"
echo -e " ${GREEN}2)${NC} Multiple Zones (创建5个数据库: tlbbdb_main, tlbbdb_11, web, tlbbdb_10, tlbbdb_100)"
read -p "Enter option (1 or 2): " zone_option
if [ "$zone_option" != "1" ] && [ "$zone_option" != "2" ]; then
echo -e "${RED}❌ Invalid option, please enter 1 or 2!${NC}"
exit 1
fi
# Set zone_count based on selection
if [ "$zone_option" = "1" ]; then
zone_count=1
databases=("tlbbdb_main" "tlbbdb_11" "web")
else
zone_count=5
databases=("tlbbdb_main" "tlbbdb_11" "web" "tlbbdb_10" "tlbbdb_100")
fi
# If installing MySQL+Redis, need to input passwords
if [ "$install_mode" = "2" ]; then
read -p "MySQL root password: " dbpass
read -p "Confirm MySQL password: " dbpass_confirm
if [ "$dbpass" != "$dbpass_confirm" ]; then
echo -e "${RED}❌ MySQL passwords do not match!${NC}"
exit 1
fi
read -p "Redis password: " redispass
read -p "Confirm Redis password: " redispass_confirm
if [ "$redispass" != "$redispass_confirm" ]; then
echo -e "${RED}❌ Redis passwords do not match!${NC}"
exit 1
fi
else
# When installing ODBC only, set default values (not used)
dbpass=""
redispass=""
fi
echo -e "${GREEN}✅ Configuration parameters set successfully!${NC}\n"
###########################################################################
# Update System Packages
###########################################################################
echo -e "${BLUE}🔧 Step 1: Update System Packages <<<${NC}"
echo -e "${YELLOW}Cleaning yum cache and fetching latest repositories...${NC}"
dnf clean all
dnf makecache -y
echo -e "${YELLOW}Upgrading all packages...${NC}"
dnf update -y
echo -e "${GREEN}✅ System packages updated successfully!${NC}\n"
###########################################################################
# Cleanup Legacy Files (Completely Remove Old Files)
###########################################################################
echo -e "${BLUE}🔧 Step 2: Cleanup MySQL/ODBC Installation Legacy Files...${NC}"
# Stop services and uninstall residual packages
systemctl stop mysqld 2>/dev/null
systemctl disable mysqld 2>/dev/null
rpm -e mysql-server mysql mysql-community-server mysql-community-client 2>/dev/null
dnf remove -y mysql\* mariadb\* unixODBC\* 2>/dev/null
# Delete configuration, data, and log residues
rm -rf /etc/my.cnf /etc/my.cnf.d /etc/mysql
rm -rf /var/lib/mysql /var/log/mysqld.log /var/run/mysqld
rm -rf /etc/yum.repos.d/mysql-*.repo
rm -rf /opt/mysql-connector-odbc*.rpm /opt/my.cnf* /opt/odbc.ini*
# Clean cache
dnf clean all 2>/dev/null
rm -rf /var/cache/dnf/* /var/lib/dnf/*
echo -e "${GREEN}✅ Legacy files cleanup completed!${NC}\n"
###########################################################################
# Basic Checks
###########################################################################
# System version check
OS_CHECK=$(grep -E '^ID="centos"' /etc/os-release && grep -E '^VERSION_ID="9"' /etc/os-release)
if [ -z "$OS_CHECK" ]; then
echo -e "${RED}❌ This script only supports CentOS 9 system!${NC}"
exit 1
fi
# Root permission check
if [ "$(id -u)" -ne 0 ]; then
echo -e "${RED}Please run this script as root user${NC}"
exit 1
fi
# Ensure /opt directory exists
[ ! -d "/opt" ] && mkdir -p /opt && chmod 755 /opt
###########################################################################
# Get Server IP Address (Prioritize Internal IP, Use External IP if Not Available)
###########################################################################
get_server_ip() {
# Try to get internal IP (exclude 127.0.0.1 and docker/virtual network cards)
local internal_ip=$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}' | head -1)
if [ -z "$internal_ip" ]; then
internal_ip=$(hostname -I 2>/dev/null | awk '{print $1}')
fi
if [ -z "$internal_ip" ] || [ "$internal_ip" = "127.0.0.1" ]; then
# Try to get internal IP from network interface
internal_ip=$(ip addr show | grep -E 'inet [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | grep -v '127.0.0.1' | head -1 | awk '{print $2}' | cut -d'/' -f1)
fi
# If still no internal IP, try to get external IP
if [ -z "$internal_ip" ] || [ "$internal_ip" = "127.0.0.1" ]; then
echo -e "${YELLOW}Internal IP not detected, getting external IP...${NC}" >&2
internal_ip=$(curl -s ifconfig.me 2>/dev/null || curl -s ip.sb 2>/dev/null || curl -s icanhazip.com 2>/dev/null)
fi
if [ -z "$internal_ip" ]; then
echo -e "${RED}❌ Unable to get server IP address!${NC}" >&2
exit 1
fi
echo "$internal_ip"
}
###########################################################################
# Install Basic Dependencies
###########################################################################
echo -e "\n${BLUE}>>> Step 3: Install Basic Dependencies <<<${NC}"
dnf install -y epel-release
dnf install -y curl gnupg2 dnf-utils policycoreutils openssh-server \
unixODBC unixODBC-devel gtk3 gtk2 gail
# Try to install wget, use curl as fallback if failed
echo -e "${YELLOW}Installing download tools...${NC}"
if ! dnf install -y wget 2>/dev/null; then
echo -e "${YELLOW}⚠️ wget installation failed, will use curl as alternative${NC}"
DOWNLOAD_CMD="curl"
else
DOWNLOAD_CMD="wget"
fi
dnf clean all && dnf makecache -y
# Verify if download tool is available
if ! command -v "$DOWNLOAD_CMD" &> /dev/null; then
echo -e "${RED}❌ Download tool installation failed! Please check network connection${NC}"
exit 1
fi
echo -e "${GREEN}✅ Download tool installed successfully: $DOWNLOAD_CMD${NC}"
###########################################################################
# Install MySQL and Fix Password Setup (Core Fix Step)
###########################################################################
if [ "$install_mode" = "2" ]; then
echo -e "\n${BLUE}>>> Step 4: Install MySQL 8.0 and Set Password <<<${NC}"
# Enable and install system MySQL
dnf module enable -y mysql:8.0
dnf install -y mysql mysql-server
cp /etc/my.cnf /opt/my.cnf.bak # Backup initial configuration
# Start MySQL and set auto-start
systemctl start mysqld
systemctl enable mysqld
if ! systemctl is-active --quiet mysqld; then
echo -e "${RED}❌ MySQL service startup failed!${NC}"
exit 1
fi
# Core fix: Set root password via socket authentication (bypass initial password restriction)
echo -e "${YELLOW}Setting MySQL password via socket authentication...${NC}"
mysql -u root -S /var/lib/mysql/mysql.sock -e "
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '$dbpass';
SET GLOBAL validate_password.policy=LOW;
SET GLOBAL validate_password.length=4;
FLUSH PRIVILEGES;
" 2>/dev/null
# Verify if password was set successfully
if mysql -u root -p"$dbpass" -e "SELECT 1;" 2>/dev/null; then
echo -e "${GREEN}✅ MySQL password set successfully!${NC}"
else
echo -e "${RED}❌ MySQL password setup failed, attempting forced reset...${NC}"
# Fallback: Modify MySQL config to skip password login, reset then restore
echo "skip-grant-tables" >> /etc/my.cnf
systemctl restart mysqld
# Login without password and reset password
mysql -u root -e "
UPDATE mysql.user SET authentication_string=PASSWORD('$dbpass') WHERE User='root' AND Host='localhost';
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '$dbpass';
FLUSH PRIVILEGES;
" 2>/dev/null
# Remove skip password config and restart
sed -i '/skip-grant-tables/d' /etc/my.cnf
systemctl restart mysqld
# Second verification
if mysql -u root -p"$dbpass" -e "SELECT 1;" 2>/dev/null; then
echo -e "${GREEN}✅ MySQL password forced reset successful!${NC}"
else
echo -e "${RED}❌ MySQL password reset completely failed, please manually run: mysql_secure_installation${NC}"
exit 1
fi
fi
else
echo -e "\n${BLUE}>>> Step 4: Skip MySQL Installation (ODBC Only) <<<${NC}"
echo -e "${YELLOW}ODBC only installation selected, skipping MySQL installation step${NC}"
fi
###########################################################################
# Install ODBC Driver (Auto Download to /opt)
###########################################################################
echo -e "\n${BLUE}>>> Step 5: Install ODBC 9.3 Driver <<<${NC}"
ODBC_MAIN_RPM="/opt/mysql-connector-odbc-9.3.0-1.el9.x86_64.rpm"
ODBC_SETUP_RPM="/opt/mysql-connector-odbc-setup-9.3.0-1.el9.x86_64.rpm"
# Auto download driver to /opt
echo -e "${YELLOW}Downloading ODBC 9.3 driver...${NC}"
# Define download function
download_file() {
local url="$1"
local output="$2"
local filename=$(basename "$output")
if [ "$DOWNLOAD_CMD" = "wget" ]; then
wget -q -O "$output" "$url"
else
curl -s -L -o "$output" "$url"
fi
return $?
}
# Download main driver
if [ ! -f "$ODBC_MAIN_RPM" ]; then
echo -e "${YELLOW}Downloading main driver...${NC}"
download_file "https://dev.mysql.com/get/Downloads/Connector-ODBC/9.3/mysql-connector-odbc-9.3.0-1.el9.x86_64.rpm" "$ODBC_MAIN_RPM"
if [ $? -ne 0 ]; then
echo -e "${RED}❌ Main driver download failed!${NC}"
exit 1
fi
fi
# Download setup driver
if [ ! -f "$ODBC_SETUP_RPM" ]; then
echo -e "${YELLOW}Downloading setup driver...${NC}"
download_file "https://dev.mysql.com/get/Downloads/Connector-ODBC/9.3/mysql-connector-odbc-setup-9.3.0-1.el9.x86_64.rpm" "$ODBC_SETUP_RPM"
if [ $? -ne 0 ]; then
echo -e "${RED}❌ Setup driver download failed!${NC}"
exit 1
fi
fi
# Verify files exist
if [ ! -f "$ODBC_MAIN_RPM" ] || [ ! -f "$ODBC_SETUP_RPM" ]; then
echo -e "${RED}❌ ODBC driver files download failed!${NC}"
exit 1
fi
echo -e "${GREEN}✅ ODBC 9.3 driver download completed!${NC}"
# Install driver
echo -e "${YELLOW}Installing ODBC driver...${NC}"
dnf install -y "$ODBC_MAIN_RPM" --allowerasing
dnf install -y "$ODBC_SETUP_RPM" --allowerasing
# Verify ODBC
if command -v odbcinst &> /dev/null && odbcinst -q -d | grep -q "MySQL ODBC"; then
echo -e "${GREEN}✅ ODBC driver installed successfully!${NC}"
else
echo -e "${RED}❌ ODBC driver installation failed!${NC}"
exit 1
fi
###########################################################################
# Configure MySQL Remote Access + ODBC Data Source
###########################################################################
if [ "$install_mode" = "2" ]; then
echo -e "\n${BLUE}>>> Step 6: Configure Remote Access and ODBC Data Source <<<${NC}"
# Configure MySQL (allow remote access)
cat >> /etc/my.cnf <<EOF
[mysqld]
skip-log-bin
skip-name-resolve
max_allowed_packet=400M
max_connections=16000
ssl=0
bind-address=0.0.0.0
EOF
cp /etc/my.cnf /opt/my.cnf.conf
systemctl restart mysqld
# Grant root remote access
mysql -u root -p"$dbpass" -e "
CREATE USER 'root'@'%' IDENTIFIED BY '$dbpass';
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '$dbpass';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
"
# Create selected databases
echo -e "${YELLOW}Creating databases...${NC}"
for db in "${databases[@]}"; do
mysql -u root -p"$dbpass" -e "CREATE DATABASE IF NOT EXISTS ${db} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}✅ Database ${db} created successfully${NC}"
else
echo -e "${RED}❌ Failed to create database ${db}${NC}"
fi
done
# Get server IP
SERVER_IP=$(get_server_ip)
echo -e "${GREEN}✅ Detected server IP: ${SERVER_IP}${NC}"
# Configure ODBC data source for all selected databases
for db in "${databases[@]}"; do
cat >> /etc/odbc.ini <<EOF
[${db}]
Driver = MySQL ODBC 9.3 ANSI Driver
SERVER = ${SERVER_IP}
PORT = 3306
USER = root
Password = ${dbpass}
Database = ${db}
OPTION = 3
SOCKET =
EOF
done
cp /etc/odbc.ini /opt/odbc.ini.conf
echo -e "${GREEN}✅ ODBC data source configuration completed!${NC}"
else
echo -e "\n${BLUE}>>> Step 6: Skip MySQL Configuration (ODBC Only) <<<${NC}"
echo -e "${YELLOW}ODBC only installation selected, skipping MySQL configuration step${NC}"
fi
###########################################################################
# Install Redis (If Option 2 is Selected)
###########################################################################
if [ "$install_mode" = "2" ]; then
echo -e "\n${BLUE}>>> Step 7: Install Redis <<<${NC}"
REDIS_VERSION="7.2.4"
REDIS_DIR="/usr/local/redis"
# Create Redis directory structure
mkdir -p ${REDIS_DIR}/bin
mkdir -p ${REDIS_DIR}/conf
# Download Redis from Chinese mirror sources
echo -e "${YELLOW}Downloading Redis from Chinese mirror...${NC}"
# Try Chinese mirrors first, then fallback to official source
REDIS_URLS=(
"https://mirrors.aliyun.com/redis/redis-${REDIS_VERSION}.tar.gz"
"https://mirrors.huaweicloud.com/redis/redis-${REDIS_VERSION}.tar.gz"
"https://mirrors.tuna.tsinghua.edu.cn/redis/redis-${REDIS_VERSION}.tar.gz"
"https://download.redis.io/releases/redis-${REDIS_VERSION}.tar.gz"
)
DOWNLOAD_SUCCESS=0
for REDIS_URL in "${REDIS_URLS[@]}"; do
echo -e "${YELLOW}Trying: ${REDIS_URL}...${NC}"
if [ "$DOWNLOAD_CMD" = "wget" ]; then
if wget -q --timeout=10 --tries=2 "${REDIS_URL}" -O /tmp/redis.tar.gz 2>/dev/null; then
DOWNLOAD_SUCCESS=1
break
fi
else
if curl -s -L --connect-timeout 10 --max-time 30 "${REDIS_URL}" -o /tmp/redis.tar.gz 2>/dev/null; then
DOWNLOAD_SUCCESS=1
break
fi
fi
done
if [ $DOWNLOAD_SUCCESS -eq 0 ] || [ ! -f /tmp/redis.tar.gz ]; then
echo -e "${RED}❌ Redis download failed from all sources!${NC}"
exit 1
fi
echo -e "${GREEN}✅ Redis downloaded successfully!${NC}"
# Extract Redis
echo -e "${YELLOW}Extracting Redis...${NC}"
tar -zxf /tmp/redis.tar.gz -C /tmp
if [ ! -d /tmp/redis-${REDIS_VERSION} ]; then
echo -e "${RED}❌ Redis extraction failed!${NC}"
exit 1
fi
# Build Redis (required as there are no precompiled binaries)
echo -e "${YELLOW}Building Redis (this may take a few minutes)...${NC}"
dnf install -y gcc make 2>/dev/null
cd /tmp/redis-${REDIS_VERSION} || { echo -e "${RED}❌ Cannot enter Redis directory${NC}"; exit 1; }
# Build Redis silently
if ! make -j$(nproc) >/dev/null 2>&1; then
# Fallback to single-threaded build
echo -e "${YELLOW}Retrying with single-threaded build...${NC}"
if ! make >/dev/null 2>&1; then
echo -e "${RED}❌ Redis build failed!${NC}"
echo -e "${YELLOW}Checking build errors...${NC}"
make 2>&1 | tail -20
exit 1
fi
fi
# Copy binaries and config
cp src/redis-server ${REDIS_DIR}/bin/
cp src/redis-cli ${REDIS_DIR}/bin/
cp redis.conf ${REDIS_DIR}/conf/
# Make binaries executable
chmod +x ${REDIS_DIR}/bin/redis-server
chmod +x ${REDIS_DIR}/bin/redis-cli
# Create symbolic links to /usr/local/bin for easy access
ln -sf ${REDIS_DIR}/bin/redis-server /usr/local/bin/redis-server
ln -sf ${REDIS_DIR}/bin/redis-cli /usr/local/bin/redis-cli
# Configure Redis
echo -e "${YELLOW}Configuring Redis...${NC}"
# Modify configuration file
CONFIG_FILE="/usr/local/redis/conf/redis.conf"
# Allow external access (bind all IPs)
sed -i 's/^bind 127.0.0.1 -::1/bind 0.0.0.0/' $CONFIG_FILE
# Disable protected mode (allow non-local connections)
sed -i 's/^protected-mode yes/protected-mode no/' $CONFIG_FILE
# Set password (same method as install_redis.sh - replace commented line)
# Use the exact same sed pattern as install_redis.sh
sed -i "s/^# requirepass foobared/requirepass $redispass/" $CONFIG_FILE
# Enable daemon mode
sed -i 's/^daemonize no/daemonize yes/' $CONFIG_FILE
# Set log file path
sed -i 's|^logfile ""|logfile "/var/log/redis.log"|' $CONFIG_FILE
# Create system service
echo -e "${YELLOW}Creating Redis system service...${NC}"
# Escape password for use in systemd service file
REDIS_PASS_ESCAPED=$(printf '%s\n' "$redispass" | sed 's/[[\.*^$()+?{|]/\\&/g')
cat > /etc/systemd/system/redis.service <<EOF
[Unit]
Description=Redis In-Memory Data Store
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
ExecStop=/usr/local/redis/bin/redis-cli -a ${REDIS_PASS_ESCAPED} shutdown
Restart=always
[Install]
WantedBy=multi-user.target
EOF
# Start Redis and set auto-start
echo -e "${YELLOW}Starting Redis service...${NC}"
systemctl daemon-reload
systemctl start redis
systemctl enable redis
if ! systemctl is-active --quiet redis; then
echo -e "${RED}❌ Redis service startup failed!${NC}"
exit 1
fi
# Open firewall port 6379 (if firewall is enabled)
echo -e "${YELLOW}Configuring firewall...${NC}"
if systemctl is-active --quiet firewalld; then
firewall-cmd --add-port=6379/tcp --permanent 2>/dev/null
firewall-cmd --reload 2>/dev/null
echo -e "${GREEN}✅ Firewall port 6379 opened${NC}"
else
echo -e "${YELLOW}Firewall not running, no port configuration needed${NC}"
fi
# Clean temporary files
rm -rf /tmp/redis.tar.gz /tmp/redis-${REDIS_VERSION}
echo -e "${GREEN}✅ Redis installation completed!${NC}"
fi
###########################################################################
# Installation Complete
###########################################################################
echo -e "\n${GREEN}🎉 All steps completed!${NC}"
echo -e "${BLUE}=============================== Installation Info ===============================${NC}"
# Display zone configuration
if [ "$zone_option" = "1" ]; then
echo -e "${BLUE} Zone Configuration: ${YELLOW}Single Zone${NC}"
else
echo -e "${BLUE} Zone Configuration: ${YELLOW}Multiple Zones${NC}"
fi
echo -e "${BLUE} Databases Created:${NC}"
for db in "${databases[@]}"; do
echo -e "${YELLOW} - ${db}${NC}"
done
if [ "$install_mode" = "2" ]; then
SERVER_IP=$(get_server_ip)
echo -e "${BLUE} Installation Mode: ${YELLOW}MySQL + ODBC + Redis${NC}"
echo -e "${BLUE} MySQL Password: ${YELLOW}$dbpass${NC}"
echo -e "${BLUE} Redis Password: ${YELLOW}$redispass${NC}"
echo -e "${BLUE} Server IP: ${YELLOW}$SERVER_IP${NC}"
echo -e "${BLUE} Test MySQL: mysql -uroot -p\"$dbpass\" -e \"SHOW DATABASES;\"${NC}"
echo -e "${BLUE} Test ODBC: isql -v ${databases[0]} root \"$dbpass\"${NC}"
echo -e "${BLUE} Test Redis: redis-cli -h $SERVER_IP -p 6379 -a \"$redispass\"${NC}"
echo -e "${BLUE} Config Backup: /opt/my.cnf.conf, /opt/odbc.ini.conf${NC}"
else
echo -e "${BLUE} Installation Mode: ${YELLOW}ODBC Only${NC}"
echo -e "${BLUE} Test ODBC: odbcinst -q -d${NC}"
fi
echo -e "\n${GREEN}✅ System configuration completed!${NC}"
|