ctdb-tools: Add standalone ctdb_natgw tool script
authorMartin Schwenke <martin@meltin.net>
Mon, 14 Dec 2015 00:34:41 +0000 (11:34 +1100)
committerAmitay Isaacs <amitay@samba.org>
Mon, 25 Jan 2016 06:18:25 +0000 (07:18 +0100)
This is intended to replace the use of "ctdb natgwlist" in 11.natgw
and provide different views of the NAT gateway status.

It replaces the use of CTDB_NATGW_SLAVE_ONLY=yes with a "slave-only"
keyword in the NAT gateway nodes file.  This means the nodes file must
be consistent on all nodes in a NAT gateway group.

Note that this script is not yet integrated, so there are no behaviour
or documentation changes.

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/packaging/RPM/ctdb.spec.in
ctdb/tools/ctdb_natgw [new file with mode: 0755]
ctdb/wscript

index 9985dfe61bbc26f0a72c6998b69851fe008c46c8..55ce0e5e1beb89f492c597cd41c7fad06e521c77 100644 (file)
@@ -203,6 +203,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_bindir}/ltdbtool
 %{_bindir}/ctdb_diagnostics
 %{_bindir}/onnode
+%{_bindir}/ctdb_natgw
 %dir %{_libdir}
 %{_libdir}/ctdb/lib*
 %{_libdir}/libtevent-unix-util.so.0*
diff --git a/ctdb/tools/ctdb_natgw b/ctdb/tools/ctdb_natgw
new file mode 100755 (executable)
index 0000000..d778c2d
--- /dev/null
@@ -0,0 +1,199 @@
+#!/bin/sh
+
+if [ -z "$CTDB_BASE" ] ; then
+    export CTDB_BASE="/usr/local/etc/ctdb"
+fi
+
+. "${CTDB_BASE}/functions"
+loadconfig "ctdb"
+
+# Default NAT gateway nodes file location
+[ -n "$CTDB_NATGW_NODES" ] || CTDB_NATGW_NODES="${CTDB_BASE}/natgw_nodes"
+
+[ -n "$CTDB_SOCKET" ] && export CTDB_SOCKET
+
+############################################################
+
+usage ()
+{
+cat <<EOF
+$0 <option>
+
+<option> is one of:
+  master     Display node number and private IP address of master node
+  list       List private IP addresses of nodes in group, annotate master
+  status     Show status of nodes in NAT gateway group
+  natgwlist  Combination of "master" and "status", for backward compatiblity
+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)
+    [ $? -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
+           slave-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 master node
+find_master ()
+{
+    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 master
+    _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 master node.
+
+    # 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 ms="$_ms" \
+       'BEGIN { ret = 2 }
+        ms ~ "@" $2 "@" && \
+            $5 == 0 && $6 == 0 && $8 == 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 && $5 == 0 && $7 == 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 && $5 == 0 { print $1, $2 ; ret=0 ; exit }
+        END { exit ret }' <<EOF
+$nodestatus_X
+EOF
+}
+
+# List all nodes in the NAT gateway group, annotating the master node
+nodes_list ()
+{
+    get_natgw_nodes || \
+       die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
+    set -- $(find_master)  || \
+       die "${prog}: Unable to determine NAT gateway master node"
+    _master_ip="$2"
+
+    # Annotate the master node
+    while read _ip _options ; do
+       if [ "$_ip" = "$_master_ip" ] ; then
+           _options="MASTER${_options:+,}${_options}"
+       fi
+       printf "${_ip}\t${_options}\n"
+    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" \
+       'BEGIN { out = "" ; count = 0 } \
+         ns ~ "@" $2 "@" { out =  out "\n" $0 ; count += 1 } \
+         END { print "Number of nodes:" count out }' <<EOF
+$nodestatus
+EOF
+}
+
+# For backward compatibility
+natgwlist ()
+{
+    ret=0
+    find_master
+    if [ $? -eq 2 ] ; then
+       echo "-1 0.0.0.0"
+       ret=2
+    fi
+    nodes_status || return $?
+    return $ret
+}
+
+prog=$(basename "$0")
+cmd="$1"
+
+case "$cmd" in
+    master)    find_master ;;
+    list)      nodes_list ;;
+    status)    nodes_status ;;
+    natgwlist) natgwlist ;;
+    *)         usage ;;
+esac
index 0acb6ff20e091586239b85a4a973c8d5113f25f7..edd4aa496bb80a496afc51faf5c68d703f1d8991 100755 (executable)
@@ -536,6 +536,13 @@ def build(bld):
     bld.INSTALL_FILES('${BINDIR}', 'ctdb_diagnostics',
                       destname='ctdb_diagnostics', chmod=0755)
 
+    bld.SAMBA_GENERATOR('ctdb-natgw',
+                        source='tools/ctdb_natgw',
+                        target='ctdb_natgw',
+                        rule='sed %s ${SRC} > ${TGT}' % (sed_cmdline))
+    bld.INSTALL_FILES('${BINDIR}', 'ctdb_natgw',
+                      destname='ctdb_natgw', chmod=0755)
+
     bld.SAMBA_GENERATOR('ctdbd-wrapper',
                         source='config/ctdbd_wrapper',
                         target='ctdbd_wrapper',