diff options
author | Julius Goryavsky <julius.goryavsky@mariadb.com> | 2021-04-28 01:39:31 +0200 |
---|---|---|
committer | Julius Goryavsky <julius.goryavsky@mariadb.com> | 2021-05-04 01:06:42 +0200 |
commit | 1ae7673aae7f82c4e659b1337177f2696c8e45ba (patch) | |
tree | 767ae7305afb9bb26ba32cedb5fea18231059b2c /scripts/wsrep_sst_common.sh | |
parent | e0324bf300a57e84e5fdeca995c91b9efa3dc62c (diff) | |
download | mariadb-git-1ae7673aae7f82c4e659b1337177f2696c8e45ba.tar.gz |
MDEV-24962: Galera SST innobackupex-move ignores Environment settings
After switching to the new mariabackup interface (instead of
the outdated innobackupex interface, which is supported for
compatibility), we need to explicitly pass a path to the datadir
directory as a parameter, since in the new interface the value
of this option is not automatically set in such a way that it
always matches the SST/IST logic. This commit adds passing this
option as an explicit parameter to mariabackup. This commit also
removed unnecessary options that are not used and not supported
by mariabackup.
Also, numerous flaws in the common wsrep_sst_common script have
been fixed:
1) There are many bash-specific constructs in the script that
may not be supported by other interpreters, which can lead
to the most unexpected errors during SST, because failures
in the interpretation of bash-specific constructs lead to
incorrect parsing of arguments;
2) There is parse_cnf() function which is often called by other
scripts for the "mysqld" or "--mysqld" group, but it does not
take into account the default group suffix, which leads to
reading values only from the default group, which then leads
to errors due to reading the default values instead of the
values for a specific group;
3) Some options such as --user, --innodb-data-home-dir or --datadir
are not removed from the --mysqld-args list, although they are
processed inside scripts (and passing of these options funther
may cause problems for mariabackup);
4) If an argument that the script understands is present in
the --mysqld-args list twice, then this causes SST to fail,
instead of reading the most recent value;
5) The "--host" parameter is technically still supported among
the arguments of the SST scripts, but in reality scripts do not
work with it as expected, especially if it has an IPv6 address;
6) If the port number is absent in the --address parameter value,
but the port number is explicitly passed through the --port
argument, then the scripts for mariabackup and xtrabackup-v2
fail;
7) If a new address interface is used (with the --address parameter),
then automatic default port substitution is not performed, although
it is supported for the legacy --host/--port interface.
8) If there are spaces in the parameter values after --mysqld_args,
then their further transfer does not occur correctly, which
causes mariabackup to fail during SST - the space splits
the argument in such a way that it breaks the parsing of the
following parameters;
9) If most of the parameters that are names or paths to the files
or directories contain spaces, then SST scripts fail in an
unpredictable way due to incorrect variable substitutions;
10) If the --log-bin option is passed among the arguments of myqlds
(--mysqld-args) without a parameter, and the --binlog option
is not specified, then the script cannot substitute the default
name for binlog and cannot construct binlog name using the
--log-basename argument (which is against server specifications);
11) Tail slashes are not removed from the directory names, which,
upon further substitution, leads to the appearance of a double
slash in the file paths;
12) The explicit --binlog parameter (which is now always transmitted
from the server side) and the "hidden" --log-bin parameter in the
list of arguments after --mysqld-args are perceived as two different
parameters in different parts of the scripts, and if they are do not
match for some reason, this will lead to failures during SST;
Also, all new changes from the 10.6 branch have been migrated here,
including the latest pull requests for authentication (only the part
that concerns SST scripts).
It also fixes dozens of other bugs in all SST scripts.
Diffstat (limited to 'scripts/wsrep_sst_common.sh')
-rw-r--r-- | scripts/wsrep_sst_common.sh | 623 |
1 files changed, 496 insertions, 127 deletions
diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 51f811bda78..9e6807e20a3 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -1,4 +1,5 @@ # Copyright (C) 2012-2015 Codership Oy +# Copyright (C) 2017-2021 MariaDB # # 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 @@ -21,24 +22,32 @@ set -u WSREP_SST_OPT_BYPASS=0 WSREP_SST_OPT_BINLOG="" WSREP_SST_OPT_BINLOG_INDEX="" +WSREP_SST_OPT_LOG_BASENAME="" WSREP_SST_OPT_DATA="" -WSREP_SST_OPT_AUTH=${WSREP_SST_OPT_AUTH:-} -WSREP_SST_OPT_USER=${WSREP_SST_OPT_USER:-} -WSREP_SST_OPT_PSWD=${WSREP_SST_OPT_PSWD:-} +WSREP_SST_OPT_AUTH="${WSREP_SST_OPT_AUTH:-}" +WSREP_SST_OPT_USER="${WSREP_SST_OPT_USER:-}" +WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_PSWD:-}" +WSREP_SST_OPT_REMOTE_AUTH="${WSREP_SST_OPT_REMOTE_AUTH:-}" WSREP_SST_OPT_DEFAULT="" WSREP_SST_OPT_EXTRA_DEFAULT="" WSREP_SST_OPT_SUFFIX_DEFAULT="" WSREP_SST_OPT_SUFFIX_VALUE="" WSREP_SST_OPT_MYSQLD="" -INNODB_DATA_HOME_DIR_ARG="" -INNODB_LOG_GROUP_HOME_ARG="" -INNODB_UNDO_DIR_ARG="" -LOG_BIN_ARG="" +WSREP_SST_OPT_PORT="" +WSREP_SST_OPT_ADDR="" +WSREP_SST_OPT_ADDR_PORT="" +WSREP_SST_OPT_HOST="" +WSREP_SST_OPT_HOST_UNESCAPED="" +WSREP_SST_OPT_HOST_ESCAPED="" +INNODB_DATA_HOME_DIR="${INNODB_DATA_HOME_DIR:-}" +INNODB_LOG_GROUP_HOME="${INNODB_LOG_GROUP_HOME:-}" +INNODB_UNDO_DIR="${INNODB_UNDO_DIR:-}" +INNOEXTRA="" while [ $# -gt 0 ]; do case "$1" in '--address') - readonly WSREP_SST_OPT_ADDR="$2" + WSREP_SST_OPT_ADDR="$2" # # Break address string into host:port/path parts # @@ -46,60 +55,61 @@ case "$1" in \[*) # IPv6 # Remove the starting and ending square brackets, if present: - addr_no_bracket=${WSREP_SST_OPT_ADDR#\[} - readonly WSREP_SST_OPT_HOST_UNESCAPED=${addr_no_bracket%%\]*} - # Square brackets are needed in most cases: - readonly WSREP_SST_OPT_HOST="[${WSREP_SST_OPT_HOST_UNESCAPED}]" + addr_no_bracket="${WSREP_SST_OPT_ADDR#\[}" # Some utilities and subsequent code require an address # without square brackets: + readonly WSREP_SST_OPT_HOST_UNESCAPED="${addr_no_bracket%%\]*}" + # Square brackets are needed in most cases: + readonly WSREP_SST_OPT_HOST="[${WSREP_SST_OPT_HOST_UNESCAPED}]" readonly WSREP_SST_OPT_HOST_ESCAPED="\\[${WSREP_SST_OPT_HOST_UNESCAPED}\\]" + # Mark this address as IPv6: readonly WSREP_SST_OPT_HOST_IPv6=1 ;; *) - readonly WSREP_SST_OPT_HOST=${WSREP_SST_OPT_ADDR%%[:/]*} - readonly WSREP_SST_OPT_HOST_UNESCAPED=$WSREP_SST_OPT_HOST - readonly WSREP_SST_OPT_HOST_ESCAPED=$WSREP_SST_OPT_HOST + readonly WSREP_SST_OPT_HOST="${WSREP_SST_OPT_ADDR%%[:/]*}" + readonly WSREP_SST_OPT_HOST_UNESCAPED="$WSREP_SST_OPT_HOST" + readonly WSREP_SST_OPT_HOST_ESCAPED="$WSREP_SST_OPT_HOST" readonly WSREP_SST_OPT_HOST_IPv6=0 ;; esac # Let's remove the leading part that contains the host address: - remain=${WSREP_SST_OPT_ADDR#${WSREP_SST_OPT_HOST_ESCAPED}} + remain="${WSREP_SST_OPT_ADDR#$WSREP_SST_OPT_HOST_ESCAPED}" # Let's remove the ":" character that separates the port number # from the hostname: - remain=${remain#:} + remain="${remain#:}" # Extract the port number from the address - all characters # up to "/" (if present): - readonly WSREP_SST_OPT_ADDR_PORT=${remain%%/*} + WSREP_SST_OPT_ADDR_PORT="${remain%%/*}" # If the "/" character is present, then the path is not empty: if [ "${remain#*/}" != "${remain}" ]; then # This operation removes everything up to the "/" character, # effectively removing the port number from the string: - readonly WSREP_SST_OPT_PATH=${remain#*/} + readonly WSREP_SST_OPT_PATH="${remain#*/}" else readonly WSREP_SST_OPT_PATH="" fi # The rest of the string is the same as the path (for now): - remain=${WSREP_SST_OPT_PATH} + remain="${WSREP_SST_OPT_PATH}" # If there is one more "/" in the string, then everything before # it will be the module name, otherwise the module name is empty: if [ "${remain%%/*}" != "${remain}" ]; then # This operation removes the tail after the very first # occurrence of the "/" character (inclusively): - readonly WSREP_SST_OPT_MODULE=${remain%%/*} + readonly WSREP_SST_OPT_MODULE="${remain%%/*}" else readonly WSREP_SST_OPT_MODULE="" fi # Remove the module name part from the string, which ends with "/": - remain=${WSREP_SST_OPT_PATH#*/} + remain="${WSREP_SST_OPT_PATH#*/}" # If the rest of the string does not match the original, then there # was something else besides the module name: if [ "$remain" != "${WSREP_SST_OPT_PATH}" ]; then # Extract the part that matches the LSN by removing all # characters starting from the very first "/": - readonly WSREP_SST_OPT_LSN=${remain%%/*} + readonly WSREP_SST_OPT_LSN="${remain%%/*}" # Exctract everything after the first occurrence of # the "/" character in the string: - remain=${remain#*/} + remain="${remain#*/}" # If the remainder does not match the original string, # then there is something else (the version number in # our case): @@ -107,7 +117,7 @@ case "$1" in # Let's extract the version number by removing the tail # after the very first occurence of the "/" character # (inclusively): - readonly WSREP_SST_OPT_SST_VER=${remain%%/*} + readonly WSREP_SST_OPT_SST_VER="${remain%%/*}" else readonly WSREP_SST_OPT_SST_VER="" fi @@ -121,23 +131,23 @@ case "$1" in WSREP_SST_OPT_BYPASS=1 ;; '--datadir') - readonly WSREP_SST_OPT_DATA="$2" + # Let's remove the trailing slash: + readonly WSREP_SST_OPT_DATA="${2%/}" shift ;; '--innodb-data-home-dir') - readonly INNODB_DATA_HOME_DIR_ARG="$2" + # Let's remove the trailing slash: + readonly INNODB_DATA_HOME_DIR="${2%/}" shift ;; '--innodb-log-group-home-dir') - readonly INNODB_LOG_GROUP_HOME_ARG="$2" + # Let's remove the trailing slash: + readonly INNODB_LOG_GROUP_HOME="${2%/}" shift ;; '--innodb-undo-directory') - readonly INNODB_UNDO_DIR_ARG="$2" - shift - ;; - '--log-bin') - readonly LOG_BIN_ARG="$2" + # Let's remove the trailing slash: + readonly INNODB_UNDO_DIR="${2%/}" shift ;; '--defaults-file') @@ -154,7 +164,28 @@ case "$1" in shift ;; '--host') - readonly WSREP_SST_OPT_HOST="$2" + case "$2" in + \[*) + # IPv6 + # Remove the starting and ending square brackets, if present: + addr_no_bracket="${2#\[}" + # Some utilities and subsequent code require an address + # without square brackets: + readonly WSREP_SST_OPT_HOST_UNESCAPED="${addr_no_bracket%%\]*}" + # Square brackets are needed in most cases: + readonly WSREP_SST_OPT_HOST="[${WSREP_SST_OPT_HOST_UNESCAPED}]" + readonly WSREP_SST_OPT_HOST_ESCAPED="\\[${WSREP_SST_OPT_HOST_UNESCAPED}\\]" + # Mark this address as IPv6: + readonly WSREP_SST_OPT_HOST_IPv6=1 + ;; + *) + readonly WSREP_SST_OPT_HOST="$2" + readonly WSREP_SST_OPT_HOST_UNESCAPED="$2" + readonly WSREP_SST_OPT_HOST_ESCAPED="$2" + readonly WSREP_SST_OPT_HOST_IPv6=0 + ;; + esac + WSREP_SST_OPT_ADDR="$WSREP_SST_OPT_HOST" shift ;; '--local-port') @@ -189,12 +220,16 @@ case "$1" in readonly WSREP_SST_OPT_GTID="$2" shift ;; - '--binlog') - WSREP_SST_OPT_BINLOG="$2" + '--binlog'|'--log-bin') + readonly WSREP_SST_OPT_BINLOG="$2" shift ;; - '--binlog-index') - WSREP_SST_OPT_BINLOG_INDEX="$2" + '--binlog-index'|'--log-bin-index') + readonly WSREP_SST_OPT_BINLOG_INDEX="$2" + shift + ;; + '--log-basename') + readonly WSREP_SST_OPT_LOG_BASENAME="$2" shift ;; '--gtid-domain-id') @@ -205,45 +240,114 @@ case "$1" in original_cmd="" shift while [ $# -gt 0 ]; do - option=${1%%=*} - if [[ "$option" != "--defaults-file" && \ - "$option" != "--defaults-extra-file" && \ - "$option" != "--defaults-group-suffix" && \ - "$option" != "--port" && \ - "$option" != "--socket" ]]; then - value=${1#*=} - if [ "$value" == "$1" ]; then - value="" - fi - case "$option" in - '--innodb-data-home-dir') - if [ -z "$INNODB_DATA_HOME_DIR_ARG" ]; then - readonly INNODB_DATA_HOME_DIR_ARG="$value" - fi - ;; - '--innodb-log-group-home-dir') - if [ -z "$INNODB_LOG_GROUP_HOME_ARG" ]; then - readonly INNODB_LOG_GROUP_HOME_ARG="$value" - fi - ;; - '--innodb-undo-directory') - if [ -z "$INNODB_UNDO_DIR_ARG" ]; then - readonly INNODB_UNDO_DIR_ARG="$value" - fi - ;; - '--log-bin') - if [ -z "$LOG_BIN_ARG" ]; then - readonly LOG_BIN_ARG="$value" - fi - ;; - esac - if [ -z "$original_cmd" ]; then - original_cmd="$1" - else - original_cmd="$original_cmd $1" - fi + # check if the argument is the short option + # (starting with "-" instead of "--"): + if [ "${1#--}" = "$1" -a "${1#-}" != "$1" ]; then + option="${1#-}" + value="" + # check that the option value follows the name, + # without a space: + if [ ${#option} -gt 1 ]; then + # let's separate the first character as the option name, + # and the subsequent characters consider its value: + value="${1#-?}" + option="${1%$value}" + # check that the option name consists of one letter + # and there are the following arguments: + elif [ ${#option} -eq 1 -a $# -gt 1 ]; then + # if the next argument does not start with a "-" character, + # then this is the value of the current option: + if [ "${2#-}" = "$2" ]; then + value="$2" + shift + fi + fi + shift + if [ "$option" = 'h' ]; then + if [ -z "$WSREP_SST_OPT_DATA" ]; then + MYSQLD_OPT_DATADIR="${value%/}" + fi + elif [ "$option" != 'u' -a \ + "$option" != 'P' ]; then + if [ -z "$original_cmd" ]; then + original_cmd="'-$option$value'" + else + original_cmd="$original_cmd '-$option$value'" + fi + fi + continue; fi - shift + option="${1%%=*}" + if [ "$option" != '--defaults-file' -a \ + "$option" != '--defaults-extra-file' -a \ + "$option" != '--defaults-group-suffix' -a \ + "$option" != '--user' -a \ + "$option" != '--port' -a \ + "$option" != '--socket' ]; then + value="${1#*=}" + if [ "$value" = "$1" ]; then + value="" + fi + # Let's fill in the variables containing important paths + # that might not have been passed through explicit parameters + # (+ removing the trailing slash in these paths). Many of these + # options are processed internally within scripts or passed + # explicitly to other programs, so we need to remove them + # from mysqld's argument list: + skip_mysqld_arg=0 + case "$option" in + '--innodb-data-home-dir') + if [ -z "$INNODB_DATA_HOME_DIR" ]; then + MYSQLD_OPT_INNODB_DATA_HOME_DIR="${value%/}" + fi + skip_mysqld_arg=1 + ;; + '--innodb-log-group-home-dir') + if [ -z "$INNODB_LOG_GROUP_HOME" ]; then + MYSQLD_OPT_INNODB_LOG_GROUP_HOME="${value%/}" + fi + skip_mysqld_arg=1 + ;; + '--innodb-undo-directory') + if [ -z "$INNODB_UNDO_DIR" ]; then + MYSQLD_OPT_INNODB_UNDO_DIR="${value%/}" + fi + skip_mysqld_arg=1 + ;; + '--log-bin') + if [ -z "$WSREP_SST_OPT_BINLOG" ]; then + MYSQLD_OPT_LOG_BIN="$value" + fi + skip_mysqld_arg=1 + ;; + '--log-bin-index') + if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + MYSQLD_OPT_LOG_BIN_INDEX="$value" + fi + skip_mysqld_arg=1 + ;; + '--log-basename') + if [ -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then + MYSQLD_OPT_LOG_BASENAME="$value" + fi + skip_mysqld_arg=1 + ;; + '--datadir') + if [ -z "$WSREP_SST_OPT_DATA" ]; then + MYSQLD_OPT_DATADIR="${value%/}" + fi + skip_mysqld_arg=1 + ;; + esac + if [ $skip_mysqld_arg -eq 0 ]; then + if [ -z "$original_cmd" ]; then + original_cmd="'$1'" + else + original_cmd="$original_cmd '$1'" + fi + fi + fi + shift done readonly WSREP_SST_OPT_MYSQLD="$original_cmd" break @@ -256,20 +360,169 @@ esac shift done readonly WSREP_SST_OPT_BYPASS -readonly WSREP_SST_OPT_BINLOG -readonly WSREP_SST_OPT_BINLOG_INDEX - -if [ -n "${WSREP_SST_OPT_ADDR_PORT:-}" ]; then - if [ -n "${WSREP_SST_OPT_PORT:-}" ]; then - if [ "$WSREP_SST_OPT_PORT" != "$WSREP_SST_OPT_ADDR_PORT" ]; then - echo "WSREP_SST: [ERROR] port in --port=$WSREP_SST_OPT_PORT differs from port in --address=$WSREP_SST_OPT_ADDR" >&2 - exit 2 + +# The same argument can be present on the command line several +# times, in this case we must take its last value: +if [ -n "${MYSQLD_OPT_INNODB_DATA_HOME_DIR:-}" -a \ + -z "$INNODB_DATA_HOME_DIR" ]; then + readonly INNODB_DATA_HOME_DIR="$MYSQLD_OPT_INNODB_DATA_HOME_DIR" +fi +if [ -n "${MYSQLD_OPT_INNODB_LOG_GROUP_HOME:-}" -a \ + -z "$INNODB_LOG_GROUP_HOME" ]; then + readonly INNODB_LOG_GROUP_HOME="$MYSQLD_OPT_INNODB_LOG_GROUP_HOME" +fi +if [ -n "${MYSQLD_OPT_INNODB_UNDO_DIR:-}" -a \ + -z "$INNODB_UNDO_DIR" ]; then + readonly INNODB_UNDO_DIR="$MYSQLD_OPT_INNODB_UNDO_DIR" +fi +if [ -n "${MYSQLD_OPT_LOG_BIN:-}" -a \ + -z "$WSREP_SST_OPT_BINLOG" ]; then + readonly WSREP_SST_OPT_BINLOG="$MYSQLD_OPT_LOG_BIN" +fi +if [ -n "${MYSQLD_OPT_LOG_BIN_INDEX:-}" -a \ + -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + readonly WSREP_SST_OPT_BINLOG_INDEX="$MYSQLD_OPT_LOG_BIN_INDEX" +fi +if [ -n "${MYSQLD_OPT_DATADIR:-}" -a \ + -z "$WSREP_SST_OPT_DATA" ]; then + readonly WSREP_SST_OPT_DATA="$MYSQLD_OPT_DATADIR" +fi +if [ -n "${MYSQLD_OPT_LOG_BASENAME:-}" -a \ + -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then + readonly WSREP_SST_OPT_LOG_BASENAME="$MYSQLD_OPT_LOG_BASENAME" +fi + +# If the --log-bin option is present without a value, then +# setting WSREP_SST_OPT_BINLOG by using other arguments: +if [ -z "$WSREP_SST_OPT_BINLOG" -a -n "${MYSQLD_OPT_LOG_BIN+x}" ]; then + if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then + # If the WSREP_SST_OPT_BINLOG variable is not set, but + # --log-basename is present among the arguments to mysqld, + # then set WSREP_SST_OPT_BINLOG equal to the base name with + # the "-bin" suffix: + readonly WSREP_SST_OPT_BINLOG="$WSREP_SST_OPT_LOG_BASENAME-bin" + else + # Take the default name: + readonly WSREP_SST_OPT_BINLOG='mysql-bin' fi - else - readonly WSREP_SST_OPT_PORT="$WSREP_SST_OPT_ADDR_PORT" - fi fi +# Reconstructing the command line arguments that control the innodb +# and binlog options: +if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then + INNOEXTRA="$INNOEXTRA --log-basename='$WSREP_SST_OPT_LOG_BASENAME'" +fi +if [ -n "$INNODB_DATA_HOME_DIR" ]; then + INNOEXTRA="$INNOEXTRA --innodb-data-home-dir='$INNODB_DATA_HOME_DIR'" +fi +if [ -n "$INNODB_LOG_GROUP_HOME" ]; then + INNOEXTRA="$INNOEXTRA --innodb-log-group-home-dir='$INNODB_LOG_GROUP_HOME'" +fi +if [ -n "$INNODB_UNDO_DIR" ]; then + INNOEXTRA="$INNOEXTRA --innodb-undo-directory='$INNODB_UNDO_DIR'" +fi +if [ -n "$WSREP_SST_OPT_BINLOG" ]; then + INNOEXTRA="$INNOEXTRA --log-bin='$WSREP_SST_OPT_BINLOG'" + if [ -n "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + INNOEXTRA="$INNOEXTRA --log-bin-index='$WSREP_SST_OPT_BINLOG_INDEX'" + fi +fi + +get_binlog() +{ + # if no command line argument and WSREP_SST_OPT_BINLOG is not set, + # try to get it from my.cnf: + if [ -z "$WSREP_SST_OPT_BINLOG" ]; then + WSREP_SST_OPT_BINLOG=$(parse_cnf '--mysqld' 'log-bin') + fi + # if no command line argument and WSREP_SST_OPT_BINLOG_INDEX is not set, + # try to get it from my.cnf: + if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + WSREP_SST_OPT_BINLOG_INDEX=$(parse_cnf '--mysqld' 'log-bin-index') + fi + # if no command line argument and WSREP_SST_OPT_LOG_BASENAME is not set, + # try to get it from my.cnf: + if [ -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then + WSREP_SST_OPT_LOG_BASENAME=$(parse_cnf '--mysqld' 'log-basename') + fi + if [ -z "$WSREP_SST_OPT_BINLOG" ]; then + # If the --log-bin option is specified without a parameter, + # then we need to build the name of the index file according + # to the rules described in the server documentation: + if [ -n "${MYSQLD_OPT_LOG_BIN+x}" -o \ + $(in_config '--mysqld' 'log-bin') -eq 1 ] + then + if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then + # If the WSREP_SST_OPT_BINLOG variable is not set, but + # --log-basename is present among the arguments of mysqld, + # then set WSREP_SST_OPT_BINLOG equal to the base name with + # the "-bin" suffix: + readonly WSREP_SST_OPT_BINLOG="$WSREP_SST_OPT_LOG_BASENAME-bin" + else + # If the --log-bin option is present without a value, then + # we take the default name: + readonly WSREP_SST_OPT_BINLOG='mysql-bin' + fi + fi + fi + if [ -n "$WSREP_SST_OPT_BINLOG" ]; then + # If the name of the index file is not specified, then we will build + # it according to the specifications for the server: + if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then + # If the WSREP_SST_OPT_BINLOG variable is not set, but + # --log-basename is present among the arguments of mysqld, + # then set WSREP_SST_OPT_BINLOG equal to the base name with + # the "-bin" suffix: + readonly WSREP_SST_OPT_BINLOG_INDEX="$WSREP_SST_OPT_LOG_BASENAME-bin.index" + else + # If the base name not specified, then we take + # the default name: + readonly WSREP_SST_OPT_BINLOG_INDEX='mysql-bin.index' + fi + fi + fi +} + +# Check the presence of the port value and, if necessary, transfer +# the port number from the address to the WSREP_SST_OPT_PORT variable +# or vice versa, and also, if necessary, substitute the missing port +# value into the address value: +if [ -n "$WSREP_SST_OPT_ADDR_PORT" ]; then + if [ -n "$WSREP_SST_OPT_PORT" ]; then + if [ "$WSREP_SST_OPT_PORT" != "$WSREP_SST_OPT_ADDR_PORT" ]; then + echo "WSREP_SST: [ERROR] port in --port=$WSREP_SST_OPT_PORT differs from port in --address=$WSREP_SST_OPT_ADDR" >&2 + exit 2 + fi + else + # If the address contains a port number, assign it to + # the corresponding variable: + readonly WSREP_SST_OPT_PORT="$WSREP_SST_OPT_ADDR_PORT" + fi +elif [ -n "$WSREP_SST_OPT_ADDR" ]; then + # If the port is missing, take the default port: + if [ -z "$WSREP_SST_OPT_PORT" ]; then + readonly WSREP_SST_OPT_PORT=4444 + fi + WSREP_SST_OPT_ADDR_PORT="$WSREP_SST_OPT_PORT" + # Let's remove the leading part that contains the host address: + remain="${WSREP_SST_OPT_ADDR#$WSREP_SST_OPT_HOST_ESCAPED}" + # Let's remove the ":" character that separates the port number + # from the hostname: + remain="${remain#:}" + # Let's remove all characters upto first "/" character that + # separates the hostname with port number from the path: + remain="${remain#/}" + # Let's construct a new value for the address with the port: + WSREP_SST_OPT_ADDR="$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT" + if [ -n "$remain" ]; then + WSREP_SST_OPT_ADDR="$WSREP_SST_OPT_ADDR/$remain" + fi +fi + +readonly WSREP_SST_OPT_ADDR +readonly WSREP_SST_OPT_ADDR_PORT + # try to use my_print_defaults, mysql and mysqldump that come with the sources # (for MTR suite) SCRIPTS_DIR="$(cd $(dirname "$0"); pwd -P)" @@ -279,13 +532,13 @@ CLIENT_DIR="$SCRIPTS_DIR/../client" if [ -x "$CLIENT_DIR/mysql" ]; then MYSQL_CLIENT="$CLIENT_DIR/mysql" else - MYSQL_CLIENT=$(which mysql) + MYSQL_CLIENT="$(command -v mysql)" fi if [ -x "$CLIENT_DIR/mysqldump" ]; then MYSQLDUMP="$CLIENT_DIR/mysqldump" else - MYSQLDUMP=$(which mysqldump) + MYSQLDUMP="$(command -v mysqldump)" fi if [ -x "$SCRIPTS_DIR/my_print_defaults" ]; then @@ -293,7 +546,7 @@ if [ -x "$SCRIPTS_DIR/my_print_defaults" ]; then elif [ -x "$EXTRA_DIR/my_print_defaults" ]; then MY_PRINT_DEFAULTS="$EXTRA_DIR/my_print_defaults" else - MY_PRINT_DEFAULTS=$(which my_print_defaults) + MY_PRINT_DEFAULTS="$(command -v my_print_defaults)" fi wsrep_defaults="$WSREP_SST_OPT_DEFAULT" @@ -307,29 +560,133 @@ fi readonly WSREP_SST_OPT_CONF="$wsrep_defaults$WSREP_SST_OPT_SUFFIX_DEFAULT" readonly MY_PRINT_DEFAULTS="$MY_PRINT_DEFAULTS $WSREP_SST_OPT_CONF" -wsrep_auth_not_set() +# +# User can specify mariabackup specific settings that will be used during sst +# process like encryption, etc. Parse such configuration option. +# +# 1st parameter: group (config file section like sst) or +# my_print_defaults argument (like --mysqld) +# 2nd parameter: var : name of the variable in the section, e.g. server-id +# 3rd parameter: default value for the parameter +# +parse_cnf() { - [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ] + local group="$1" + local var="$2" + local reval="" + + # normalize the variable names specified in cnf file (user can use _ or - for example log-bin or log_bin) + # then search for needed variable + # finally get the variable value (if variables has been specified multiple time use the last value only) + + if [ "$group" = '--mysqld' -o \ + "$group" = 'mysqld' ]; then + if [ -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then + reval=$($MY_PRINT_DEFAULTS "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk 'BEGIN {OFS=FS="="} {sub(/^--loose/,"-",$0); gsub(/_/,"-",$1); if ($1=="--'"$var"'") lastval=substr($0,length($1)+2)} END {print lastval}') + fi + fi + + if [ -z "$reval" ]; then + reval=$($MY_PRINT_DEFAULTS "$group" | awk 'BEGIN {OFS=FS="="} {sub(/^--loose/,"-",$0); gsub(/_/,"-",$1); if ($1=="--'"$var"'") lastval=substr($0,length($1)+2)} END {print lastval}') + fi + + # use default if we haven't found a value + if [ -z "$reval" ]; then + [ -n "${3:-}" ] && reval="$3" + fi + echo $reval } -# State Snapshot Transfer authentication password was displayed in the ps output. Bug fixed #1200727. -if $MY_PRINT_DEFAULTS sst | grep -q "wsrep_sst_auth"; then - if wsrep_auth_not_set; then - WSREP_SST_OPT_AUTH=$($MY_PRINT_DEFAULTS sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) +# +# This function simply checks for the presence of the parameter +# in the config file, but does not return its value. It returns "1" +# (true) even if the parameter is present in the configuration file +# without a value: +# +in_config() +{ + local group="$1" + local var="$2" + local found=0 + if [ "$group" = '--mysqld' -o \ + "$group" = 'mysqld' ]; then + if [ -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then + found=$($MY_PRINT_DEFAULTS "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk 'BEGIN {OFS=FS="="; found=0} {sub(/^--loose/,"-",$0); gsub(/_/,"-",$1); if ($1=="--'"$var"'") found=1} END {print found}') + fi + fi + if [ $found -eq 0 ]; then + found=$($MY_PRINT_DEFAULTS "$group" | awk 'BEGIN {OFS=FS="="; found=0} {sub(/^--loose/,"-",$0); gsub(/_/,"-",$1); if ($1=="--'"$var"'") found=1} END {print found}') fi + echo $found +} + +wsrep_auth_not_set() +{ + [ -z "$WSREP_SST_OPT_AUTH" ] +} + +# Get rid of incorrect values resulting from substitution +# in programs external to the script: +if [ "$WSREP_SST_OPT_USER" = '(null)' ]; then + WSREP_SST_OPT_USER="" +fi +if [ "$WSREP_SST_OPT_PSWD" = '(null)' ]; then + WSREP_SST_OPT_PSWD="" +fi +if [ "$WSREP_SST_OPT_AUTH" = '(null)' ]; then + WSREP_SST_OPT_AUTH="" +fi + +# Let's read the value of the authentication string from the +# configuration file so that it does not go to the command line +# and does not appear in the ps output: +if wsrep_auth_not_set; then + WSREP_SST_OPT_AUTH=$(parse_cnf 'sst' 'wsrep-sst-auth') fi -readonly WSREP_SST_OPT_AUTH -# Splitting AUTH into potential user:password pair +# Splitting WSREP_SST_OPT_AUTH as "user:password" pair: if ! wsrep_auth_not_set then - WSREP_SST_OPT_USER="${WSREP_SST_OPT_AUTH%%:*}" - WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_AUTH##*:}" + # Extract username as shortest prefix up to first ':' character: + WSREP_SST_OPT_AUTH_USER="${WSREP_SST_OPT_AUTH%%:*}" + if [ -z "$WSREP_SST_OPT_USER" ]; then + # if the username is not in the command line arguments, + # set the username and password using WSREP_SST_OPT_AUTH + # from the environment: + WSREP_SST_OPT_USER="$WSREP_SST_OPT_AUTH_USER" + WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_AUTH#*:}" + elif [ "$WSREP_SST_OPT_USER" = "$WSREP_SST_OPT_AUTH_USER" ]; then + # If the username in the command line arguments and in + # the environment variable are the same, set the password + # if it was not specified in the command line: + if [ -z "$WSREP_SST_OPT_PSWD" ]; then + WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_AUTH#*:}" + fi + else + # The username is passed through the command line and does + # not match the username in the environment variable - ignore + # the environment and rebuild the authentication parameters: + WSREP_SST_OPT_AUTH="$WSREP_SST_OPT_USER:$WSREP_SST_OPT_PSWD" + fi fi + readonly WSREP_SST_OPT_USER readonly WSREP_SST_OPT_PSWD +readonly WSREP_SST_OPT_AUTH + +if [ -n "$WSREP_SST_OPT_REMOTE_AUTH" ] +then + # Split auth string at the last ':' + readonly WSREP_SST_OPT_REMOTE_USER="${WSREP_SST_OPT_REMOTE_AUTH%%:*}" + readonly WSREP_SST_OPT_REMOTE_PSWD="${WSREP_SST_OPT_REMOTE_AUTH#*:}" +else + readonly WSREP_SST_OPT_REMOTE_USER= + readonly WSREP_SST_OPT_REMOTE_PSWD= +fi + +readonly WSREP_SST_OPT_REMOTE_AUTH -if [ -n "${WSREP_SST_OPT_DATA:-}" ] +if [ -n "$WSREP_SST_OPT_DATA" ] then SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress" else @@ -361,15 +718,14 @@ wsrep_log_info() wsrep_cleanup_progress_file() { - [ -n "${SST_PROGRESS_FILE:-}" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null || true + [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null || true } wsrep_check_program() { - local prog=$1 - - if ! which $prog >/dev/null - then + local prog="$1" + local cmd=$(command -v "$prog") + if [ ! -x "$cmd" ]; then echo "'$prog' not found in PATH" return 2 # no such file or directory fi @@ -388,29 +744,42 @@ wsrep_check_programs() return $ret } -# -# user can specify mariabackup specific settings that will be used during sst -# process like encryption, etc..... -# parse such configuration option. (group for xb settings is [sst] in my.cnf -# -# 1st param: group (config file section like sst) or my_print_defaults argument (like --mysqld) -# 2nd param: var : name of the variable in the section, e.g. server-id -# 3rd param: - : default value for the param -parse_cnf() +wsrep_check_datadir() { - local group=$1 - local var=$2 - local reval="" - - # normalize the variable names specified in cnf file (user can use _ or - for example log-bin or log_bin) - # then search for needed variable - # finally get the variable value (if variables has been specified multiple time use the last value only) + if [ -z "$WSREP_SST_OPT_DATA" ] + then + wsrep_log_error "The '--datadir' parameter must be passed to the SST script" + exit 2 + fi +} - reval=$($MY_PRINT_DEFAULTS "${group}" | awk -v var="${var}" 'BEGIN { OFS=FS="=" } { gsub(/_/,"-",$1); if ( $1=="--"var) lastval=substr($0,length($1)+2) } END { print lastval}') +get_openssl() +{ + # If the OPENSSL_BINARY variable is already defined, just return: + if [ -n "${OPENSSL_BINARY+x}" ]; then + return + fi + # Let's look for openssl: + OPENSSL_BINARY="$(command -v openssl)" + if [ ! -x "$OPENSSL_BINARY" ]; then + OPENSSL_BINARY='/usr/bin/openssl' + if [ ! -x "$OPENSSL_BINARY" ]; then + OPENSSL_BINARY="" + fi + fi + readonly OPENSSL_BINARY +} - # use default if we haven't found a value - if [ -z "$reval" ]; then - [ -n "$3" ] && reval=$3 +# Generate a string equivalent to 16 random bytes +wsrep_gen_secret() +{ + get_openssl + if [ -n "$OPENSSL_BINARY" ] + then + echo $("$OPENSSL_BINARY" rand -hex 16) + else + printf "%04x%04x%04x%04x%04x%04x%04x%04x" \ + $RANDOM $RANDOM $RANDOM $RANDOM \ + $RANDOM $RANDOM $RANDOM $RANDOM fi - echo $reval } |