From 20621ebdb044b8f3f99086e042fd9b621a6b560a Mon Sep 17 00:00:00 2001
From: Thomas Bellman <bellman@lysator.liu.se>
Date: Mon, 17 Dec 2018 18:03:27 +0100
Subject: [PATCH] Perform actual pinging in check_ping_multiaddr.

The output text is rather rudimentary, just giving status codes and
IP addresses, but it is enough for showing that the calls to fping
and parsing of the fping output works.
---
 check_ping_multiaddr.py | 66 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)

diff --git a/check_ping_multiaddr.py b/check_ping_multiaddr.py
index ca74603..1a297dc 100755
--- a/check_ping_multiaddr.py
+++ b/check_ping_multiaddr.py
@@ -145,6 +145,63 @@ def collect_addresses(hosts, all_addresses, do_v4, do_v6):
 
 
 
+__fping_parser_re = re.compile(r"^([0-9a-f.:]+) is ([a-z]+)$")
+
+def parse_fping_output(output, expected_addrs):
+    alive = set()
+    unreachable = set()
+    for line in filter(bool, output):
+        match = __fping_parser_re.match(line)
+        if not match:
+            continue
+        ip = ipaddr.IPAddress(match.group(1))
+        status = match.group(2)
+        if status == 'alive':
+            alive.add(ip)
+        elif status == 'unreachable':
+            unreachable.add(ip)
+        else:
+            raise RuntimeError(
+                "Unexpected status line from fping, " + repr(line))
+    not_reported = expected_addrs - alive - unreachable
+    unexpected = (alive | unreachable) - expected_addrs
+
+    return (alive, unreachable, not_reported, unexpected)
+
+
+def ping_addresses(addresses):
+    fpingcmds = {
+        4: ['fping'],
+        6: ['fping6'],
+    }
+    fpingflags = [
+        # These settings gives ca 5 seconds timeout for unreachable addresses
+        '-i10',         # -i10 is the fastest fping allows without being root
+        '-t250',
+        '-B1.125',
+        '-r9',
+    ]
+    all_output = []
+    for ipver,addrs in addresses.items():
+        if not addrs:
+            continue
+        cmd = fpingcmds[ipver] + fpingflags + map(str, addrs)
+        chatter(1, "Running %r", cmd)
+        p = subprocess.Popen(
+            cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        output,errors = p.communicate()
+        output = output.split("\n"); errors = errors.split("\n")
+        chatter(3, "Received output %r", output)
+        chatter(3, "Received errors %r", errors)
+        all_output += output
+
+    alive, unreachable, not_reported, unexpected = parse_fping_output(
+        all_output, set().union(*addresses.values()))
+
+    return (alive, unreachable, not_reported, unexpected)
+
+
+
 def main(argv):
     global OPTIONS
     OPTIONS, arg_addresses = Options().parse_args(argv[1:])
@@ -155,8 +212,15 @@ def main(argv):
     for ipver,addrs in addresses.items():
         chatter(2, "IPv%d addresses:   %s", ipver, "  ".join(map(str, addrs)))
 
+    (alive, unreachable, not_reported, unexpected) = \
+        ping_addresses(addresses)
+
+    # XXX: Better messages
     ping_statuses = {
-        'UNKNOWN':  [ 'check_ping_multiaddr not yet implemented' ],
+        'OK':       map(str, alive),
+        'WARNING':  map(str, unexpected),
+        'CRITICAL': map(str, unreachable),
+        'UNKNOWN':  map(str, not_reported),
     }
     lvl,message = trh_nagioslib.nagios_report(ping_statuses)
     sys.stdout.write(message)
-- 
GitLab