#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Ручки для проверки живости контейнера (/status) и graceful остановки (/stop).
Полезно в разных stateful *loud сервисах.

Пример:
container-http-hooks --status-hook /usr/local/share/container-helpers/status-hook \
--stop-hook /usr/local/share/container-helpers/stop-hook --log-level DEBUG &

curl localhost:5725/status
curl localhost:5725/stop

/stop хук можт возвращать ответ быстро, а потом в фоне методично стопать сервис.
Platform будет ждать именно смерти контейнера (выхода CMD процесса) в течение
заданного таймаута.
"""

from http.server import HTTPServer, BaseHTTPRequestHandler
import argparse
import logging
import logging.handlers
import socket
import subprocess
import time


def init_root_logger(args):
    try:
        args.log_level = int(logging.getLevelName(args.log_level))
    except:
        args.log_level = logging.ERROR

    logger = logging.getLogger()
    logger.setLevel(args.log_level)
    handler = logging.StreamHandler()

    handler.setLevel(args.log_level)
    handler.setFormatter(logging.Formatter('[%(asctime)s]\t%(levelname)-8s\t%(threadName)-15s\t%(message)s'))
    logger.addHandler(handler)
    return logger


class HttpProcessor(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/status':
            self.run_hook(self.args.status_hook)
        if self.path == '/stop':
            self.run_hook(self.args.stop_hook)

    def log_message(self, format, *args):
        self.logger.info(format % args)
        return

    def run_hook(self, script_path):
        try:
            self.logger.info('run ' + script_path)
            out = subprocess.check_call(script_path) #, timeout=5) # script timeout
            self.logger.info('success')
            self.hook_ok('ok')
        except Exception as e:
            err = 'fail: %s - %s' % (type(e), e)
            self.logger.error(err)
            self.hook_fail(err)

    def hook_ok(self, msg):
        self.send_response(200)
        self.send_header('Content-type','text/plain; charset=utf-8')
        self.end_headers()
        self.wfile.write(msg.encode())

    def hook_fail(self, msg):
        self.send_response(500)
        self.send_header('Content-type','text/plain; charset=utf-8')
        self.end_headers()
        self.wfile.write(msg.encode())


class HttpServerV6(HTTPServer):
    address_family = socket.AF_INET6


def run(server_class=HttpServerV6, handler_class=HttpProcessor):
    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__)
    parser.add_argument('--port', type=int, default=5725, help='Port for http-server (default 5725)')
    parser.add_argument('--status-hook', type=str, default=None, required=True, help='Path to status hook script')
    parser.add_argument('--stop-hook', type=str, default=None, required=True, help='Path to stop hook script')
    parser.add_argument('--log-level', type=str, required=False, choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='ERROR', help='Logging level')
    args = parser.parse_args()
 
    logger = init_root_logger(args) 
    logger.info('Started with args ' + str(args))

    server_address = ('', args.port)
    # socket timeout
    # handler_class.timeout = 1
    handler_class.logger = logger
    handler_class.args = args

    httpd = server_class(server_address, handler_class)
    httpd.serve_forever()

if __name__ == '__main__':
    run()
