diff options
Diffstat (limited to 'ctdb/tools/ctdb_natgw')
-rwxr-xr-x | ctdb/tools/ctdb_natgw | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/ctdb/tools/ctdb_natgw b/ctdb/tools/ctdb_natgw new file mode 100755 index 0000000..728cd9c --- /dev/null +++ b/ctdb/tools/ctdb_natgw @@ -0,0 +1,194 @@ +#!/bin/sh + +if [ -z "$CTDB_BASE" ] ; then + export CTDB_BASE="/usr/local/etc/ctdb" +fi + +. "${CTDB_BASE}/functions" + +load_script_options "failover" "11.natgw" + +# Default NAT gateway nodes file location +[ -n "$CTDB_NATGW_NODES" ] || CTDB_NATGW_NODES="${CTDB_BASE}/natgw_nodes" + +if [ -z "$CTDB" ] ; then + CTDB=ctdb +fi + +############################################################ + +usage () +{ +cat <<EOF +$0 <option> + +<option> is one of: + leader Display node number and private IP address of leader node + list List private IP addresses of nodes in group, annotate leader + status Show status of nodes in NAT gateway group +EOF + exit 1 +} + +nodestatus_X="" +# Fields are: +# Node|IP|Disconnected|Unknown|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode +get_nodestatus_X () +{ + # Result is cached in global variable nodestatus_X + [ -n "$nodestatus_X" ] || \ + nodestatus_X=$($CTDB -X nodestatus all | + sed -e '1d' -e 's@^|@@' -e 's@|$@@') +} + +get_nodestatus () +{ + # Result is cached in global variable nodestatus + [ -n "$nodestatus" ] || nodestatus=$($CTDB nodestatus all) + [ $? -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 + follower-only|"") : ;; + *) die "${prog}: Invalid options \"${_options}\" in \"$CTDB_NATGW_NODES\"" + esac + done <<EOF +$natgw_nodes +EOF + + return 0 +} + +# Print the PNN and IP address of the NAT gateway leader node +find_leader () +{ + 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" + + # $_ms is an @-delimited list of nodes that are allowed to be the leader + _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 + # the first to succeed will select the leader node. + + # First try for a fully active and healthy node, so must not be + # UNKNOWN, DISABLED, UNHEALTHY or INACTIVE (last covers DISCONNECTED, + # BANNED or STOPPED) + awk -F '|' -v ms="$_ms" \ + 'BEGIN { ret = 2 } + ms ~ "@" $2 "@" && + $4 == 0 && $6 == 0 && $7 == 0 && $9 == 0 { print $1, $2 ; ret=0 ; exit } + 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 } + ms ~ "@" $2 "@" && + $3 == 0 && $6 == 0 && $8 == 0 { print $1, $2 ; ret=0 ; exit } + 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 } + ms ~ "@" $2 "@" && + $3 == 0 && $6 == 0 { print $1, $2 ; ret=0 ; exit } + END { exit ret }' <<EOF +$nodestatus_X +EOF +} + +# List all nodes in the NAT gateway group, annotating the leader node +nodes_list () +{ + get_natgw_nodes || \ + die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found" + # Intentional word splitting here + # shellcheck disable=SC2046 + set -- $(find_leader) || \ + die "${prog}: Unable to determine NAT gateway leader node" + _leader_ip="$2" + + # Annotate the leader node + while read _ip _options ; do + if [ "$_ip" = "$_leader_ip" ] ; then + _options="LEADER${_options:+,}${_options}" + fi + # 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 + printf '%s\t%s\n' "$_ip" "$_options" + else + echo "$_ip" + fi + 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 + awk -v ns="$_ns" 'ns ~ "@" $2 "@" { print $0 }' <<EOF +$nodestatus +EOF +} + +prog=$(basename "$0") +cmd="$1" + +case "$cmd" in + leader) find_leader ;; + list) nodes_list ;; + status) nodes_status ;; + *) usage ;; +esac |