summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ctdb/packaging/RPM/ctdb.spec.in1
-rwxr-xr-xctdb/tools/ctdb_lvs220
-rwxr-xr-xctdb/wscript7
3 files changed, 228 insertions, 0 deletions
diff --git a/ctdb/packaging/RPM/ctdb.spec.in b/ctdb/packaging/RPM/ctdb.spec.in
index bbbf66c26b1..19c2af19e5e 100644
--- a/ctdb/packaging/RPM/ctdb.spec.in
+++ b/ctdb/packaging/RPM/ctdb.spec.in
@@ -205,6 +205,7 @@ rm -rf $RPM_BUILD_ROOT
%{_libexecdir}/ctdb/ctdb_event_helper
%{_libexecdir}/ctdb/ctdb_recovery_helper
%{_libexecdir}/ctdb/ctdb_natgw
+%{_libexecdir}/ctdb/ctdb_lvs
%{_libexecdir}/ctdb/ctdb_killtcp
%{_libexecdir}/ctdb/smnotify
%dir %{_libdir}
diff --git a/ctdb/tools/ctdb_lvs b/ctdb/tools/ctdb_lvs
new file mode 100755
index 00000000000..b71a3d47df8
--- /dev/null
+++ b/ctdb/tools/ctdb_lvs
@@ -0,0 +1,220 @@
+#!/bin/sh
+
+if [ -z "$CTDB_BASE" ] ; then
+ export CTDB_BASE="/usr/local/etc/ctdb"
+fi
+
+. "${CTDB_BASE}/functions"
+loadconfig "ctdb"
+
+# Default LVS nodes file location
+[ -n "$CTDB_LVS_NODES" ] || CTDB_LVS_NODES="${CTDB_BASE}/lvs_nodes"
+
+[ -n "$CTDB_SOCKET" ] && export CTDB_SOCKET
+
+############################################################
+
+usage ()
+{
+ cat <<EOF
+$0 <option>
+
+<option> is one of:
+ master Display node number of master 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|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
+ slave-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 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
+}
+
+# Print the PNN of the LVS master node
+find_master ()
+{
+ 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 master
+ _ms="@"
+ while read _ip _options ; do
+ case "$_options" in
+ "") _ms="${_ms}${_ip}@" ;;
+ esac
+ done <<EOF
+$lvs_nodes
+EOF
+
+ _master_candidates=$(filter_nodes "$_ms") || return $?
+ echo "${_master_candidates%% *}"
+}
+
+# Print the PNN of the LVS master node, verbose version
+show_master ()
+{
+ _master_pnn=$(find_master)
+ case "$?" in
+ 0)
+ echo "Node ${_master_pnn} is LVS master"
+ exit 0
+ ;;
+ 255)
+ echo "There is no LVS master"
+ exit 255
+ ;;
+ *)
+ exit 10
+ ;;
+ esac
+}
+
+# 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
+master) show_master ;;
+list) nodes_list ;;
+status) nodes_status ;;
+*) usage ;;
+esac
diff --git a/ctdb/wscript b/ctdb/wscript
index 41048fb8fc8..55b50eda819 100755
--- a/ctdb/wscript
+++ b/ctdb/wscript
@@ -550,6 +550,13 @@ def build(bld):
bld.INSTALL_FILES('${CTDB_HELPER_BINDIR}', 'ctdb_natgw',
destname='ctdb_natgw', chmod=0755)
+ bld.SAMBA_GENERATOR('ctdb-lvs',
+ source='tools/ctdb_lvs',
+ target='ctdb_lvs',
+ rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+ bld.INSTALL_FILES('${CTDB_HELPER_BINDIR}', 'ctdb_lvs',
+ destname='ctdb_lvs', chmod=0755)
+
bld.SAMBA_GENERATOR('ctdbd-wrapper',
source='config/ctdbd_wrapper',
target='ctdbd_wrapper',