Eventscripts - generalise TCP port checking plus new nmap-based checker
authorMartin Schwenke <martin@meltin.net>
Wed, 17 Aug 2011 02:12:20 +0000 (12:12 +1000)
committerMartin Schwenke <martin@meltin.net>
Fri, 19 Aug 2011 04:07:33 +0000 (14:07 +1000)
Split the netstat-specific parts of ctdb_check_tcp_ports() into new
function ctdb_check_tcp_ports_netstat().

Implement new ctdb_check_tcp_ports_nmap() function that uses
"nmap -PS" to check if the desired ports are listening.

ctdb_check_ctdb_ports() now uses new configuration variable
CTDB_TCP_PORT_CHECKERS to decide which port checkers to try.  Default
value is currently "nmap netstat".  If nmap is not found then this
will fall back to netstat.  This indicates that either nmap should be
installed or the default value of CTDB_TCP_PORT_CHECKERS should be
changed (in a configuration file) to avoid trying to use nmap.

Signed-off-by: Martin Schwenke <martin@meltin.net>
config/functions

index 1f50e70b7cedc715d639119d634e1cbe197fc072..caede81e2e2209760bd8c84eb92e3c846583c1ff 100755 (executable)
@@ -210,10 +210,60 @@ ctdb_check_tcp_init ()
 
 ctdb_check_tcp_ports()
 {
-    _ctdb_check_tcp_common
+    if [ -z "$1" ] ; then
+       echo "INTERNAL ERROR: ctdb_check_tcp_ports - no ports specified"
+       exit 1
+    fi
+
+    # Set default value for CTDB_TCP_PORT_CHECKS if unset.
+    # If any of these defaults are unsupported then this variable can
+    # be overridden in /etc/sysconfig/ctdb or via a file in
+    # /etc/ctdb/rc.local.d/.
+    : ${CTDB_TCP_PORT_CHECKERS:=nmap netstat}
+
+    for _c in $CTDB_TCP_PORT_CHECKERS ; do
+       ctdb_check_tcp_ports_$_c "$@"
+       case "$?" in
+           0)
+               rm -f "$_ctdb_service_started_file"
+               return 0
+               ;;
+           1)
+               _ctdb_check_tcp_common
+               if [ ! -f "$_ctdb_service_started_file" ] ; then
+                   echo "ERROR: $service_name tcp port $_p is not responding"
+                   cat <<EOF
+$ctdb_check_tcp_ports_debug
+EOF
+               else
+                   echo "INFO: $service_name tcp port $_p is not responding"
+               fi
+
+               return 1
+               ;;
+           127)
+               : # Not implemented
+               ;;
+           *)
+               
+       esac
+    done
 
+    echo "INTERNAL ERROR: ctdb_check_ports - no working checkers in CTDB_TCP_PORT_CHECKERS=\"$CTDB_TCP_PORT_CHECKERS\""
+
+    return 127
+}
+
+ctdb_check_tcp_ports_netstat ()
+{
     _cmd='netstat -l -t -n'
-    _ns=$($_cmd)
+    _ns=$($_cmd 2>&1)
+    if [ $? -eq 127 ] ; then
+       # netstat probably not installed - unlikely?
+       ctdb_check_tcp_ports_debug="$_ns"
+       return 127
+    fi
+
     for _p ; do  # process each function argument (port)
        for _a in '0\.0\.0\.0' '::' ; do
            _pat="[[:space:]]${_a}:${_p}[[:space:]]+[^[:space:]]+[[:space:]]+LISTEN"
@@ -223,21 +273,51 @@ ctdb_check_tcp_ports()
            fi
        done
 
-       # We didn't match the port, so flag an error, print some debug
-       if [ ! -f "$_ctdb_service_started_file" ] ; then
-           cat <<EOF
-ERROR: $service_name tcp port $_p is not responding
-$_cmd shows this output:
-$_ns
-EOF
-       else
-           echo "INFO: $service_name tcp port $_p is not responding"
-       fi
-
+       # We didn't match the port, so flag an error.
+       ctdb_check_tcp_ports_debug="$_cmd shows this output:
+$_ns"
        return 1
     done
 
-    rm -f "$_ctdb_service_started_file"
+    return 0
+}
+
+ctdb_check_tcp_ports_nmap ()
+{
+    # nmap wants a comma-separated list of ports
+    _ports=""
+    for _p ; do
+       _ports="${_ports}${_ports:+,}${_p}"
+    done
+
+    _cmd="nmap -n -oG - -PS 127.0.0.1 -p $_ports"
+
+    _nmap_out=$($_cmd 2>&1)
+    if [ $? -eq 127 ] ; then
+       # nmap probably not installed
+       ctdb_check_tcp_ports_debug="$_nmap_out"
+       return 127
+    fi
+
+    # get the port-related output
+    _port_info=$(echo "$_nmap_out" | sed -n -r -e 's@^.*Ports:[[:space:]]@@p')
+
+    for _p ; do
+       # looking for something like this:
+       #  445/open/tcp//microsoft-ds///
+       # possibly followed by a comma
+       _t="$_p/open/tcp//"
+       case "$_port_info" in
+           # The info we're after must be either at the beginning of
+           # the string or it must follow a space.
+            $_t*|*\ $_t*) : ;;
+           *)
+               # Nope, flag an error...
+               ctdb_check_tcp_ports_debug="$_cmd shows this output:
+$_nmap_out"
+               return 1
+       esac
+    done
 
     return 0
 }