diff options
author | Julius Goryavsky <julius.goryavsky@mariadb.com> | 2021-05-21 03:38:04 +0200 |
---|---|---|
committer | Julius Goryavsky <julius.goryavsky@mariadb.com> | 2021-05-21 13:09:58 +0200 |
commit | 8e280f300744ff5e0d7eee0e254dae0ca95e9a5b (patch) | |
tree | 3b787db326539832a1f3ea200a1e0a83ad469f0c /scripts | |
parent | 5667baad5d7a597d56786e6872da79696e511149 (diff) | |
download | mariadb-git-8e280f300744ff5e0d7eee0e254dae0ca95e9a5b.tar.gz |
MDEV-25719: stunnel uses "verifyChain" without subject checks
Another batch of changes that should make the SST process
more reliable in all scenarios:
1) Added hostname or CN verification when stunnel is used
with certificate chain verification (verifyChain = yes);
2) Added check for the absence of the stunnel utility for
mtr tests;
3) Deletion of working files before and after SST is done
more accurately;
4) rsync on joiner can be run even if the path to its
configuration file contains spaces;
5) More accurate directory creation (for data files and
for logs);
6) IST with mysqldump no longer turns off statement logging;
7) Reset password for mysqldump when password is empty but
username is specified;
8) More reliable quoting when generating statements in
wsrep_sst_mysqldump;
9) Added explicit generation of 2048-bit Diffie-Hellman
parameters for sockat < 1.7.3, by analogy with xtrabackup;
10) Compression parameters for qpress are read from all
suitable server groups in configuration file, as well as
from the [sst] and [xtrabackup] groups;
11) Added a test that checks compression using qpress;
12) Checking for optional utilities is modified to work even
if they implemented as built-in shell commands (unlikely
on real systems, but more reliable).
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/wsrep_sst_common.sh | 88 | ||||
-rw-r--r-- | scripts/wsrep_sst_mariabackup.sh | 129 | ||||
-rw-r--r-- | scripts/wsrep_sst_mysqldump.sh | 64 | ||||
-rw-r--r-- | scripts/wsrep_sst_rsync.sh | 110 |
4 files changed, 268 insertions, 123 deletions
diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index c98b388a1e2..f4ac2e9936d 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -1,5 +1,5 @@ -# Copyright (C) 2012-2015 Codership Oy # Copyright (C) 2017-2021 MariaDB +# Copyright (C) 2012-2015 Codership Oy # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -822,14 +822,15 @@ wsrep_log_info() wsrep_cleanup_progress_file() { - [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null || true + [ -n "$SST_PROGRESS_FILE" -a \ + -f "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null || true } wsrep_check_program() { local prog="$1" local cmd=$(command -v "$prog") - if [ ! -x "$cmd" ]; then + if [ -z "$cmd" ]; then echo "'$prog' not found in PATH" return 2 # no such file or directory fi @@ -865,9 +866,9 @@ get_openssl() fi # Let's look for openssl: OPENSSL_BINARY="$(command -v openssl)" - if [ ! -x "$OPENSSL_BINARY" ]; then + if [ -z "$OPENSSL_BINARY" ]; then OPENSSL_BINARY='/usr/bin/openssl' - if [ ! -x "$OPENSSL_BINARY" ]; then + if [ -z "$OPENSSL_BINARY" ]; then OPENSSL_BINARY="" fi fi @@ -899,14 +900,14 @@ is_local_ip() [ "$1" = "$(hostname -d)" ] && return 0 local ip_util="$(command -v ip)" - if [ -x "$ip_util" ]; then + if [ -n "$ip_util" ]; then # ip address show ouput format is " inet[6] <address>/<mask>": "$ip_util" address show \ | grep -E "^[[:space:]]*inet.? [^[:space:]]+/" -o \ | grep -F " $1/" >/dev/null && return 0 else local ifconfig_util="$(command -v ifconfig)" - if [ -x "$ifconfig_util" ]; then + if [ -n "$ifconfig_util" ]; then # ifconfig output format is " inet[6] <address> ...": "$ifconfig_util" \ | grep -E "^[[:space:]]*inet.? [^[:space:]]+ " -o \ @@ -923,16 +924,79 @@ check_sockets_utils() sockstat_available=0 ss_available=0 - [ -x "$(command -v lsof)" ] && lsof_available=1 - [ -x "$(command -v sockstat)" ] && sockstat_available=1 - [ -x "$(command -v ss)" ] && ss_available=1 + [ -n "$(command -v lsof)" ] && lsof_available=1 + [ -n "$(command -v sockstat)" ] && sockstat_available=1 + [ -n "$(command -v ss)" ] && ss_available=1 if [ $lsof_available -eq 0 -a \ $sockstat_available -eq 0 -a \ $ss_available -eq 0 ] then - wsrep_log_error "Neither lsof tool, nor ss or sockstat was found in " \ - "the PATH! Make sure you have it installed." + wsrep_log_error "Neither lsof, nor sockstat or ss tool was found in " \ + "the PATH. Make sure you have it installed." exit 2 # ENOENT fi } + +# +# If the ssl_dhparams variable is already set, uses that as a source +# of dh parameters for OpenSSL. Otherwise, looks for dhparams.pem in +# the datadir, and creates it there if it can't find the file. +# +check_for_dhparams() +{ + if [ -z "$ssl_dhparams" ]; then + ssl_dhparams="$DATA/dhparams.pem" + if [ ! -r "$ssl_dhparams" ]; then + get_openssl + if [ -n "$OPENSSL_BINARY" ]; then + wsrep_log_info "Could not find dhparams file, creating $ssl_dhparams" + if ! "$OPENSSL_BINARY" dhparam -out "$ssl_dhparams" 2048 >/dev/null 2>&1 + then + wsrep_log_error "******** ERROR *****************************************" + wsrep_log_error "* Could not create the dhparams.pem file with OpenSSL. *" + wsrep_log_error "********************************************************" + ssl_dhparams="" + fi + else + # Rollback: if openssl is not installed, then use + # the default parameters: + ssl_dhparams="" + fi + fi + fi +} + +# +# Compares two version strings. +# The first parameter is the version to be checked; +# The second parameter is the minimum version required; +# Returns 1 (failure) if $1 >= $2, 0 (success) otherwise. +# +check_for_version() +{ + y1=${1#*.} + [ "$y1" = "$1" ] && y1="" + z1=${y1#*.} + [ "$z1" = "$y1" ] && z1="" + x1=${1%%.*} + y1=${y1%%.*} + z1=${z1%%.*} + [ -z "$y1" ] && y1=0 + [ -z "$z1" ] && z1=0 + y2=${2#*.} + [ "$y2" = "$2" ] && y2="" + z2=${y2#*.} + [ "$z2" = "$y2" ] && z2="" + x2=${2%%.*} + y2=${y2%%.*} + z2=${z2%%.*} + [ -z "$y2" ] && y2=0 + [ -z "$z2" ] && z2=0 + [ $x1 -lt $x2 ] && return 1 + [ $x1 -gt $x2 ] && return 0 + [ $y1 -lt $y2 ] && return 1 + [ $y1 -gt $y2 ] && return 0 + [ $z1 -lt $z2 ] && return 1 + return 0 +} diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 899f3eb4f3c..5618c704dbc 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -73,6 +73,12 @@ xtmpdir="" scomp="" sdecomp="" +ssl_dhparams="" + +compress='none' +compress_chunk="" +compress_threads="" + readonly SECRET_TAG="secret" # Required for backup locks @@ -80,25 +86,24 @@ readonly SECRET_TAG="secret" # 5.6.21 PXC and later can't donate to an older joiner sst_ver=1 -if [ -x "$(command -v pv)" ] && pv --help | grep -qw -- '-F'; then +if [ -n "$(command -v pv)" ] && pv --help | grep -qw -- '-F'; then pvopts="$pvopts $pvformat" fi pcmd="pv $pvopts" declare -a RC -set +e MARIABACKUP_BIN="$(command -v mariabackup)" if [ ! -x "$MARIABACKUP_BIN" ]; then wsrep_log_error 'mariabackup binary not found in $PATH' exit 42 fi -set -e MBSTREAM_BIN=mbstream DATA="$WSREP_SST_OPT_DATA" INFO_FILE="xtrabackup_galera_info" IST_FILE="xtrabackup_ist" MAGIC_FILE="$DATA/$INFO_FILE" + INNOAPPLYLOG="$DATA/mariabackup.prepare.log" INNOMOVELOG="$DATA/mariabackup.move.log" INNOBACKUPLOG="$DATA/mariabackup.backup.log" @@ -184,7 +189,7 @@ get_keys() ecmd="$ecmd -k '$ekey'" fi elif [ "$eformat" = 'xbcrypt' ]; then - if [ ! -x "$(command -v xbcrypt)" ]; then + if [ -z "$(command -v xbcrypt)" ]; then wsrep_log_error "If encryption using the xbcrypt is enabled, " \ "then you need to install xbcrypt" exit 2 @@ -268,6 +273,22 @@ get_transfer() exit 2 fi + # Determine the socat version + SOCAT_VERSION=$(socat -V 2>&1 | grep -m1 -oe '[0-9]\.[0-9][\.0-9]*') + if [ -z "$SOCAT_VERSION" ]; then + wsrep_log_error "******** FATAL ERROR ******************" + wsrep_log_error "* Cannot determine the socat version. *" + wsrep_log_error "***************************************" + exit 2 + fi + + if ! check_for_version "$SOCAT_VERSION" "1.7.3"; then + # socat versions < 1.7.3 will have 512-bit dhparams (too small) + # so create 2048-bit dhparams and send that as a parameter: + check_for_dhparams + sockopt=",dhparam='$ssl_dhparams'$sockopt" + fi + if [ $encrypt -eq 2 ]; then wsrep_log_info "Using openssl based encryption with socat: with crt and pem" if [ -z "$tpem" -o -z "$tcert" ]; then @@ -328,7 +349,7 @@ get_footprint() { pushd "$WSREP_SST_OPT_DATA" 1>/dev/null payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | du --files0-from=- --block-size=1 -c | awk 'END { print $1 }') - if $MY_PRINT_DEFAULTS xtrabackup | grep -q -- "--compress"; then + if [ "$compress" != 'none' ]; then # QuickLZ has around 50% compression ratio # When compression/compaction used, the progress is only an approximate. payload=$(( payload*1/2 )) @@ -340,7 +361,7 @@ get_footprint() adjust_progress() { - if [ ! -x "$(command -v pv)" ]; then + if [ -z "$(command -v pv)" ]; then wsrep_log_error "pv not found in path: $PATH" wsrep_log_error "Disabling all progress/rate-limiting" pcmd="" @@ -447,6 +468,14 @@ read_cnf() if [ $ssyslog -ne -1 ]; then ssyslog=$(in_config 'mysqld_safe' 'syslog') fi + + if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then + compress=$(parse_cnf "$encgroups" 'compress' 'none') + if [ "$compress" != 'none' ]; then + compress_chunk=$(parse_cnf "$encgroups" 'compress-chunk-size') + compress_threads=$(parse_cnf "$encgroups" 'compress-threads') + fi + fi } get_stream() @@ -480,7 +509,7 @@ get_proc() sig_joiner_cleanup() { wsrep_log_error "Removing $MAGIC_FILE file due to signal" - rm -f "$MAGIC_FILE" + [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" } cleanup_joiner() @@ -540,7 +569,7 @@ cleanup_donor() fi fi - rm -f "$DATA/$IST_FILE" || true + [ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" if [ -n "$progress" -a -p "$progress" ]; then wsrep_log_info "Cleaning up fifo file $progress" @@ -549,13 +578,8 @@ cleanup_donor() wsrep_log_info "Cleaning up temporary directories" - if [ -n "$xtmpdir" ]; then - [ -d "$xtmpdir" ] && rm -rf "$xtmpdir" || true - fi - - if [ -n "$itmpdir" ]; then - [ -d "$itmpdir" ] && rm -rf "$itmpdir" || true - fi + [ -n "$xtmpdir" -a -d "$xtmpdir" ] && rm -rf "$xtmpdir" || true + [ -n "$itmpdir" -a -d "$itmpdir" ] && rm -rf "$itmpdir" || true # Final cleanup pgid=$(ps -o pgid= $$ | grep -o '[0-9]*') @@ -682,12 +706,9 @@ recv_joiner() return fi - pushd "$dir" 1>/dev/null - set +e - local ltcmd="$tcmd" if [ $tmt -gt 0 ]; then - if [ -x "$(command -v timeout)" ]; then + if [ -n "$(command -v timeout)" ]; then if timeout --help | grep -qw -- '-k'; then ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd" else @@ -696,6 +717,9 @@ recv_joiner() fi fi + pushd "$dir" 1>/dev/null + set +e + if [ $wait -ne 0 ]; then wait_for_listen "$SST_PORT" "$ADDR" "$MODULE" & fi @@ -781,7 +805,7 @@ monitor_process() wsrep_check_programs "$MARIABACKUP_BIN" -rm -f "$MAGIC_FILE" +[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" if [ "$WSREP_SST_OPT_ROLE" != 'joiner' -a "$WSREP_SST_OPT_ROLE" != 'donor' ]; then wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" @@ -795,13 +819,6 @@ if "$MARIABACKUP_BIN" --help 2>/dev/null | grep -qw -- '--version-check'; then disver='--no-version-check' fi -iopts="$iopts --databases-exclude='lost+found'" - -if [ ${FORCE_FTWRL:-0} -eq 1 ]; then - wsrep_log_info "Forcing FTWRL due to environment variable FORCE_FTWRL equal to $FORCE_FTWRL" - iopts="$iopts --no-backup-locks" -fi - # if no command line argument and INNODB_DATA_HOME_DIR environment variable # is not set, try to get it from my.cnf: if [ -z "$INNODB_DATA_HOME_DIR" ]; then @@ -810,19 +827,19 @@ fi OLD_PWD="$(pwd)" +cd "$WSREP_SST_OPT_DATA" if [ -n "$INNODB_DATA_HOME_DIR" ]; then # handle both relative and absolute paths - INNODB_DATA_HOME_DIR=$(cd "$DATA"; mkdir -p "$INNODB_DATA_HOME_DIR"; cd "$INNODB_DATA_HOME_DIR"; pwd -P) -else - # default to datadir - INNODB_DATA_HOME_DIR=$(cd "$DATA"; pwd -P) + [ ! -d "$INNODB_DATA_HOME_DIR" ] && mkdir -p "$INNODB_DATA_HOME_DIR" + cd "$INNODB_DATA_HOME_DIR" fi +INNODB_DATA_HOME_DIR=$(pwd -P) cd "$OLD_PWD" if [ $ssyslog -eq 1 ]; then - if [ -x "$(command -v logger)" ]; then + if [ -n "$(command -v logger)" ]; then wsrep_log_info "Logging all stderr of SST/mariabackup to syslog" exec 2> >(logger -p daemon.err -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE) @@ -850,10 +867,8 @@ if [ $sstlogarchive -eq 1 ] then ARCHIVETIMESTAMP=$(date "+%Y.%m.%d-%H.%M.%S.%N") - if [ -n "$sstlogarchivedir" ] - then - if [ ! -d "$sstlogarchivedir" ] - then + if [ -n "$sstlogarchivedir" ]; then + if [ ! -d "$sstlogarchivedir" ]; then mkdir -p "$sstlogarchivedir" fi fi @@ -927,7 +942,6 @@ then if [ $WSREP_SST_OPT_BYPASS -eq 0 ] then - usrst=0 if [ -z "$sst_ver" ]; then wsrep_log_error "Upgrade joiner to 5.6.21 or higher for backup locks support" wsrep_log_error "The joiner is not supported for this version of donor" @@ -944,6 +958,7 @@ then itmpdir="$(mktemp -d)" wsrep_log_info "Using $itmpdir as mariabackup temporary directory" + usrst=0 if [ -n "$WSREP_SST_OPT_USER" ]; then INNOEXTRA="$INNOEXTRA --user='$WSREP_SST_OPT_USER'" usrst=1 @@ -1008,6 +1023,25 @@ then tcmd="$ecmd | $tcmd" fi + iopts="$iopts --databases-exclude='lost+found'" + + if [ ${FORCE_FTWRL:-0} -eq 1 ]; then + wsrep_log_info "Forcing FTWRL due to environment variable FORCE_FTWRL equal to $FORCE_FTWRL" + iopts="$iopts --no-backup-locks" + fi + + # if compression is enabled for backup files, then add the + # appropriate options to the mariabackup command line: + if [ "$compress" != 'none' ]; then + iopts="$iopts --compress${compress:+=$compress}" + if [ -n "$compress_threads" ]; then + iopts="$iopts --compress-threads=$compress_threads" + fi + if [ -n "$compress_chunk" ]; then + iopts="$iopts --compress-chunk-size=$compress_chunk" + fi + fi + setup_commands set +e timeit "$stagemsg-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" @@ -1082,10 +1116,12 @@ then MODULE="xtrabackup_sst" - rm -f "$DATA/$IST_FILE" + [ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" # May need xtrabackup_checkpoints later on - rm -f "$DATA/xtrabackup_binary" "$DATA/xtrabackup_galera_info" "$DATA/ib_logfile0" + [ -f "$DATA/xtrabackup_binary" ] && rm -f "$DATA/xtrabackup_binary" + [ -f "$DATA/xtrabackup_galera_info" ] && rm -f "$DATA/xtrabackup_galera_info" + [ -f "$DATA/ib_logfile0" ] && rm -f "$DATA/ib_logfile0" ADDR="$WSREP_SST_OPT_ADDR" @@ -1185,8 +1221,6 @@ then wsrep_log_info "Waiting for SST streaming to complete!" monitor_process $jpid - get_proc - if [ ! -s "$DATA/xtrabackup_checkpoints" ]; then wsrep_log_error "xtrabackup_checkpoints missing, failed mariabackup/SST on donor" exit 2 @@ -1203,11 +1237,15 @@ then if [ -n "$qpfiles" ]; then wsrep_log_info "Compressed qpress files found" - if [ ! -x "$(command -v qpress)" ]; then - wsrep_log_error "qpress not found in path: $PATH" + if [ -z "$(command -v qpress)" ]; then + wsrep_log_error "qpress utility not found in the path" exit 22 fi + get_proc + + dcmd="xargs -n 2 qpress -dT$nproc" + if [ -n "$progress" ] && pv --help | grep -qw -- '--line-mode'; then count=$(find "$DATA" -type f -name '*.qp' | wc -l) count=$(( count*2 )) @@ -1217,9 +1255,7 @@ then fi pcmd="pv $pvopts" adjust_progress - dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" - else - dcmd="xargs -n 2 qpress -T${nproc}d" + dcmd="$pcmd | $dcmd" fi # Decompress the qpress files @@ -1267,6 +1303,7 @@ then MAGIC_FILE="$TDATA/$INFO_FILE" wsrep_log_info "Moving the backup to ${TDATA}" timeit "mariabackup move stage" "$INNOMOVE" + if [ $? -eq 0 ]; then wsrep_log_info "Move successful, removing ${DATA}" rm -rf "$DATA" diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh index e227a888baf..4aa3f8e63d8 100644 --- a/scripts/wsrep_sst_mysqldump.sh +++ b/scripts/wsrep_sst_mysqldump.sh @@ -45,7 +45,12 @@ then exit $EINVAL fi -[ -n "$WSREP_SST_OPT_USER" ] && AUTH="-u$WSREP_SST_OPT_USER" || AUTH= +AUTH="" +usrst=0 +if [ -n "$WSREP_SST_OPT_USER" ]; then + AUTH="-u$WSREP_SST_OPT_USER" + usrst=1 +fi # Refs https://github.com/codership/mysql-wsrep/issues/141 # Passing password in MYSQL_PWD environment variable is considered @@ -56,9 +61,14 @@ fi # whereas (at least on Linux) unprivileged user can't see process environment # that he does not own. So while it may be not secure in the NSA sense of the # word, it is arguably more secure than passing password on the command line. -[ -n "$WSREP_SST_OPT_PSWD" ] && export MYSQL_PWD="$WSREP_SST_OPT_PSWD" +if [ -n "$WSREP_SST_OPT_PSWD" ]; then + export MYSQL_PWD="$WSREP_SST_OPT_PSWD" +elif [ $usrst -eq 1 ]; then + # Empty password, used for testing, debugging etc. + unset MYSQL_PWD +fi -STOP_WSREP="SET wsrep_on=OFF;" +STOP_WSREP='SET wsrep_on=OFF;' # mysqldump cannot restore CSV tables, fix this issue CSV_TABLES_FIX=" @@ -68,13 +78,13 @@ USE mysql; SET @cond = (SELECT (SUPPORT = 'YES' or SUPPORT = 'DEFAULT') FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'csv'); -SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"General log\"', 'SET @dummy = 0'); +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8mb3 COMMENT=\"General log\"', 'SET @dummy = 0'); PREPARE stmt FROM @stmt; EXECUTE stmt; DROP PREPARE stmt; -SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent int(11) NOT NULL, rows_examined int(11) NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"Slow log\"', 'SET @dummy = 0'); +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent int(11) NOT NULL, rows_examined int(11) NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8mb3 COMMENT=\"Slow log\"', 'SET @dummy = 0'); PREPARE stmt FROM @stmt; EXECUTE stmt; @@ -99,15 +109,15 @@ MYSQL="$MYSQL_CLIENT $WSREP_SST_OPT_CONF "\ # Check if binary logging is enabled on the joiner node. # Note: SELECT cannot be used at this point. -LOG_BIN=$(echo "set statement wsrep_sync_wait=0 for SHOW VARIABLES LIKE 'log_bin'" | $MYSQL |\ +LOG_BIN=$(echo "set statement wsrep_sync_wait=0 for SHOW VARIABLES LIKE 'log_bin'" | $MYSQL | \ tail -1 | awk -F ' ' '{ print $2 }') # Check the joiner node's server version. -SERVER_VERSION=$(echo "set statement wsrep_sync_wait=0 for SHOW VARIABLES LIKE 'version'" | $MYSQL |\ +SERVER_VERSION=$(echo "set statement wsrep_sync_wait=0 for SHOW VARIABLES LIKE 'version'" | $MYSQL | \ tail -1 | awk -F ' ' '{ print $2 }') # Retrieve the donor's @@global.gtid_binlog_state. -GTID_BINLOG_STATE=$(echo "SHOW GLOBAL VARIABLES LIKE 'gtid_binlog_state'" | $MYSQL |\ +GTID_BINLOG_STATE=$(echo "SHOW GLOBAL VARIABLES LIKE 'gtid_binlog_state'" | $MYSQL | \ tail -1 | awk -F ' ' '{ print $2 }') RESET_MASTER="" @@ -115,7 +125,7 @@ SET_GTID_BINLOG_STATE="" SQL_LOG_BIN_OFF="" # Safety check -if [ "${SERVER_VERSION%%.*}" != '5' ] +if [ ${SERVER_VERSION%%.*} -gt 5 ] then # If binary logging is enabled on the joiner node, we need to copy donor's # gtid_binlog_state to joiner. In order to do that, a RESET MASTER must be @@ -135,29 +145,29 @@ MYSQLDUMP="$MYSQLDUMP $WSREP_SST_OPT_CONF $AUTH -S$WSREP_SST_OPT_SOCKET \ --disable-keys --extended-insert --skip-lock-tables --quick --set-charset \ --skip-comments --flush-privileges --all-databases --events" -# need to disable logging when loading the dump -# reason is that dump contains ALTER TABLE for log tables, and -# this causes an error if logging is enabled -GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@GENERAL_LOG"` -SLOW_LOG_OPT=`$MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@SLOW_QUERY_LOG"` -$MYSQL -e "$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF" -$MYSQL -e "$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF" - -# commands to restore log settings -RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" -RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;" - if [ $WSREP_SST_OPT_BYPASS -eq 0 ] then - (echo $STOP_WSREP && echo $RESET_MASTER && \ - echo $SET_GTID_BINLOG_STATE && echo $SQL_LOG_BIN_OFF && \ - echo $STOP_WSREP && $MYSQLDUMP && echo $CSV_TABLES_FIX && \ - echo $RESTORE_GENERAL_LOG && echo $RESTORE_SLOW_QUERY_LOG && \ - echo $SET_START_POSITION && echo $SET_WSREP_GTID_DOMAIN_ID \ + # need to disable logging when loading the dump + # reason is that dump contains ALTER TABLE for log tables, and + # this causes an error if logging is enabled + GENERAL_LOG_OPT=$($MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@GENERAL_LOG") + SLOW_LOG_OPT=$($MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@SLOW_QUERY_LOG") + + LOG_OFF="SET GLOBAL GENERAL_LOG=OFF; SET GLOBAL SLOW_QUERY_LOG=OFF;" + + # commands to restore log settings + RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" + RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;" + + (echo "$STOP_WSREP" && echo "$LOG_OFF" && echo "$RESET_MASTER" && \ + echo "$SET_GTID_BINLOG_STATE" && echo "$SQL_LOG_BIN_OFF" && \ + echo "$STOP_WSREP" && $MYSQLDUMP && echo "$CSV_TABLES_FIX" && \ + echo "$RESTORE_GENERAL_LOG" && echo "$RESTORE_SLOW_QUERY_LOG" && \ + echo "$SET_START_POSITION" && echo "$SET_WSREP_GTID_DOMAIN_ID" \ || echo "SST failed to complete;") | $MYSQL else wsrep_log_info "Bypassing state dump." - echo $SET_START_POSITION | $MYSQL + echo "$SET_START_POSITION" | $MYSQL fi # diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 4f39835e15d..92f77eec331 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -40,13 +40,12 @@ cleanup_joiner() [ "0" != "$RSYNC_REAL_PID" ] && \ kill $RSYNC_REAL_PID && \ sleep 0.5 && \ - kill -9 $RSYNC_REAL_PID >/dev/null 2>&1 || \ - : - rm -rf "$RSYNC_CONF" - rm -f "$STUNNEL_CONF" - rm -f "$STUNNEL_PID" - rm -rf "$MAGIC_FILE" - rm -rf "$RSYNC_PID" + kill -9 $RSYNC_REAL_PID >/dev/null 2>&1 || : + [ -f "$RSYNC_CONF" ] && rm -f "$RSYNC_CONF" + [ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF" + [ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID" + [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" + [ -f "$RSYNC_PID" ] && rm -f "$RSYNC_PID" wsrep_log_info "Joiner cleanup done." if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then wsrep_cleanup_progress_file @@ -125,17 +124,13 @@ check_pid_and_port() } STUNNEL_CONF="$WSREP_SST_OPT_DATA/stunnel.conf" -rm -f "$STUNNEL_CONF" STUNNEL_PID="$WSREP_SST_OPT_DATA/stunnel.pid" -rm -f "$STUNNEL_PID" MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" -rm -rf "$MAGIC_FILE" BINLOG_TAR_FILE="$WSREP_SST_OPT_DATA/wsrep_sst_binlog.tar" BINLOG_N_FILES=1 -rm -f "$BINLOG_TAR_FILE" || : get_binlog @@ -154,13 +149,13 @@ OLD_PWD="$(pwd)" WSREP_LOG_DIR="$INNODB_LOG_GROUP_HOME" +cd "$WSREP_SST_OPT_DATA" if [ -n "$WSREP_LOG_DIR" ]; then # handle both relative and absolute paths - WSREP_LOG_DIR=$(cd "$WSREP_SST_OPT_DATA"; mkdir -p "$WSREP_LOG_DIR"; cd "$WSREP_LOG_DIR"; pwd -P) -else - # default to datadir - WSREP_LOG_DIR=$(cd "$WSREP_SST_OPT_DATA"; pwd -P) + [ ! -d "$WSREP_LOG_DIR" ] && mkdir -p "$WSREP_LOG_DIR" + cd "$WSREP_LOG_DIR" fi +WSREP_LOG_DIR=$(pwd -P) cd "$OLD_PWD" @@ -170,13 +165,13 @@ if [ -z "$INNODB_DATA_HOME_DIR" ]; then INNODB_DATA_HOME_DIR=$(parse_cnf '--mysqld' 'innodb-data-home-dir') fi +cd "$WSREP_SST_OPT_DATA" if [ -n "$INNODB_DATA_HOME_DIR" ]; then # handle both relative and absolute paths - INNODB_DATA_HOME_DIR=$(cd "$WSREP_SST_OPT_DATA"; mkdir -p "$INNODB_DATA_HOME_DIR"; cd "$INNODB_DATA_HOME_DIR"; pwd -P) -else - # default to datadir - INNODB_DATA_HOME_DIR=$(cd "$WSREP_SST_OPT_DATA"; pwd -P) + [ ! -d "$INNODB_DATA_HOME_DIR" ] && mkdir -p "$INNODB_DATA_HOME_DIR" + cd "$INNODB_DATA_HOME_DIR" fi +INNODB_DATA_HOME_DIR=$(pwd -P) cd "$OLD_PWD" @@ -185,13 +180,13 @@ if [ -z "$INNODB_UNDO_DIR" ]; then INNODB_UNDO_DIR=$(parse_cnf '--mysqld' 'innodb-undo-directory') fi +cd "$WSREP_SST_OPT_DATA" if [ -n "$INNODB_UNDO_DIR" ]; then # handle both relative and absolute paths - INNODB_UNDO_DIR=$(cd "$WSREP_SST_OPT_DATA"; mkdir -p "$INNODB_UNDO_DIR"; cd "$INNODB_UNDO_DIR"; pwd -P) -else - # default to datadir - INNODB_UNDO_DIR=$(cd "$WSREP_SST_OPT_DATA"; pwd -P) + [ ! -d "$INNODB_UNDO_DIR" ] && mkdir -p "$INNODB_UNDO_DIR" + cd "$INNODB_UNDO_DIR" fi +INNODB_UNDO_DIR=$(pwd -P) cd "$OLD_PWD" @@ -239,7 +234,7 @@ if [ -z "$SSLMODE" ]; then # Implicit verification if CA is set and the SSL mode # is not specified by user: if [ -n "$SSTCA" ]; then - if [ -x "$(command -v stunnel)" ]; then + if [ -n "$(command -v stunnel)" ]; then SSLMODE='VERIFY_CA' fi # Require SSL by default if SSL key and cert are present: @@ -260,28 +255,36 @@ then case "$SSLMODE" in 'VERIFY_IDENTITY') VERIFY_OPT='verifyPeer = yes' + CHECK_OPT="" ;; 'VERIFY_CA') VERIFY_OPT='verifyChain = yes' + if is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then + CHECK_OPT='checkHost = localhost' + else + CHECK_OPT='checkHost = $WSREP_SST_OPT_HOST_UNESCAPED' + fi ;; *) wsrep_log_error "Unrecognized ssl-mode option: '$SSLMODE'" exit 22 # EINVAL esac - if [ -z "$CAFILE_OPT" ] - then - wsrep_log_error "Can't have ssl-mode=$SSLMODE without CA file" + if [ -z "$CAFILE_OPT" ]; then + wsrep_log_error "Can't have ssl-mode='$SSLMODE' without CA file" exit 22 # EINVAL fi else VERIFY_OPT="" + CHECK_OPT="" fi STUNNEL="" -if [ -n "$SSLMODE" -a "$SSLMODE" != 'DISABLED' ] && wsrep_check_programs stunnel -then - wsrep_log_info "Using stunnel for SSL encryption: CAfile: '$SSTCA', SSLMODE: '$SSLMODE'" - STUNNEL="stunnel $STUNNEL_CONF" +if [ -n "$SSLMODE" -a "$SSLMODE" != 'DISABLED' ]; then + STUNNEL_BIN="$(command -v stunnel)" + if [ -n "$STUNNEL_BIN" ]; then + wsrep_log_info "Using stunnel for SSL encryption: CAfile: '$SSTCA', ssl-mode='$SSLMODE'" + STUNNEL="$STUNNEL_BIN $STUNNEL_CONF" + fi fi readonly SECRET_TAG="secret" @@ -289,7 +292,13 @@ readonly SECRET_TAG="secret" if [ "$WSREP_SST_OPT_ROLE" = 'donor' ] then -cat << EOF > "$STUNNEL_CONF" + [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" + [ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE" + + if [ -n "$STUNNEL" ] + then + [ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID" + cat << EOF > "$STUNNEL_CONF" key = $SSTKEY cert = $SSTCERT ${CAFILE_OPT} @@ -300,7 +309,9 @@ client = yes connect = $WSREP_SST_OPT_HOST_UNESCAPED:$WSREP_SST_OPT_PORT TIMEOUTclose = 0 ${VERIFY_OPT} +${CHECK_OPT} EOF + fi if [ $WSREP_SST_OPT_BYPASS -eq 0 ] then @@ -366,7 +377,7 @@ EOF # first, the normal directories, so that we can detect incompatible protocol RC=0 - eval rsync ${STUNNEL:+--rsh=\"$STUNNEL\"} \ + eval rsync ${STUNNEL:+"'--rsh=$STUNNEL'"} \ --owner --group --perms --links --specials \ --ignore-times --inplace --dirs --delete --quiet \ $WHOLE_FILE_OPT $FILTER "'$WSREP_SST_OPT_DATA/'" \ @@ -449,7 +460,7 @@ EOF fi - echo "continue" # now server can resume updating data + echo 'continue' # now server can resume updating data echo "$STATE" > "$MAGIC_FILE" @@ -487,7 +498,10 @@ then wsrep_log_error "rsync daemon already running." exit 114 # EALREADY fi - rm -rf "$RSYNC_PID" + + [ -f "$RSYNC_PID" ] && rm -f "$RSYNC_PID" + [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" + [ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE" ADDR="$WSREP_SST_OPT_ADDR" RSYNC_PORT="$WSREP_SST_OPT_PORT" @@ -541,20 +555,40 @@ EOF rsync --daemon --no-detach --port "$RSYNC_PORT" --config "$RSYNC_CONF" $RSYNC_EXTRA_ARGS & RSYNC_REAL_PID=$! else - cat << EOF > "$STUNNEL_CONF" + [ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID" + # Let's check if the path to the config file contains a space? + if [ "${RSYNC_CONF#* }" = "$RSYNC_CONF" ]; then + cat << EOF > "$STUNNEL_CONF" key = $SSTKEY cert = $SSTCERT ${CAFILE_OPT} foreground = yes pid = $STUNNEL_PID debug = warning -debug = 6 client = no [rsync] accept = $STUNNEL_ACCEPT exec = $(command -v rsync) execargs = rsync --server --daemon --config=$RSYNC_CONF . EOF + else + # The path contains a space, so we will run it via + # shell with "eval" command: + export RSYNC_CMD="eval $(command -v rsync) --server --daemon --config='$RSYNC_CONF' ." + cat << EOF > "$STUNNEL_CONF" +key = $SSTKEY +cert = $SSTCERT +${CAFILE_OPT} +foreground = yes +pid = $STUNNEL_PID +debug = warning +client = no +[rsync] +accept = $STUNNEL_ACCEPT +exec = $SHELL +execargs = $SHELL -c \$RSYNC_CMD +EOF + fi stunnel "$STUNNEL_CONF" & RSYNC_REAL_PID=$! RSYNC_PID="$STUNNEL_PID" @@ -655,6 +689,6 @@ else exit 22 # EINVAL fi -rm -f "$BINLOG_TAR_FILE" || : +[ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE" exit 0 |