Commit 83664e21 authored by Alexey Yurchenko's avatar Alexey Yurchenko Committed by Jan Lindström

MW-366 Improved support for IPv6 networks - made mysqld and SST scripts to...

MW-366 Improved support for IPv6 networks - made mysqld and SST scripts to recognize []-escaped IPv6 addresses - pulled in latest Percona and MariaDB updates to SST scripts - instruct netcat and socat in wsrep_sst_xtrabackup-v2 to listen on IPv6 socket via sockopt parameter in the [sst] section of my.cnf

In summary, wsrep_node_address and wsrep_sst_receive_address can now
be set to IPv6 addresses escaped by []. Rsync SST works out ouf the
box thanks to rsync daemon listening on both IPv4 and IPv6 sockets by
default. For xtrabackup SST onver IPv6 one needs to set sockopt in
the [sst] section of joiner's configuration file to ",pf=ip6" if
using socat as a streamer or to "-6" if using netcat.
parent 5108dede
...@@ -30,6 +30,22 @@ while [ $# -gt 0 ]; do ...@@ -30,6 +30,22 @@ while [ $# -gt 0 ]; do
case "$1" in case "$1" in
'--address') '--address')
readonly WSREP_SST_OPT_ADDR="$2" readonly WSREP_SST_OPT_ADDR="$2"
#
# Break address string into host:port/path parts
#
if echo $WSREP_SST_OPT_ADDR | grep -qe '^\[.*\]'
then
# IPv6 notation
readonly WSREP_SST_OPT_HOST=${WSREP_SST_OPT_ADDR/\]*/\]}
readonly WSREP_SST_OPT_HOST_UNESCAPED=$(echo $WSREP_SST_OPT_HOST | \
cut -d '[' -f 2 | cut -d ']' -f 1)
else
# "traditional" notation
readonly WSREP_SST_OPT_HOST=${WSREP_SST_OPT_ADDR%%[:/]*}
fi
readonly WSREP_SST_OPT_PORT=$(echo $WSREP_SST_OPT_ADDR | \
cut -d ']' -f 2 | cut -s -d ':' -f 2 | cut -d '/' -f 1)
readonly WSREP_SST_OPT_PATH=${WSREP_SST_OPT_ADDR#*/}
shift shift
;; ;;
'--bypass') '--bypass')
...@@ -169,6 +185,11 @@ wsrep_log_error() ...@@ -169,6 +185,11 @@ wsrep_log_error()
wsrep_log "[ERROR] $*" wsrep_log "[ERROR] $*"
} }
wsrep_log_warning()
{
wsrep_log "[WARNING] $*"
}
wsrep_log_info() wsrep_log_info()
{ {
wsrep_log "[INFO] $*" wsrep_log "[INFO] $*"
...@@ -202,3 +223,39 @@ wsrep_check_programs() ...@@ -202,3 +223,39 @@ wsrep_check_programs()
return $ret return $ret
} }
#
# user can specify xtrabackup 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 : name of the config file section, e.g. mysqld
# 2nd param: var : name of the variable in the section, e.g. server-id
# 3rd param: - : default value for the param
parse_cnf()
{
local group=$1
local var=$2
local reval=""
# print the default settings for given group using my_print_default.
# normalize the variable names specified in cnf file (user can use _ or - for example log-bin or log_bin)
# then grep for needed variable
# finally get the variable value (if variables has been specified multiple time use the last value only)
# look in group+suffix
if [[ -n $WSREP_SST_OPT_CONF_SUFFIX ]]; then
reval=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF "${group}${WSREP_SST_OPT_CONF_SUFFIX}" | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2- | tail -1)
fi
# look in group
if [[ -z $reval ]]; then
reval=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2- | tail -1)
fi
# use default if we haven't found a value
if [[ -z $reval ]]; then
[[ -n $3 ]] && reval=$3
fi
echo $reval
}
...@@ -30,6 +30,7 @@ local_ip() ...@@ -30,6 +30,7 @@ local_ip()
{ {
[ "$1" = "127.0.0.1" ] && return 0 [ "$1" = "127.0.0.1" ] && return 0
[ "$1" = "localhost" ] && return 0 [ "$1" = "localhost" ] && return 0
[ "$1" = "[::1]" ] && return 0
[ "$1" = "$(hostname -s)" ] && return 0 [ "$1" = "$(hostname -s)" ] && return 0
[ "$1" = "$(hostname -f)" ] && return 0 [ "$1" = "$(hostname -f)" ] && return 0
[ "$1" = "$(hostname -d)" ] && return 0 [ "$1" = "$(hostname -d)" ] && return 0
...@@ -105,8 +106,9 @@ GTID_BINLOG_STATE=$(echo "SHOW GLOBAL VARIABLES LIKE 'gtid_binlog_state'" |\ ...@@ -105,8 +106,9 @@ GTID_BINLOG_STATE=$(echo "SHOW GLOBAL VARIABLES LIKE 'gtid_binlog_state'" |\
$MYSQL_CLIENT $AUTH -S$WSREP_SST_OPT_SOCKET --disable-reconnect --connect_timeout=10 |\ $MYSQL_CLIENT $AUTH -S$WSREP_SST_OPT_SOCKET --disable-reconnect --connect_timeout=10 |\
tail -1 | awk -F ' ' '{ print $2 }') tail -1 | awk -F ' ' '{ print $2 }')
MYSQL="$MYSQL_CLIENT $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\ MYSQL="$MYSQL_CLIENT --defaults-extra-file=$WSREP_SST_OPT_CONF "\
"--disable-reconnect --connect_timeout=10" "$AUTH -h${WSREP_SST_OPT_HOST_UNESCAPED:-$WSREP_SST_OPT_HOST} "\
"-P$WSREP_SST_OPT_PORT --disable-reconnect --connect_timeout=10"
# Check if binary logging is enabled on the joiner node. # Check if binary logging is enabled on the joiner node.
# Note: SELECT cannot be used at this point. # Note: SELECT cannot be used at this point.
......
...@@ -67,6 +67,11 @@ check_pid_and_port() ...@@ -67,6 +67,11 @@ check_pid_and_port()
exit 2 # ENOENT exit 2 # ENOENT
fi fi
if ! which lsof > /dev/null; then
wsrep_log_error "lsof tool not found in PATH! Make sure you have it installed."
exit 2 # ENOENT
fi
local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \ local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \
grep "(LISTEN)") grep "(LISTEN)")
local is_rsync=$(echo $port_info | \ local is_rsync=$(echo $port_info | \
...@@ -97,10 +102,19 @@ fi ...@@ -97,10 +102,19 @@ fi
WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} WSREP_LOG_DIR=${WSREP_LOG_DIR:-""}
# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf # if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf
if [ -z "$WSREP_LOG_DIR" ]; then if [ -z "$WSREP_LOG_DIR" ]; then
WSREP_LOG_DIR=$($MY_PRINT_DEFAULTS --defaults-file \ WSREP_LOG_DIR=$(parse_cnf mariadb-10.0 innodb_log_group_home_dir "")
"$WSREP_SST_OPT_CONF" mysqld server mysqld-10.0 mariadb mariadb-10.0 \ fi
| grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \ if [ -z "$WSREP_LOG_DIR" ]; then
| cut -b 29- ) WSREP_LOG_DIR=$(parse_cnf mysqld innodb_log_group_home_dir "")
fi
if [ -z "$WSREP_LOG_DIR" ]; then
WSREP_LOG_DIR=$(parse_cnf server innodb_log_group_home_dir "")
fi
if [ -z "$WSREP_LOG_DIR" ]; then
WSREP_LOG_DIR=$(parse_cnf mariadb innodb_log_group_home_dir "")
fi
if [ -z "$WSREP_LOG_DIR" ]; then
WSREP_LOG_DIR=$(parse_cnf mysqld-10.0 innodb_log_group_home_dir "")
fi fi
if [ -n "$WSREP_LOG_DIR" ]; then if [ -n "$WSREP_LOG_DIR" ]; then
...@@ -208,8 +222,8 @@ then ...@@ -208,8 +222,8 @@ then
[ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo) [ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo)
[ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu) [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu)
find . -maxdepth 1 -mindepth 1 -type d -not -name "lost+found" -print0 | \ find . -maxdepth 1 -mindepth 1 -type d -not -name "lost+found" \
xargs -I{} -0 -P $count \ -print0 | xargs -I{} -0 -P $count \
rsync --owner --group --perms --links --specials \ rsync --owner --group --perms --links --specials \
--ignore-times --inplace --recursive --delete --quiet \ --ignore-times --inplace --recursive --delete --quiet \
$WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \
...@@ -252,25 +266,24 @@ then ...@@ -252,25 +266,24 @@ then
fi fi
rm -rf "$RSYNC_PID" rm -rf "$RSYNC_PID"
ADDR=$WSREP_SST_OPT_ADDR
RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }')
if [ -z "$RSYNC_PORT" ]
then
RSYNC_PORT=4444
ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT"
fi
trap "exit 32" HUP PIPE trap "exit 32" HUP PIPE
trap "exit 3" INT TERM ABRT trap "exit 3" INT TERM ABRT
trap cleanup_joiner EXIT trap cleanup_joiner EXIT
RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf"
if [ -n "${MYSQL_TMP_DIR:-}" ] ; then
SILENT="log file = $MYSQL_TMP_DIR/rsyncd.log"
else
SILENT=""
fi
cat << EOF > "$RSYNC_CONF" cat << EOF > "$RSYNC_CONF"
pid file = $RSYNC_PID pid file = $RSYNC_PID
use chroot = no use chroot = no
read only = no read only = no
timeout = 300 timeout = 300
$SILENT
[$MODULE] [$MODULE]
path = $WSREP_SST_OPT_DATA path = $WSREP_SST_OPT_DATA
[$MODULE-log_dir] [$MODULE-log_dir]
...@@ -280,6 +293,7 @@ EOF ...@@ -280,6 +293,7 @@ EOF
# rm -rf "$DATA"/ib_logfile* # we don't want old logs around # rm -rf "$DATA"/ib_logfile* # we don't want old logs around
# listen at all interfaces (for firewalled setups) # listen at all interfaces (for firewalled setups)
readonly RSYNC_PORT=${WSREP_SST_OPT_PORT:-4444}
rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" & rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" &
RSYNC_REAL_PID=$! RSYNC_REAL_PID=$!
...@@ -288,7 +302,7 @@ EOF ...@@ -288,7 +302,7 @@ EOF
sleep 0.2 sleep 0.2
done done
echo "ready $ADDR/$MODULE" echo "ready $WSREP_SST_OPT_HOST:$RSYNC_PORT/$MODULE"
# wait for SST to complete by monitoring magic file # wait for SST to complete by monitoring magic file
while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \ while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \
......
This diff is collapsed.
...@@ -571,27 +571,17 @@ int wsrep_init() ...@@ -571,27 +571,17 @@ int wsrep_init()
size_t const node_addr_len= strlen(node_addr); size_t const node_addr_len= strlen(node_addr);
if (node_addr_len > 0) if (node_addr_len > 0)
{ {
const char* const colon= strrchr(node_addr, ':'); size_t const ip_len= wsrep_host_len(node_addr, node_addr_len);
if (strchr(node_addr, ':') == colon) // 1 or 0 ':' if (ip_len + 7 /* :55555\0 */ < inc_addr_max)
{ {
size_t const ip_len= colon ? colon - node_addr : node_addr_len; memcpy (inc_addr, node_addr, ip_len);
if (ip_len + 7 /* :55555\0 */ < inc_addr_max) snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u",
{ (int)mysqld_port);
memcpy (inc_addr, node_addr, ip_len);
snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u",
(int)mysqld_port);
}
else
{
WSREP_WARN("Guessing address for incoming client connections: "
"address too long.");
inc_addr[0]= '\0';
}
} }
else else
{ {
WSREP_WARN("Guessing address for incoming client connections: " WSREP_WARN("Guessing address for incoming client connections: "
"too many colons :) ."); "address too long.");
inc_addr[0]= '\0'; inc_addr[0]= '\0';
} }
} }
......
...@@ -634,18 +634,19 @@ ssize_t wsrep_sst_prepare (void** msg) ...@@ -634,18 +634,19 @@ ssize_t wsrep_sst_prepare (void** msg)
// Figure out SST address. Common for all SST methods // Figure out SST address. Common for all SST methods
if (wsrep_sst_receive_address && if (wsrep_sst_receive_address &&
strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO)) strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO))
{ {
addr_in= wsrep_sst_receive_address; addr_in= wsrep_sst_receive_address;
} }
else if (wsrep_node_address && strlen(wsrep_node_address)) else if (wsrep_node_address && strlen(wsrep_node_address))
{ {
const char* const colon= strchr (wsrep_node_address, ':'); size_t const addr_len= strlen(wsrep_node_address);
if (colon) size_t const host_len= wsrep_host_len(wsrep_node_address, addr_len);
if (host_len < addr_len)
{ {
ptrdiff_t const len= colon - wsrep_node_address; strncpy (ip_buf, wsrep_node_address, host_len);
strncpy (ip_buf, wsrep_node_address, len); ip_buf[host_len]= '\0';
ip_buf[len]= '\0';
addr_in= ip_buf; addr_in= ip_buf;
} }
else else
...@@ -772,25 +773,6 @@ static int sst_donate_mysqldump (const char* addr, ...@@ -772,25 +773,6 @@ static int sst_donate_mysqldump (const char* addr,
bool bypass, bool bypass,
char** env) // carries auth info char** env) // carries auth info
{ {
size_t host_len;
const char* port = strchr (addr, ':');
if (port)
{
port += 1;
host_len = port - addr;
}
else
{
port = "";
host_len = strlen (addr) + 1;
}
char *host= (char *) alloca(host_len);
strncpy (host, addr, host_len - 1);
host[host_len - 1] = '\0';
int const cmd_len= 4096; int const cmd_len= 4096;
wsp::string cmd_str(cmd_len); wsp::string cmd_str(cmd_len);
...@@ -805,14 +787,13 @@ static int sst_donate_mysqldump (const char* addr, ...@@ -805,14 +787,13 @@ static int sst_donate_mysqldump (const char* addr,
int ret= snprintf (cmd_str(), cmd_len, int ret= snprintf (cmd_str(), cmd_len,
"wsrep_sst_mysqldump " "wsrep_sst_mysqldump "
WSREP_SST_OPT_HOST" '%s' " WSREP_SST_OPT_ADDR" '%s' "
WSREP_SST_OPT_PORT" '%s' "
WSREP_SST_OPT_LPORT" '%u' " WSREP_SST_OPT_LPORT" '%u' "
WSREP_SST_OPT_SOCKET" '%s' " WSREP_SST_OPT_SOCKET" '%s' "
WSREP_SST_OPT_CONF" '%s' " WSREP_SST_OPT_CONF" '%s' "
WSREP_SST_OPT_GTID" '%s:%lld'" WSREP_SST_OPT_GTID" '%s:%lld'"
"%s", "%s",
host, port, mysqld_port, mysqld_unix_port, addr, mysqld_port, mysqld_unix_port,
wsrep_defaults_file, uuid_str, wsrep_defaults_file, uuid_str,
(long long)seqno, bypass ? " " WSREP_SST_OPT_BYPASS : ""); (long long)seqno, bypass ? " " WSREP_SST_OPT_BYPASS : "");
......
...@@ -554,3 +554,18 @@ size_t wsrep_guess_ip (char* buf, size_t buf_len) ...@@ -554,3 +554,18 @@ size_t wsrep_guess_ip (char* buf, size_t buf_len)
return 0; return 0;
} }
/* returns the length of the host part of the address string */
size_t wsrep_host_len(const char* const addr, size_t const addr_len)
{
// check for IPv6 notation first
const char* const bracket= ('[' == addr[0] ? strchr(addr, ']') : NULL);
if (bracket) { // IPv6
return (bracket - addr + 1);
}
else { // host part ends at ':' or end of string
const char* const colon= strchr(addr, ':');
return (colon ? colon - addr : addr_len);
}
}
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
unsigned int wsrep_check_ip (const char* addr); unsigned int wsrep_check_ip (const char* addr);
size_t wsrep_guess_ip (char* buf, size_t buf_len); size_t wsrep_guess_ip (char* buf, size_t buf_len);
/* returns the length of the host part of the address string */
size_t wsrep_host_len(const char* addr, size_t addr_len);
namespace wsp { namespace wsp {
class node_status class node_status
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment