2016-04-07 10:30:28 +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" "91.lvs"
2016-04-07 10:30:28 +03:00
# Default LVS nodes file location
[ -n "$CTDB_LVS_NODES" ] || CTDB_LVS_NODES="${CTDB_BASE}/lvs_nodes"
2016-04-26 18:43:39 +03:00
if [ -z "$CTDB" ] ; then
CTDB=ctdb
fi
2016-04-07 10:30:28 +03:00
############################################################
usage ()
{
cat <<EOF
$0 <option>
<option> is one of:
2020-07-17 13:46:07 +03:00
leader Display node number of leader node
2016-04-07 10:30:28 +03:00
list List node number and private IP address of usable nodes in group
status Show status of all nodes in LVS group
EOF
exit 1
}
nodestatus_X=""
# Fields are:
# Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode
get_nodestatus_X ()
{
# Result is cached in global variable nodestatus_X
[ -n "$nodestatus_X" ] || \
2016-04-26 18:43:39 +03:00
nodestatus_X=$($CTDB -X nodestatus all |
2016-04-07 10:30:28 +03:00
sed -e '1d' -e 's@^|@@' -e 's@|$@@')
}
get_nodestatus ()
{
# Result is cached in global variable nodestatus
2016-04-26 18:43:39 +03:00
[ -n "$nodestatus" ] || nodestatus=$($CTDB nodestatus all)
2016-04-07 10:30:28 +03:00
case $? in
2016-04-26 18:43:39 +03:00
# $CTDB nodestatus returns 255 on failure
2016-04-07 10:30:28 +03:00
0|255) return 0 ;;
*) return 1 ;;
esac
}
get_lvs_nodes ()
{
# Result is cached in global variable lvs_nodes
if [ -n "$lvs_nodes" ] ; then
return
fi
if [ ! -r "$CTDB_LVS_NODES" ] ; then
return 1
fi
lvs_nodes=$(cat "$CTDB_LVS_NODES") || return 1
# Sanity check file contents here
while read _ip _options ; do
# Skip comments
case "$_ip" in
\#*) continue ;;
esac
case "$_options" in
2020-07-17 13:46:07 +03:00
follower-only|"") : ;;
2016-04-07 10:30:28 +03:00
*) die "${prog}: Invalid options \"${_options}\" in \"$CTDB_LVS_NODES\""
esac
done <<EOF
$lvs_nodes
EOF
return 0
}
# Print PNN and IP address of given nodes meeting the criteria for
# usable LVS nodes. That is, either those that are healthy or, if no
# healthy nodes, then nodes that are active and not-disabled.
# Return codes: 0 = nodes found, 255 = no nodes found, 10 = error.
filter_nodes ()
{
# $_ns is an @-delimited list of nodes to be considered
_ns="$1"
get_nodestatus_X
[ -n "$nodestatus_X" ] || return 10
# Now filter by $_ns and by status of nodes...
# Note that the 2 awk invocations below have "||" between
# them, so the first to succeed will print the nodes.
# First try for a fully active and healthy node, so must not
# be DISABLED, UNHEALTHY or INACTIVE (last covers
# DISCONNECTED, BANNED or STOPPED)
awk -F '|' -v ns="$_ns" '
BEGIN { ret = 255 }
ns ~ "@" $2 "@" && $5 == 0 && $6 == 0 && $8 == 0 {
print $1, $2 ; ret=0
}
END { exit ret }
' <<EOF ||
$nodestatus_X
EOF
# Not found? UNHEALTHY do, so node must not be INACTIVE or
# DISABLED
awk -F '|' -v ns="$_ns" '
BEGIN { ret = 255 }
ns ~ "@" $2 "@" && $5 == 0 && $8 == 0 {
print $1, $2 ; ret=0
}
END { exit ret }
' <<EOF
$nodestatus_X
EOF
}
2020-07-17 13:46:07 +03:00
# Print the PNN of the LVS leader node
find_leader ()
2016-04-07 10:30:28 +03:00
{
get_lvs_nodes || \
die "${prog}: LVS nodes file \"$CTDB_LVS_NODES\" not found"
2020-07-17 13:46:07 +03:00
# $_ms is an @-delimited list of nodes that are allowed to be the leader
2016-04-07 10:30:28 +03:00
_ms="@"
while read _ip _options ; do
case "$_options" in
"") _ms="${_ms}${_ip}@" ;;
esac
done <<EOF
$lvs_nodes
EOF
2020-07-17 13:46:07 +03:00
_leader_candidates=$(filter_nodes "$_ms") || return $?
echo "${_leader_candidates%% *}"
2016-04-07 10:30:28 +03:00
}
# List all usable nodes in the LVS group
nodes_list ()
{
get_lvs_nodes || \
die "${prog}: LVS nodes file \"$CTDB_LVS_NODES\" not found"
# $_ns is a @-delimited list of nodes in the LVS group
_ns="@"
while read _ip _options ; do
_ns="${_ns}${_ip}@"
done <<EOF
$lvs_nodes
EOF
_usable_nodes=$(filter_nodes "$_ns")
case $? in
0) : ;;
255) exit 0 ;; # Return 0 even if no usable nodes
*) exit 10 ;;
esac
2016-04-13 10:47:45 +03:00
awk '{ print $1, $2 }'<<EOF
2016-04-07 10:30:28 +03:00
$_usable_nodes
EOF
}
# Print the status of all nodes in the LVS group, along with a count
nodes_status ()
{
get_lvs_nodes || \
die "${prog}: LVS nodes file \"$CTDB_LVS_NODES\" not found"
get_nodestatus
[ -n "$nodestatus" ] || exit 10
# $_ns is a @-delimited list of nodes in the LVS group
_ns="@"
while read _ip _options ; do
_ns="${_ns}${_ip}@"
done <<EOF
$lvs_nodes
EOF
# Print status of nodes in $_ns, along with node count
awk -v ns="$_ns" 'ns ~ "@" $2 "@" { print }' <<EOF
$nodestatus
EOF
}
# For backward compatibility
prog=$(basename "$0")
cmd="$1"
case "$cmd" in
2020-07-17 13:46:07 +03:00
leader) find_leader ;;
2016-04-07 10:30:28 +03:00
list) nodes_list ;;
status) nodes_status ;;
*) usage ;;
esac