picomon.py 3.7 KB
Newer Older
Jonathan Michalon's avatar
Jonathan Michalon committed
1 2
import concurrent.futures
from time import sleep
3
from subprocess_compat import TimeoutExpired, Popen, PIPE
Jonathan Michalon's avatar
Jonathan Michalon committed
4

5

Jonathan Michalon's avatar
Jonathan Michalon committed
6 7 8 9 10 11 12 13 14
class Check(object):
    def __init__(self, **options):
        self._options = options
        self.errmsg = ''
        self.ok = True

    def __repr__(self):
        return '<%s options=%s>' % (self.__class__.__name__, self._options)

15
    def setup(self):
Jonathan Michalon's avatar
Jonathan Michalon committed
16 17
        pass

18 19
    def teardown(self):
        pass
Jonathan Michalon's avatar
Jonathan Michalon committed
20 21 22 23

    def check(self, host, addr):
        pass

24 25 26 27
    def run(self):
        self.setup()
        self.ok = self.check()
        self.teardown()
Jonathan Michalon's avatar
Jonathan Michalon committed
28
        return self.ok
29

Jonathan Michalon's avatar
Jonathan Michalon committed
30
    def exec_with_timeout(self, command, timeout=2):
31
        self.errmsg = ''
32
        p = Popen(command, stdout=PIPE, stderr=PIPE)
33 34 35 36 37 38 39 40 41 42
        try:
            out, err = p.communicate(timeout=timeout)
        except TimeoutExpired:
            p.kill()
            out, err = p.communicate()
            self.errmsg += "Operation timed out\n"
        if p.returncode != 0:
            self.errmsg += "stdout: " + str(out) + '\n' + \
                           "stderr: " + str(err) + '\n'
        return p.returncode == 0
43

Jonathan Michalon's avatar
Jonathan Michalon committed
44

45 46 47
class CheckIP(Check):
    def __repr__(self):
        return '<%s on %s, options=%s>' % (self.__class__.__name__, self.addr, self._options)
Jonathan Michalon's avatar
Jonathan Michalon committed
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63

class Check4(CheckIP):
    def __init__(self, host, **options):
        super().__init__(**options)
        self.addr = host.ipv4


class Check6(CheckIP):
    def __init__(self, host, **options):
        super().__init__(**options)
        self.addr = host.ipv6


class CheckPing4(Check4):
    def check(self):
64 65
        command = ['/bin/ping', '-c', '1', '-W', '2', self.addr]
        return self.exec_with_timeout(command, timeout=3)
66 67 68 69


class CheckPing6(Check6):
    def check(self):
70 71
        command = ['/bin/ping6', '-c', '1', '-W', '2', self.addr]
        return self.exec_with_timeout(command, timeout=3)
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86


class CheckDNSZone(Check):
    def __init__(self, zone, **options):
        super().__init__(**options)
        self.zone = zone

    def __repr__(self):
        return '<%s on %s, options=%s>' % (self.__class__.__name__, self.zone, self._options)

    def check(self):
        self.errmsg = "Unimplemented"
        return False
        command = ['check_dns_soa', '-4', '-H', self.zone]
        return self.exec_with_timeout(command)
Jonathan Michalon's avatar
Jonathan Michalon committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101


class CheckDNSRec(Check):
    def check(self, host, addr):
        self.errmsg = "Unimplemented"
        return False


class CheckDNSAut(Check):
    def check(self, host, addr):
        self.errmsg = "Unimplemented"
        return False


class Host(object):
102
    def __init__(self, ipv4, ipv6):
Jonathan Michalon's avatar
Jonathan Michalon committed
103 104 105 106 107 108 109
        self.ipv4 = ipv4
        self.ipv6 = ipv6

    def __repr__(self):
        return '<Host ipv4="%s" ipv6="%s">' % (self.ipv4, self.ipv6)


110 111 112
class Checks(list):
    def add(self, check, dests):
        self += [check(d) for d in dests]
113 114 115 116 117


mail   = Host(ipv4='127.0.0.1', ipv6='::1')
web    = Host(ipv4='127.0.0.0', ipv6='::42')
alsace = Host(ipv4='127.0.0.1', ipv6='::1')
Jonathan Michalon's avatar
Jonathan Michalon committed
118

119 120 121 122 123 124
checks = Checks()
checks.add(CheckDNSZone, ["arn-fai.net", "netlib.re"])
checks.add(CheckPing4, [mail, web])
checks.add(CheckPing6, [mail, web])
# checks.add(CheckSMTP4, [mail, alsace])
# checks.add(CheckSMTP6, [mail, alsace])
Jonathan Michalon's avatar
Jonathan Michalon committed
125 126 127 128


if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
129 130 131 132 133 134 135 136 137 138 139 140 141 142
        def runner(check):
            return check.run(), check

        futures = []
        for check in checks:
            futures.append(executor.submit(runner, check))

        for future in concurrent.futures.as_completed(futures):
            success, check = future.result()
            if success:
                print("Check %s successful!" % (str(check)))
            else:
                print("Check %s failed:\n%s" %
                      (str(check), check.errmsg))