#!/usr/bin/python3
#
#  {{ ansible_managed }}
#
import os
import sys
import subprocess
import yaml
import yaml.loader
import getopt
import time
import re
from os.path import basename


proc_name = basename(sys.argv[0])

CONFIG="/etc/grommunio-common/grommunio-certbot-deploy-hook.conf"

def get_config():
    try:
        config_stream = open(CONFIG)
        config = yaml.load(config_stream, Loader=yaml.loader.SafeLoader)
        config_stream.close()
    except (OSError, IOError) as err:
        print("{0}: I/O error opening/closing '{1}' - {2}"
              .format(proc_name, CONFIG, err), file=sys.stderr)
        sys.exit(200)
    except Exception as err:
        print("{0}: Invalid yaml in '{1}' - {2}"
              .format(proc_name, CONFIG, err), file=sys.stderr)
        sys.exit(200)
    if config == None:
        print("{0}: No configuration in '{1}' - please supply parsable yaml contents"
              .format(proc_name, CONFIG), file=sys.stderr)
        sys.exit(201)
    return config

def run_process(args, stdin='', accept_retcode=[]):
    result=None
    try:
        if not stdin:
            result = subprocess.run(args, check=True, stdout=subprocess.PIPE)
        else:
            result = subprocess.run(args, input=stdin.encode(),check=True, stdout=subprocess.PIPE)
    except subprocess.SubprocessError as err:
        if err.returncode in accept_retcode:
            return err
        print("{0}: Error calling '{1}' - '{2}'".format(proc_name, ' '.join(args), err), file=sys.stderr)
        sys.exit(202)
    return result

def process_service(service, restart=True):
    global config
    global renewed_domains

    if (type(service) is dict):
        serv_keys = set(service.keys())
        if ( not serv_keys.issuperset(set(['name',]))
                and not serv_keys.issuperset(set(['service',]))
                and not serv_keys.issuperset(set(['name', 'sans'])) 
                and not serv_keys.issuperset(set(['service', 'sans']))):
            print("{0}: service has invalid keys - must be 'service' and 'sans' or 'name' and 'sans' - exiting."
                  .format(proc_name),
                  file=sys.stderr)
            sys.exit(2)
        doms = set(service.get('sans', config.get('sans', [])))
        serv = service.get('name', '')
        serv = service.get('service', serv)
    elif (type(service) is str):
        doms = set(config.get('sans', []))
        serv = service
    else:
        print("{0}: service is not a string or dict - exiting."
              .format(proc_name),
              file=sys.stderr)
        sys.exit(2)
    if not serv:
        print("{0}: no service specified - exiting."
              .format(proc_name),
              file=sys.stderr)
        sys.exit(2)
    no_sans = config.get('no_sans', False)
    if (not no_sans and not renewed_domains.intersection(doms)):
        return False
    result = run_process(['systemctl', 'is-active', '-q', serv], accept_retcode=[0,3,4])
    if result.returncode != 0:
        return False
    run_process(['systemctl', 'try-restart' if restart else 'try-reload-or-restart', serv])
    return True

def short_usage():
    print("Usage: '{0}'".format(proc_name), file=sys.stderr)

def full_usage():
    short_usage()
    print('', file=sys.stderr)
    print("\tCertbot deploy hook, to manage service reload/restart", file=sys.stderr)

def main():
    global config
    global renewed_domains

    if (len(sys.argv) not in [1,]):
        full_usage()
        sys.exit(2)

    config = get_config()
    renewed_domains = set([x.strip() for x in os.environ.get('RENEWED_DOMAINS', '').split()])

    for s in config.get('systemd_reload', []):
        result = process_service(s, restart=False)
        if not result:
            continue

    for s in config.get('systemd_restart', []):
        result = process_service(s, restart=True)
        if not result:
            continue

    return

if __name__ == '__main__':
    main()
