#!/bin/bash if [ $# -lt 2 ]; then echo "Usage: mysql-repl ..." 1>&2 echo exit 1 fi RSYNC_PORT=873 MASTER=$1 shift SLAVES=$@ REMOTEPATH=/usr/sbin:/usr/bin:/sbin:/bin:/www/mysql/bin:/www/mysql-backup/bin TMPFILE=/tmp/mysql-repl.$$ function ask_again { read -p "Try again? [Y/n]" ANSWER [ "$ANSWER" != "N" -a "$ANSWER" != "n" ] || exit 1 } function f_ask_again { echo Failed echo ask_again } function error_output { echo "Error output follows:" cat $TMPFILE rm $TMPFILE } echo echo "Setting up MySQL replication from $MASTER to:" for SLAVE in $SLAVES; do echo -e "\t$SLAVE" done read -p "Do you want to continue? [y/N] " ANSWER [ "$ANSWER" != "Y" -a "$ANSWER" != "y" ] && exit 1 touch $TMPFILE echo echo "Note that You may see the progres watching tempfile $TMPFILE." echo "( $ tail -f $TMPFILE )" read -p "Pres ENTER to continue" echo echo "Checking ssh to given hosts:" for host in $MASTER $SLAVES; do echo -n " $host ... " if ssh root@$host true 2> $TMPFILE; then echo OK else echo Failed echo cat $TMPFILE exit 1 fi done OK=0 echo while [ $OK -le $# ]; do OK=0 echo "Checking szn-mysql5-backup and rsync:" for host in $MASTER $SLAVES; do echo -n " $host: " if [ "$(ssh root@$host dpkg -l szn-mysql5-backup rsync | grep -c ^ii)" = "2" ]; then echo OK OK=$((OK+1)) else echo Failed echo "Trying to install szn-mysql5-backup and rsync on $host:" if ssh root@$host -t "apt-get install szn-mysql5-backup rsync"; then echo echo "Instalation complete." OK=$((OK+1)) else echo echo "Instalation failed." echo ask_again fi fi done done OK=0 while [ $OK = 0 ]; do echo echo -n "Creating backup on $MASTER: " ssh root@$MASTER -t PATH=$REMOTEPATH mysql5-backup backup_innodb > $TMPFILE 2>&1 if tail -n 5 $TMPFILE | grep -q "innobackup: innobackup completed OK!"; then echo OK OK=1 else echo Failed echo error_output echo ask_again fi done OK=0 echo echo "Parsing backup output:" echo -en "\t* backup dir: " read BACKUPDIR <<< "$(grep "Backup created in directory" $TMPFILE | sed -r "s/^.*directory '(.*)'.*$/\1/")" echo -n "$BACKUPDIR ... " while ! ssh root@$MASTER "test -d $BACKUPDIR"; do echo Failed echo read -p "Entrer the backup dir > " BACKUPDIR echo -en "\t* backup dir: $BACKUPDIR ... " done echo OK _BACKUPDIR=`echo $BACKUPDIR | sed s/\\\\//\\\\\\\\\\\\//g` echo echo -en "\t* last binlog position:" read LOGFILE LOGPOS <<< "$(grep "MySQL binlog position" $TMPFILE | sed -r "s/^.*filename '([^']+)', position ([0-9]+).*$/\1 \2/")" echo -n "$LOGFILE:$LOGPOS ... " while [ -z $LOGFILE ] || ! ssh root@$MASTER "test -f /www/mysql/data/$LOGFILE" 2> /dev/null; do echo Failed echo read -p "Insert correct binlog file > " LOGFILE echo -en "\t* last binlog position: $LOGFILE:$LOGPOS ... " done while [ -z $LOGPOS ]; do echo Failed echo read -p "Insert correct binlog position > " LOGPOS echo -en "\t* last binlog position: $LOGFILE:$LOGPOS ... " done echo OK OK=0 while [ $OK = 0 ]; do echo echo -n "Starting rsync server on $MASTER ... " ssh root@$MASTER "cat > .mysql-repl.rsyncd.conf" < $TMPFILE; then echo OK OK=1 else echo Failed ssh root@$MASTER rm -f .mysql-repl.rsyncd.conf &>> $TMPFILE echo error_output echo ask_again fi done sleep 5 OK=0 while [ $OK -lt $# ]; do OK=0 echo echo "Syncing backup files from master to slaves:" for SLAVE in $SLAVES; do echo -en "\t* forking rsync on $SLAVE ... " if ssh root@$SLAVE "rsync -a $MASTER::mysql-repl/ $BACKUPDIR/" && touch $TMPFILE.$SLAVE.stamp & then echo OK else echo Failed fi done echo -n "Waiting ... "; wait; echo done echo echo "Checking rsync results:" for SLAVE in $SLAVES; do echo -en "\t* checking result of rsync on $SLAVE ... " if rm $TMPFILE.$SLAVE.stamp 2> /dev/null; then echo OK OK=$((OK+1)) else echo Failed fi done done echo echo -n "Removing backup files from master ... " if ssh root@$MASTER "rm -r $BACKUPDIR" &> $TMPFILE; then echo OK else echo Failed echo error_output echo echo Please remove $BACKUPDIR on $MASTER. read -p "Pres ENTER to continue" fi echo echo -n "Killing rsync server on $MASTER ... " if ssh root@$MASTER "kill \$( $TMPFILE; then echo OK else echo Failed echo error_output echo echo Please kill the rsync server. read -p "Pres ENTER to continue" fi OK=0 echo while [ $OK = 0 ]; do read -sp "Insert MySQL replication password > " PASS1 echo read -sp "Repeat MySQL replication password > " PASS2 echo if [ $PASS1 != $PASS2 ]; then echo "Passwords do not match." elif [ -z "$PASS1" ]; then echo "Password is empty" else OK=1 fi done for SLAVE in $SLAVES; do echo FIRST=1 while ssh root@$SLAVE mysqladmin ping > /dev/null 2>&1; do echo "Slave MySQL server is running" if [ $FIRST = 1 ]; then echo "Going to stop the slave MySQL server ($SLAVE)." read -p "Pres ENTER to continue ... " FIRST=0 fi echo -n "Stoping slave mysqld on $SLAVE: " if ssh root@$SLAVE mysqladmin shutdown > /dev/null 2>&1; then echo OK else f_ask_again fi done OK=0 ssh root@$SLAVE "rm -rf /www/mysql/data/master.info" while [ $OK = 0 ]; do echo echo -n "Applying log on $SLAVE ... " ssh root@$SLAVE PATH=$REMOTEPATH innobackup --apply-log $BACKUPDIR/backup-my.cnf $BACKUPDIR/ > $TMPFILE 2>&1 if tail -n 5 $TMPFILE | grep -q "innobackup: innobackup completed OK!"; then echo OK OK=1 else echo Failed echo error_output echo ask_again fi done ssh root@$SLAVE "rm -rf /www/mysql/data/*" echo -n "Tunning $BACKUPDIR/backup-my.cnf ... " if ssh root@$SLAVE "sed -i 's/$_BACKUPDIR/\/www\/mysql\/data/' $BACKUPDIR/backup-my.cnf"; then echo OK else echo Failed echo read -p "Fix the file manually and press ENTER to continue. " fi echo echo -n "Moving backup on $SLAVE ... " if ssh root@$SLAVE "rm -rf /www/mysql/data.repl_{old,new}; chown -R mysql:mysql $BACKUPDIR && mv $BACKUPDIR /www/mysql/data.repl_new && mv /www/mysql/data /www/mysql/data.repl_old && mv /www/mysql/data.repl_new /www/mysql/data" > $TMPFILE 2>&1; then echo OK echo -n "Removing old data files from $SLAVE ... " ssh root@$SLAVE "rm -rf /www/mysql/data.repl_old" && echo OK || echo Failed else echo Failed echo error_output echo echo "Please move the data dir from $BACKUPDIR to /www/mysql/data manually." read -p "Pres ENTER to continue ... " fi ssh root@$SLAVE "chown -R mysql:mysql /www/mysql/data/" OK=0 echo echo -n "Fetching config file from master ... " if rsync root@$MASTER:/etc/mysql/my.cnf $TMPFILE 2> /dev/null; then echo OK echo -n "Parsing server-id: " MASTERID=`grep ^server-id $TMPFILE | sed -r 's/.*=\\s+(\\S+)\\s*/\\1/'` if [ -n "$MASTERID" ]; then echo "OK ($MASTERID)" read -p "Insert slave server-id (default $((MASTERID+1))) > " SLAVEID test -z $SLAVEID && SLAVEID=$((MASTERID+1)) echo -n "Updating slave config file ... " if sed -r -i "s/^(server-id\s*=\s*)(\S+)\s*/\1$SLAVEID/" $TMPFILE; then echo OK echo -n "Syncing config file to $SLAVE ... " if rsync $TMPFILE root@$SLAVE:/etc/mysql/my.cnf 2> /dev/null; then echo OK OK=1 else echo Failed fi else echo Failed fi else echo Failed rm $TMPFILE fi else echo Failed fi if [ $OK = 0 ]; then echo echo "Please, check the config file on $SLAVE manually." read -p "Pres ENTER to continue. " fi OK=0 echo while [ $OK = 0 ]; do echo -n "Starting slave MySQL server ... " if ssh root@$SLAVE /etc/init.d/szn-mysql-server start > /dev/null 2>&1; then N=30 while [ $N -gt 0 -a $OK = 0 ]; do sleep 1 if ssh root@$SLAVE mysqladmin ping > /dev/null 2>&1; then echo OK OK=1 else echo -n ". " N=$((N-1)) fi done test $OK = 0 && f_ask_again else f_ask_again fi done OK=0 PASS=`echo $PASS1 | sed "s/'/\\\\\\'/g"` echo while [ $OK = 0 ]; do echo -n "Setting up permissions on $MASTER ... " if ssh root@$MASTER "echo \"GRANT REPLICATION SLAVE ON *.* TO repl@'$SLAVE' IDENTIFIED BY '$PASS'; FLUSH PRIVILEGES\" | mysql" > /dev/null 2>&1; then echo OK OK=1 else f_ask_again fi done OK=0 while [ $OK = 0 ]; do echo -n "Setting up replication on $SLAVE ... " if ssh root@$SLAVE "echo \"CHANGE MASTER TO MASTER_HOST='$MASTER', MASTER_USER='repl', MASTER_PASSWORD='$PASS', MASTER_LOG_FILE='$LOGFILE', MASTER_LOG_POS=$LOGPOS;\" | mysql" > /dev/null 2>&1; then echo OK OK=1 else f_ask_again fi done OK=0 while [ $OK = 0 ]; do echo -n "Starting replication on $SLAVE ... " if ssh root@$SLAVE "echo \"SLAVE START;\" | mysql" > /dev/null 2>&1; then echo OK OK=1 else f_ask_again fi done ssh root@$SLAVE -t "watch -n 5 \"echo 'SHOW SLAVE STATUS\\G' | mysql 2> /dev/null; echo; echo 'Press CTRL+C to exit.'\"" 2> /dev/null rm $TMPFILE echo echo "That's all for $SLAVE." done echo echo "That's all." exit 0