2015-12-14 03:34:41 +03:00
#!/bin/sh
if [ -z "$CTDB_BASE" ] ; then
export CTDB_BASE="/usr/local/etc/ctdb"
fi
. "${CTDB_BASE}/functions"
2018-02-06 03:25:56 +03:00
2018-04-04 12:16:57 +03:00
load_script_options "failover" "11.natgw"
2015-12-14 03:34:41 +03:00
# Default NAT gateway nodes file location
[ -n "$CTDB_NATGW_NODES" ] || CTDB_NATGW_NODES="${CTDB_BASE}/natgw_nodes"
2016-04-28 06:11:29 +03:00
if [ -z "$CTDB" ] ; then
CTDB=ctdb
fi
2015-12-14 03:34:41 +03:00
############################################################
usage ()
{
cat <<EOF
$0 <option>
<option> is one of:
2020-06-24 04:20:24 +03:00
leader Display node number and private IP address of leader node
list List private IP addresses of nodes in group, annotate leader
2015-12-14 03:34:41 +03:00
status Show status of nodes in NAT gateway group
EOF
exit 1
}
nodestatus_X=""
# Fields are:
2022-04-26 10:20:21 +03:00
# Node|IP|Disconnected|Unknown|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode
2015-12-14 03:34:41 +03:00
get_nodestatus_X ()
{
# Result is cached in global variable nodestatus_X
[ -n "$nodestatus_X" ] || \
2016-04-28 06:11:29 +03:00
nodestatus_X=$($CTDB -X nodestatus all |
2015-12-14 03:34:41 +03:00
sed -e '1d' -e 's@^|@@' -e 's@|$@@')
}
get_nodestatus ()
{
# Result is cached in global variable nodestatus
2016-04-28 06:11:29 +03:00
[ -n "$nodestatus" ] || nodestatus=$($CTDB nodestatus all)
2015-12-14 03:34:41 +03:00
[ $? -ne 255 ] # ctdb nodestatus returns 255 on failure
}
get_natgw_nodes ()
{
# Result is cached in global variable natgw_nodes
if [ -n "$natgw_nodes" ] ; then
return
fi
if [ ! -r "$CTDB_NATGW_NODES" ] ; then
return 1
fi
natgw_nodes=$(cat "$CTDB_NATGW_NODES") || return 1
# Sanity check file contents here
while read _ip _options ; do
# Skip comments
case "$_ip" in
\#*) continue ;;
esac
case "$_options" in
2020-06-24 04:20:24 +03:00
follower-only|"") : ;;
2015-12-14 03:34:41 +03:00
*) die "${prog}: Invalid options \"${_options}\" in \"$CTDB_NATGW_NODES\""
esac
done <<EOF
$natgw_nodes
EOF
return 0
}
2020-06-24 04:20:24 +03:00
# Print the PNN and IP address of the NAT gateway leader node
find_leader ()
2015-12-14 03:34:41 +03:00
{
get_natgw_nodes || \
die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
get_nodestatus_X || \
die "${prog}: Unable to get status of nodes"
2020-06-24 04:20:24 +03:00
# $_ms is an @-delimited list of nodes that are allowed to be the leader
2015-12-14 03:34:41 +03:00
_ms="@"
while read _ip _options ; do
case "$_options" in
"") _ms="${_ms}${_ip}@" ;;
esac
done <<EOF
$natgw_nodes
EOF
# Now filter by $ms and by status of nodes...
# Note that the 3 awk invocations below have "||" between them, so
2020-06-24 04:20:24 +03:00
# the first to succeed will select the leader node.
2015-12-14 03:34:41 +03:00
# First try for a fully active and healthy node, so must not be
2022-04-26 10:20:21 +03:00
# UNKNOWN, DISABLED, UNHEALTHY or INACTIVE (last covers DISCONNECTED,
2015-12-14 03:34:41 +03:00
# BANNED or STOPPED)
awk -F '|' -v ms="$_ms" \
'BEGIN { ret = 2 }
2016-07-06 13:09:07 +03:00
ms ~ "@" $2 "@" &&
2022-04-26 10:20:21 +03:00
$4 == 0 && $6 == 0 && $7 == 0 && $9 == 0 { print $1, $2 ; ret=0 ; exit }
2015-12-14 03:34:41 +03:00
END { exit ret }' <<EOF ||
$nodestatus_X
EOF
# Not found? UNHEALTHY/BANNED will do, so node must not be
# DISCONNECTED, DISABLED or STOPPED
awk -F '|' -v ms="$_ms" \
'BEGIN { ret = 2 }
2016-07-06 13:09:07 +03:00
ms ~ "@" $2 "@" &&
2022-04-26 10:20:21 +03:00
$3 == 0 && $6 == 0 && $8 == 0 { print $1, $2 ; ret=0 ; exit }
2015-12-14 03:34:41 +03:00
END { exit ret }' <<EOF ||
$nodestatus_X
EOF
# Not found? STOPPED will do, so node must not be DISCONNECTED or
# DISABLED
awk -F '|' -v ms="$_ms" \
'BEGIN { ret = 2 }
2016-07-06 13:09:07 +03:00
ms ~ "@" $2 "@" &&
2022-04-26 10:20:21 +03:00
$3 == 0 && $6 == 0 { print $1, $2 ; ret=0 ; exit }
2015-12-14 03:34:41 +03:00
END { exit ret }' <<EOF
$nodestatus_X
EOF
}
2020-06-24 04:20:24 +03:00
# List all nodes in the NAT gateway group, annotating the leader node
2015-12-14 03:34:41 +03:00
nodes_list ()
{
get_natgw_nodes || \
die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
2016-07-06 10:31:51 +03:00
# Intentional word splitting here
# shellcheck disable=SC2046
2020-06-24 04:20:24 +03:00
set -- $(find_leader) || \
die "${prog}: Unable to determine NAT gateway leader node"
_leader_ip="$2"
2015-12-14 03:34:41 +03:00
2020-06-24 04:20:24 +03:00
# Annotate the leader node
2015-12-14 03:34:41 +03:00
while read _ip _options ; do
2020-06-24 04:20:24 +03:00
if [ "$_ip" = "$_leader_ip" ] ; then
_options="LEADER${_options:+,}${_options}"
2015-12-14 03:34:41 +03:00
fi
2016-07-14 05:08:04 +03:00
# There is no other way to do this and keep shellcheck happy.
# The tab character must be in the format string and the
# format string must contain no variables. Some shells will
# expand a tab if it is in an argument but others won't.
if [ -n "$_options" ] ; then
2018-04-19 04:54:26 +03:00
printf '%s\t%s\n' "$_ip" "$_options"
2016-07-14 05:08:04 +03:00
else
echo "$_ip"
fi
2015-12-14 03:34:41 +03:00
done <<EOF
$natgw_nodes
EOF
}
# Print the status of all nodes in the NAT gateway group, along with a count
nodes_status ()
{
get_natgw_nodes || \
die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
get_nodestatus || \
die "${prog}: Unable to get status of nodes"
# $_ns is a @-delimited list of nodes in the NAT gateway group
_ns="@"
while read _ip _options ; do
_ns="${_ns}${_ip}@"
done <<EOF
$natgw_nodes
EOF
# Print status of nodes in $_ns, along with node count
2016-04-18 08:44:15 +03:00
awk -v ns="$_ns" 'ns ~ "@" $2 "@" { print $0 }' <<EOF
2015-12-14 03:34:41 +03:00
$nodestatus
EOF
}
prog=$(basename "$0")
cmd="$1"
case "$cmd" in
2020-06-24 04:20:24 +03:00
leader) find_leader ;;
2015-12-14 03:34:41 +03:00
list) nodes_list ;;
status) nodes_status ;;
*) usage ;;
esac