#!/usr/bin/env bash ## - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ## - ## - assuming your remote user is called "back", you have ## - to give sudoer rights to him as follow: ## - ## - visudo (edits /etc/sudoers file) ## - ## - add line: ## - back ALL = (root)NOPASSWD:/usr/bin/rsync ## - ## - on the remote database allow the congigured mysql user to ## - access the database from localhost an give him the follwing ## - privileges: ## - Select_priv ## - Lock_tables_priv ## - Show_view_priv ## - Event_priv ## - Process_priv (since MySQL 5.5) ## - ## - INSERT INTO user (Host,User,Password,Select_priv,Lock_tables_priv,Show_view_priv,Event_priv) VALUES('localhost','backup',password('backup'),'Y','Y','Y','Y'); ## - ## - Since MySQL 5.5 - you also have to add process privileges (Process_priv = 'Y') ## - INSERT INTO user (Host,User,Password,Select_priv,Process_priv,Lock_tables_priv,Show_view_priv,Event_priv) VALUES('localhost','backup',password('backup'),'Y','Y','Y','Y','Y'); ## - ## - ## - Since MySQL 5.7.x - you also have to add process privileges (Execute_priv = 'Y') ## - Password field is now: "authentication_string" ## - INSERT INTO user (Host,User,authentication_string,Select_priv,Process_priv,Lock_tables_priv,Show_view_priv,Event_priv,Execute_priv,ssl_cipher,x509_issuer,x509_subject) VALUES('localhost','backup',password('backup'),'Y','Y','Y','Y','Y','Y','','',''); ## - ## - or if updating from older mysql version: ## - ## - UPDATE user SET Execute_priv = 'Y' WHERE User = 'backup'; ## - ## - ## - FLUSH PRIVILEGES; ## - ## - ## - Since Version 5.6, giving password on command line is considered as insecure. ## - To avoid giving the password on command line, you can use an ## - encrypted option file instead. ## - ## - 1.) Create (encrypted) option file: ## - ## - Debian package installation: ## - $ mysql_config_editor set --login-path=local --socket=/var/run/mysqld/mysqld.sock --user=backup --password ## - $ Password: ## - ## - Source installation: ## - $ mysql_config_editor set --login-path=local --socket=/tmp/mysql.sock --user=backup --password ## - $ Password: ## - ## - 2.) Set environment variable mysql_credential_args="--login-path=local" ## - Now, the backup script uses the encrypted option file instead of (unencrypt) password ## - on command line. ## - ## - ## - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! err_Log=${LOCK_DIR}/mysql.err.log > $err_Log ## - load functions ## - . $rcopy_functions_file # --------------------------------------------------- # # -------------------- Variable --------------------- # # _backupDestArchiveDir="${script_backup_dir}/MySQL" if [ $srcHost != "localhost" ] || $_via_ssh_tunnel ;then mysql=`$ssh ${ssh_user}@$srcHost which mysql` mysqldump=`$ssh ${ssh_user}@$srcHost which mysqldump` ssh_options="-o BatchMode=yes -o ConnectTimeout=360" else mysql=`which mysql` mysqldump=`which mysqldump` fi if [ -z "$mysql" ]; then mysql="/usr/local/mysql/bin/mysql" fi if [ -z "$mysqldump" ]; then mysqldump="/usr/local/mysql/bin/mysqldump" fi # # ------------------ Ende Variable ------------------ # # --------------------------------------------------- # if [ $srcHost != "localhost" ] || $_via_ssh_tunnel ;then if [ -n "$mysql_credential_args" ] ; then DATABASES=`$ssh ${ssh_user}@$srcHost "$mysql $mysql_credential_args -N -s -e \"show databases\""` MYSQL_VERSION=`$ssh ${ssh_user}@$srcHost "$mysql $mysql_credential_args -N -s -e \"SELECT VERSION()\""` else DATABASES=`$ssh ${ssh_user}@$srcHost "$mysql -u$mysql_user -p$mysql_password -N -s -e \"show databases\""` MYSQL_VERSION=`$ssh ${ssh_user}@$srcHost "$mysql -u$mysql_user -p$mysql_password -N -s -e \"SELECT VERSION()\""` fi else if [ -n "$mysql_credential_args" ] ; then DATABASES=`$mysql $mysql_credential_args -N -s -e "show databases"` MYSQL_VERSION=`$mysql $mysql_credential_args -N -s -e "SELECT VERSION()"` else DATABASES=`$mysql -u$mysql_user -p$mysql_password -N -s -e "show databases"` MYSQL_VERSION=`$mysql -u$mysql_user -p$mysql_password -N -s -e "SELECT VERSION()"` fi fi MYSQL_VERSION_NUM=`echo $MYSQL_VERSION | awk -F \. '{ printf "%02d", $1; printf "%02d", $2; printf "%02d", $3 }'` if [ ! -d $_backupDestArchiveDir ]; then mkdir -p $_backupDestArchiveDir fi echolog "" if $ARCHIVE ;then if [ "$_TEST" = "1" ];then progArgs="-n $progArgs --stats" elif [ "$_DEBUG" -gt 0 ];then progArgs="$progArgs --stats" if [ "$_DEBUG" -gt 1 ];then formats="%t -- %o %f %b Bytes[%l]" fi fi ## ----------------------------- ## - Backup SQL Grants for users ## - info_msg="save SQL Grants for users" echononl "\t$info_msg" ## - begin timestamp ## - b_timestamp=`$date +"%s"` filedate=`$date +"%Y-%m-%d-%H%M"` if [ $srcHost != "localhost" ] || $_via_ssh_tunnel ;then if [ -n "$mysql_credential_args" ] ; then $( $ssh $ssh_options ${ssh_user}@$srcHost "$mysql $mysql_credential_args -N -s -A -e\"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''\" | $mysql $mysql_credential_args -N -s -A | sed 's/\$/;/g'" \ > ${_backupDestArchiveDir}/MySQLGrants.sql-${filedate}.sql 2> $err_Log exit $? ) retval=$? else $( $ssh $ssh_options ${ssh_user}@$srcHost "$mysql -u$mysql_user -p$mysql_password -N -s -A -e\"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''\" | $mysql -u$mysql_user -p$mysql_password -N -s -A | sed 's/\$/;/g'" \ > ${_backupDestArchiveDir}/MySQLGrants.sql-${filedate}.sql 2> $err_Log exit $? ) retval=$? fi else if [ -n "$mysql_credential_args" ] ; then $( $mysql $mysql_credential_args -N -s -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''" | $mysql $mysql_credential_args -N -s -A | sed 's/\$/;/g' \ > ${_backupDestArchiveDir}/MySQLGrants.sql-${filedate}.sql 2> $err_Log exit $? ) retval=$? else $( $mysql -u$mysql_user -p$mysql_password -N -s -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''" | $mysql -u$mysql_user -p$mysql_password -N -s -A | sed 's/\$/;/g' \ > ${_backupDestArchiveDir}/MySQLGrants.sql-${filedate}.sql 2> $err_Log exit $? ) retval=$? fi fi err_msg="Cannot save SQL Grants for users" keep_backup_on_error=false if [ "$retval" = 0 ];then [ -z $mysql_gzip ] && mysql_gzip=false if $mysql_gzip ; then $gzip ${_backupDestArchiveDir}/MySQLGrants.sql-${filedate}.sql 2> $err_Log retval=$? err_msg="Cannot gzip \"MySQLGrants.sql-${filedate}.sql\"" keep_backup_on_error=true fi fi ## - end timestamp ## - e_timestamp=`$date +"%s"` ## - determin duration ## - _time=`expr $e_timestamp - $b_timestamp` t_h=`expr $_time / 60 / 60` t_rest_h=`expr $_time - $t_h \\* 60 \\* 60` t_m=`expr $t_rest_h / 60` t_s=`expr $t_rest_h - $t_m \\* 60` duration="" if [ $t_h -gt 0 ]; then duration="$t_h h : $t_m min : $t_s sec" elif [ $t_m -gt 0 ];then duration="$t_m min : $t_s sec" else duration="$t_s sec" fi ## - look about errors.. ## - if [ "$retval" != "0" ]; then echolog "" echolog "\t[ERROR] ${err_msg} [ $duration ]\n\t`$cat $err_Log`\n" if ! $keep_backup_on_error ; then rm -f ${_backupDestArchiveDir}/MySQLGrants.sql-${filedate}.sql fi else ## - print durations right-aligned ## - [ -z $right_tabstop ] && right_tabstop=65 _tmp_string="${info_msg}${duration}" _strlen=${#_tmp_string} _count_blank=`expr $right_tabstop - $_strlen` _str_blanks="" while [ $_count_blank -gt 1 ]; do _str_blanks="$_str_blanks " _count_blank=`expr $_count_blank - 1` done echononl "$_str_blanks" echolog " [ $duration ]" fi ## - End: Backup SQL Grants for users ## ---------------------------------- ## ----------------------------- ## - Backup/Create Database Craetion sql statements ## - info_msg="create database creation SQL file" echononl "\t$info_msg" filedate=`$date +"%Y-%m-%d-%H%M"` > ${_backupDestArchiveDir}/MySQL_Create_Databases-${filedate}.sql ## - begin timestamp ## - b_timestamp=`$date +"%s"` retval=0 for i in $DATABASES ; do if [ "$i" = "information_schema" -o "$i" = "performance_schema" ];then continue fi echo "CREATE DATABASE IF NOT EXISTS $i CHARACTER SET utf8 COLLATE utf8_general_ci;" \ >> ${_backupDestArchiveDir}/MySQL_Create_Databases-${filedate}.sql if [ "$?" != 0 ]; then retval=1 fi done err_msg="Cannot create Database Creation SQL file" keep_backup_on_error=false if [ "$retval" = 0 ];then [ -z $mysql_gzip ] && mysql_gzip=false if $mysql_gzip ; then $gzip ${_backupDestArchiveDir}/MySQL_Create_Databases-${filedate}.sql 2> $err_Log retval=$? err_msg="Cannot gzip \"MySQLGrants.sql-${filedate}.sql\"" keep_backup_on_error=true fi fi ## - end timestamp ## - e_timestamp=`$date +"%s"` ## - determin duration ## - _time=`expr $e_timestamp - $b_timestamp` t_h=`expr $_time / 60 / 60` t_rest_h=`expr $_time - $t_h \\* 60 \\* 60` t_m=`expr $t_rest_h / 60` t_s=`expr $t_rest_h - $t_m \\* 60` duration="" if [ $t_h -gt 0 ]; then duration="$t_h h : $t_m min : $t_s sec" elif [ $t_m -gt 0 ];then duration="$t_m min : $t_s sec" else duration="$t_s sec" fi ## - look about errors.. ## - if [ "$retval" != "0" ]; then echolog "" echolog "\t[ERROR] ${err_msg} [ $duration ]\n\t`$cat $err_Log`\n" if ! $keep_backup_on_error ; then rm -f ${_backupDestArchiveDir}/MySQL_Create_Databases-${filedate}.sql fi else ## - print durations right-aligned ## - [ -z $right_tabstop ] && right_tabstop=65 _tmp_string="${info_msg}${duration}" _strlen=${#_tmp_string} _count_blank=`expr $right_tabstop - $_strlen` _str_blanks="" while [ $_count_blank -gt 1 ]; do _str_blanks="$_str_blanks " _count_blank=`expr $_count_blank - 1` done echononl "$_str_blanks" echolog " [ $duration ]" fi ## - End: Create Database Craetion sql statements ## ----------------------------------------------------- ## - backup all databases except the those from midgard.. ## - for i in $DATABASES ; do ## ------------------------------------ ## - Save Functions seperatly if exists ## - declare -i COUNT_FUNCTION=0 if [ $srcHost != "localhost" ] || $_via_ssh_tunnel ;then if [ -n "$mysql_credential_args" ] ; then COUNT_FUNCTION=`$ssh ${ssh_user}@$srcHost "$mysql $mysql_credential_args -N -s -e \"SELECT COUNT(*) FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '${i}'\""` else COUNT_FUNCTION=`$ssh ${ssh_user}@$srcHost "$mysql -u$mysql_user -p$mysql_password -N -s -e \"SELECT COUNT(*) FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '${i}'\""` fi else if [ -n "$mysql_credential_args" ] ; then COUNT_FUNCTION=`$mysql $mysql_credential_args -N -s -e "SELECT COUNT(*) FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '${i}'"` else COUNT_FUNCTION=`$mysql -u$mysql_user -p$mysql_password -N -s -e "SELECT COUNT(*) FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '${i}'"` fi fi if [ $COUNT_FUNCTION -gt 0 ] ; then ## - begin timestamp ## - b_timestamp=`$date +"%s"` filedate=`$date +"%Y-%m-%d-%H%M"` mysqldump_flags="--no-data --no-create-info --routines" info_msg="save functions of database $i.." echononl "\t$info_msg" if [ $srcHost != "localhost" ] || $_via_ssh_tunnel ;then if [ -n "$mysql_credential_args" ] ; then $( $ssh $ssh_options ${ssh_user}@$srcHost "$mysqldump $mysql_credential_args $mysqldump_flags $i" \ > ${_backupDestArchiveDir}/${i}/MySQLStoredProcedures.${i}-${filedate}.sql 2> $err_Log exit $? ) retval=$? else $( $ssh $ssh_options ${ssh_user}@$srcHost "$mysqldump -u$mysql_user -p$mysql_password $mysqldump_flags $i" \ > ${_backupDestArchiveDir}/${i}/MySQLStoredProcedures.${i}-${filedate}.sql 2> $err_Log exit $? ) retval=$? fi else if [ -n "$mysql_credential_args" ] ; then $( $mysqldump $mysql_credential_args $mysqldump_flags $i \ > ${_backupDestArchiveDir}/${i}/MySQLStoredProcedures.${i}-${filedate}.sql 2> $err_Log exit $? ) retval=$? else $( $mysqldump -u$mysql_user -p$mysql_password $mysqldump_flags $i \ > ${_backupDestArchiveDir}/${i}/MySQLStoredProcedures.${i}-${filedate}.sql 2> $err_Log exit $? ) retval=$? fi fi err_msg="Cannot save functions of database \"$i\"" keep_backup_on_error=false if [ "$retval" = 0 ];then [ -z $mysql_gzip ] && mysql_gzip=false if $mysql_gzip ; then $gzip ${_backupDestArchiveDir}/MySQLStoredProcedures.${i}-${filedate}.sql 2> $err_Log retval=$? err_msg="Cannot gzip \"MySQLStoredProcedures.${i}-${filedate}.sql\"" keep_backup_on_error=true fi fi ## - end timestamp ## - e_timestamp=`$date +"%s"` ## - determin duration ## - _time=`expr $e_timestamp - $b_timestamp` t_h=`expr $_time / 60 / 60` t_rest_h=`expr $_time - $t_h \\* 60 \\* 60` t_m=`expr $t_rest_h / 60` t_s=`expr $t_rest_h - $t_m \\* 60` duration="" if [ $t_h -gt 0 ]; then duration="$t_h h : $t_m min : $t_s sec" elif [ $t_m -gt 0 ];then duration="$t_m min : $t_s sec" else duration="$t_s sec" fi ## - look about errors.. ## - if [ "$retval" != "0" ]; then echolog "" echolog "\t[ERROR] ${err_msg} [ $duration ]\n\t`$cat $err_Log`\n" if ! $keep_backup_on_error ; then rm -f ${_backupDestArchiveDir}/MySQLStoredProcedures.${i}-${filedate}.sql fi else ## - print durations right-aligned ## - [ -z $right_tabstop ] && right_tabstop=65 _tmp_string="${info_msg}${duration}" _strlen=${#_tmp_string} _count_blank=`expr $right_tabstop - $_strlen` _str_blanks="" while [ $_count_blank -gt 1 ]; do _str_blanks="$_str_blanks " _count_blank=`expr $_count_blank - 1` done echononl "$_str_blanks" echolog " [ $duration ]" fi fi ## - End: Save Functions seperatly if exists ## ----------------------------------------- ## -------------- ## - Dump Databas filedate=`$date +"%Y-%m-%d-%H%M"` ## - begin timestamp ## - b_timestamp=`$date +"%s"` ## - Like --opt but without --extended-insert. So mysqldump_flags="--protocol=SOCKET --max_allowed_packet=128M --skip-opt --add-drop-table --add-locks --create-options --quick --set-charset --disable-keys --lock-tables --routines" if [ "$i" = "information_schema" -o "$i" = "performance_schema" ];then mysqldump_flags="$mysqldump_flags --single-transaction" if [ "$i" = "information_schema" -a "$MYSQL_VERSION_NUM" -ge 050700 ]; then ## - As of MySQL 5.7.6, the Performance Schema also contains system and status variable tables. ## - ## - The Performance Schema tables are intended to replace the INFORMATION_SCHEMA tables, ## - which are deprecated as of MySQL 5.7.6 and will be removed in a future MySQL release. ## - ## - As of MySQL 5.7.6, the value of the "show_compatibility_56" system variable ## - affects the information available from "information_schema". If tis variable ## - is set to "OFF" (the default), mysqldump produces the tollowing error: ## - ## - Couldn't execute 'SELECT /*!40001 SQL_NO_CACHE */ * FROM `GLOBAL_STATUS`': ## - The 'INFORMATION_SCHEMA.GLOBAL_STATUS' feature is disabled; see the documentation ## - for 'show_compatibility_56' (3167) ## - ## - We will ignore errors (force) and also we don#t want error messages ## - mysqldump_flags="$mysqldump_flags --force --log-error=/dev/null" fi elif [ "$i" = "mysql" -a "$MYSQL_VERSION_NUM" -ge 050500 ]; then mysqldump_flags="$mysqldump_flags --events" fi if [ "$destHost" = "localhost" ]; then if [ ! -d ${_backupDestArchiveDir}/${i} ] ; then $mkdir -p ${_backupDestArchiveDir}/${i} fi fi info_msg="save database $i.." echononl "\t$info_msg" if [ $srcHost != "localhost" ] || $_via_ssh_tunnel ;then if [ -n "$mysql_credential_args" ] ; then $( $ssh $ssh_options ${ssh_user}@$srcHost "$mysqldump $mysql_credential_args $mysqldump_flags $i" \ > ${_backupDestArchiveDir}/${i}/${i}-${filedate}.sql 2> $err_Log exit $? ) retval=$? else $( $ssh $ssh_options ${ssh_user}@$srcHost "$mysqldump -u$mysql_user -p$mysql_password $mysqldump_flags $i" \ > ${_backupDestArchiveDir}/${i}/${i}-${filedate}.sql 2> $err_Log exit $? ) retval=$? fi else if [ -n "$mysql_credential_args" ] ; then $( $mysqldump $mysql_credential_args $mysqldump_flags $i \ > ${_backupDestArchiveDir}/${i}/${i}-${filedate}.sql 2> $err_Log exit $? ) retval=$? else $( $mysqldump -u$mysql_user -p$mysql_password $mysqldump_flags $i \ > ${_backupDestArchiveDir}/${i}/${i}-${filedate}.sql 2> $err_Log exit $? ) retval=$? fi fi err_msg="Cannot save database \"$i\"" keep_backup_on_error=false if [ "$i" = "information_schema" -a "$MYSQL_VERSION_NUM" -ge 050700 ]; then ## - As sayed befor: in that case, we want ignore all errors taken from that dump ## - retval=0 fi if [ "$retval" = 0 ];then [ -z $mysql_gzip ] && mysql_gzip=false if $mysql_gzip ; then $gzip ${_backupDestArchiveDir}/${i}/${i}-${filedate}.sql 2> $err_Log retval=$? err_msg="Cannot gzip database \"$i\"" keep_backup_on_error=true fi fi ## - end timestamp ## - e_timestamp=`$date +"%s"` ## - determin duration ## - _time=`expr $e_timestamp - $b_timestamp` t_h=`expr $_time / 60 / 60` t_rest_h=`expr $_time - $t_h \\* 60 \\* 60` t_m=`expr $t_rest_h / 60` t_s=`expr $t_rest_h - $t_m \\* 60` duration="" if [ $t_h -gt 0 ]; then duration="$t_h h : $t_m min : $t_s sec" elif [ $t_m -gt 0 ];then duration="$t_m min : $t_s sec" else duration="$t_s sec" fi ## - look about errors.. ## - if [ "$retval" != "0" ]; then echolog "" echolog "\t[ERROR] ${err_msg} [ $duration ]\n\t`$cat $err_Log`\n" if ! $keep_backup_on_error ; then rm -f ${_backupDestArchiveDir}/${i}/${i}-${filedate}.sql fi continue else ## - print durations right-aligned ## - [ -z $right_tabstop ] && right_tabstop=65 _tmp_string="${info_msg}${duration}" _strlen=${#_tmp_string} _count_blank=`expr $right_tabstop - $_strlen` _str_blanks="" while [ $_count_blank -gt 1 ]; do _str_blanks="$_str_blanks " _count_blank=`expr $_count_blank - 1` done echononl "$_str_blanks" echolog " [ $duration ]" fi ## - End: Dump Databas ## ------------------- done ## /usr/bin/killall -HUP mysqld else echolog "\tARCHIVE is set to $ARCHIVE. So nothing to do." fi echolog "" ## - remove all files older than $days days.. ## - $find $_backupDestArchiveDir -type f -mtime +${days} -exec rm {} \;