summaryrefslogtreecommitdiffstats
path: root/ctdb/tools/ctdb_lvs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xctdb/tools/ctdb_lvs204
1 files changed, 204 insertions, 0 deletions
diff --git a/ctdb/tools/ctdb_lvs b/ctdb/tools/ctdb_lvs
new file mode 100755
index 0000000..d0249b9
--- /dev/null
+++ b/ctdb/tools/ctdb_lvs
@@ -0,0 +1,204 @@
+#!/bin/sh
+
+if [ -z "$CTDB_BASE" ] ; then
+ export CTDB_BASE="/usr/local/etc/ctdb"
+fi
+
+. "${CTDB_BASE}/functions"
+
+load_script_options "failover" "91.lvs"
+
+# Default LVS nodes file location
+[ -n "$CTDB_LVS_NODES" ] || CTDB_LVS_NODES="${CTDB_BASE}/lvs_nodes"
+
+if [ -z "$CTDB" ] ; then
+ CTDB=ctdb
+fi
+
+############################################################
+
+usage ()
+{
+ cat <<EOF
+$0 <option>
+
+<option> is one of:
+ leader Display node number of leader node
+ 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|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)
+ case $? in
+ # $CTDB nodestatus returns 255 on failure
+ 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
+ follower-only|"") : ;;
+ *) 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 UNKNOWN, DISABLED, UNHEALTHY or INACTIVE (last covers
+ # DISCONNECTED, BANNED or STOPPED)
+ awk -F '|' -v ns="$_ns" '
+ BEGIN { ret = 255 }
+ ns ~ "@" $2 "@" && $4 == 0 && $6 == 0 && $7 == 0 && $9 == 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 "@" && $6 == 0 && $9 == 0 {
+ print $1, $2 ; ret=0
+ }
+ END { exit ret }
+ ' <<EOF
+$nodestatus_X
+EOF
+}
+
+# Print the PNN of the LVS leader node
+find_leader ()
+{
+ get_lvs_nodes || \
+ die "${prog}: LVS nodes file \"$CTDB_LVS_NODES\" not found"
+
+ # $_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
+$lvs_nodes
+EOF
+
+ _leader_candidates=$(filter_nodes "$_ms") || return $?
+ echo "${_leader_candidates%% *}"
+}
+
+# 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
+
+ awk '{ print $1, $2 }'<<EOF
+$_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
+leader) find_leader ;;
+list) nodes_list ;;
+status) nodes_status ;;
+*) usage ;;
+esac