#!/usr/bin/env python
#
# Provides: push-client
#
# simple push-client checker

import argparse
import commands
import json
import time
import os

INSTANCES_PATH = "/place/db/iss3/instances"


def main(args):
    instances = os.listdir(INSTANCES_PATH)

    check_failed = False
    errors = set()

    for i in instances:
        buf = i.split("_")

        if len(buf) < 3:
            raise Exception("Inccorect instance name {0}".format(i))
        # first element is instance port
        push_client_path_gencfg = os.path.join(INSTANCES_PATH, i, "wrap-pushclient-{0}".format(buf[0]))
        push_client_path_yp = os.path.join(INSTANCES_PATH, i, "wrap-pushclient-80")
        push_client_conf_real = os.path.join(INSTANCES_PATH, i, "push-client_real.conf")
        push_client_conf = os.path.join(INSTANCES_PATH, i, "push-client.conf")

        push_client_path = None
        if os.path.isfile(push_client_path_gencfg) or os.access(push_client_path_gencfg, os.X_OK):
            push_client_path = push_client_path_gencfg
        elif os.path.isfile(push_client_path_yp) or os.access(push_client_path_yp, os.X_OK):
            push_client_path = push_client_path_yp
        else:
            errors.add("No executable push client was found in {0}, {1}".format(push_client_path_gencfg, push_client_path_yp))
            check_failed = True
            continue

        config_path = None
        if os.path.isfile(push_client_conf_real):
            config_path = push_client_conf_real
        elif os.path.isfile(push_client_conf):
            config_path = push_client_conf
        else:
            check_failed = True
            errors.add("No config file was found in {0}, {1}".format(push_client_conf_real, push_client_conf))
            continue

        code, out = commands.getstatusoutput("{0} -c {1} --status --json".format(push_client_path, config_path))
        if code != 0:
            check_failed = True
            errors.add("Incorrect status code {0}: {1}".format(code, out))
            continue

        loaded_logs = json.loads(out)
        if not isinstance(loaded_logs, list):
            check_failed = True
            errors.add("Push client returned invalid json")
            continue

        if len(loaded_logs) == 0:
            check_failed = True
            errors.add("No logs was loadeded")
            continue

        for log in loaded_logs:
            if "name" not in log:
                check_failed = True
                errors.add("No log name in returned json")
                continue

            name = log["name"]

            if "last send time" not in log:
                check_failed = True
                errors.add("No 'last send time' in returned json for {0} log".format(name))
                continue
            if "lag" not in log:
                check_failed = True
                errors.add("No 'lag' in returned json for {0} log".format(name))
                continue
            if "last commit time" not in log:
                check_failed = True
                errors.add("No 'last commit time' in returned json for {0} log".format(name))
                continue

            send_delay = time.time() - log["last send time"]
            commit_delay = time.time() - log["last commit time"]
            lag = log["lag"]

            # file is adding, data is sending - ok
            if send_delay < args.s and commit_delay < args.c and lag < args.l:
                continue
            # not write to file, data is sending - ok
            elif send_delay < args.s and commit_delay >= args.c and lag == 0:
                continue
            elif send_delay < args.s and commit_delay >= args.c and lag > 0:
                check_failed = True
                errors.add("Push client has connection, but could not send data")
            else:
                check_failed = True
                errors.add("Push client could not connect")

    if check_failed:
        print("PASSIVE-CHECK:push-client;2;problems: {0}".format(", ".join(errors)))
    else:
        print("PASSIVE-CHECK:push-client;0;ok")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Push client checker for L7 balancer")
    parser.add_argument("-c", type=int, default=10*60, help="max push client commit delay")
    parser.add_argument("-s", type=int, default=10*60, help="max push client send delay")
    parser.add_argument("-l", type=int, default=2000000, help="max push client lag size")

    main(parser.parse_args())
