#! /usr/bin/env python3

import glob
import jinja2
import re
import os
import subprocess
import sys
import textwrap
import yaml

from typing import List


TEMPLATE = """
vars.http_vhosts["{{hostname}}"] = {
  http_uri = "{{ uri }}"
  http_vhost = "{{ vhost | default(hostname) }}"
  http_ssl = {{ ssl | default('true') }}
  {% if expect %}
  http_expect = "{{ expect }}"
  {% endif %}
}

"""


DEBUG = os.getenv("DEBUG", None)


def get_vhosts() -> List[str]:
    vhosts = set()

    for filename in glob.glob("/etc/nginx/sites-enabled/*"):
        with open(filename, "r") as f:
            matches = re.findall("server_name\s+(.+);", f.read())
            if not matches:
                print("Warning: could not find any vhosts in file: {}".format(filename))

            for match in matches:
                for server_name in match.split(" "):
                    vhosts.add(server_name)

    for i in read_config()["exclude_vhosts"]:
        vhosts.discard(i)

    for vhost in list(vhosts):
        if "*." in vhost:
            # assumption: in a wildcard setup, the hostname _wildcard should be reachable
            vhosts.remove(vhost)
            vhosts.add(vhost.replace("*.", "_wildcard."))

    for vhost in read_config()["vhosts"].keys():
        if vhost not in vhosts:
            vhosts.add(vhost)

    rv = list(vhosts)
    rv.sort()
    return rv


def read_config() -> dict:
    # dummy configuration in case the path can't be resolved
    data = {
        "vhosts": [],
        "exclude_vhosts": [],
    }

    config_path = os.path.abspath(
        os.path.join(
            os.path.dirname(os.path.realpath(__file__)),
            "config.yml"
        )
    )

    try:
        with open(config_path, "r") as f:
            data = yaml.load(f.read(), Loader=yaml.SafeLoader)
    except Exception as e:
        print("Warning: could not open configuration file {}: "
              "{}".format(config_path, repr(e)),
              file=sys.stderr)

    return data


def render(vhost: str) -> str:
    template = jinja2.Template(TEMPLATE)

    vars = {
        "hostname": vhost,
        "uri": "/",
    }

    vhosts = read_config()["vhosts"]

    # if it's a wildcard host, assume 404 as default status
    if "_wildcard." in vhost:
        vars["expect"] = 404

    if vhost in vhosts:
        vars.update(vhosts[vhost])

    result = template.render(**vars)
    return result


def main():
    vhosts = get_vhosts()

    f = None

    try:
        if DEBUG:
            # overwrite f with sys.stdout
            f = sys.stdout
        else:
            dirpath = "/etc/icinga2/conf.d/"
            os.makedirs(dirpath, exist_ok=True)
            f = open(os.path.join(dirpath, "nginx-vhosts.conf"), "w")

        preamble = textwrap.dedent("""\
        # autogenerated vhosts list
        """)

        f.write(preamble)

        for vhost in vhosts:
            data = render(vhost)
            f.write(data)

        f.write("\n")

    except:
        raise

    else:
        subprocess.check_output("service icinga2 reload".split())

    finally:
        if not DEBUG:
            if f is not None:
                f.close()


if __name__ == "__main__":
    sys.exit(main())


#! /usr/bin/env python3

import glob
import jinja2
import re
import os
import subprocess
import sys
import textwrap
import yaml

from typing import List


TEMPLATE = """
vars.http_vhosts["{{hostname}}"] = {
  http_uri = "{{ uri }}"
  http_vhost = "{{ vhost | default(hostname) }}"
  http_ssl = {{ ssl | default('true') }}
  {% if expect %}
  http_expect = "{{ expect }}"
  {% endif %}
}

"""


DEBUG = os.getenv("DEBUG", None)


def get_vhosts() -> List[str]:
    vhosts = set()

    for filename in glob.glob("/etc/nginx/sites-enabled/*"):
        with open(filename, "r") as f:
            matches = re.findall("server_name\s+(.+);", f.read())
            if not matches:
                print("Warning: could not find any vhosts in file: {}".format(filename))

            for match in matches:
                for server_name in match.split(" "):
                    vhosts.add(server_name)

    for i in read_config()["exclude_vhosts"]:
        vhosts.discard(i)

    for vhost in list(vhosts):
        if "*." in vhost:
            # assumption: in a wildcard setup, the hostname _wildcard should be reachable
            vhosts.remove(vhost)
            vhosts.add(vhost.replace("*.", "_wildcard."))

    for vhost in read_config()["vhosts"].keys():
        if vhost not in vhosts:
            vhosts.add(vhost)

    rv = list(vhosts)
    rv.sort()
    return rv


def read_config() -> dict:
    # dummy configuration in case the path can't be resolved
    data = {
        "vhosts": [],
        "exclude_vhosts": [],
    }

    config_path = os.path.abspath(
        os.path.join(
            os.path.dirname(os.path.realpath(__file__)),
            "config.yml"
        )
    )

    try:
        with open(config_path, "r") as f:
            data = yaml.load(f.read(), Loader=yaml.SafeLoader)
    except Exception as e:
        print("Warning: could not open configuration file {}: "
              "{}".format(config_path, repr(e)),
              file=sys.stderr)

    return data


def render(vhost: str) -> str:
    template = jinja2.Template(TEMPLATE)

    vars = {
        "hostname": vhost,
        "uri": "/",
    }

    vhosts = read_config()["vhosts"]

    # if it's a wildcard host, assume 404 as default status
    if "_wildcard." in vhost:
        vars["expect"] = 404

    if vhost in vhosts:
        vars.update(vhosts[vhost])

    result = template.render(**vars)
    return result


def main():
    vhosts = get_vhosts()

    f = None

    try:
        if DEBUG:
            # overwrite f with sys.stdout
            f = sys.stdout
        else:
            dirpath = "/etc/icinga2/conf.d/"
            os.makedirs(dirpath, exist_ok=True)
            f = open(os.path.join(dirpath, "nginx-vhosts.conf"), "w")

        preamble = textwrap.dedent("""\
        # autogenerated vhosts list
        """)

        f.write(preamble)

        for vhost in vhosts:
            data = render(vhost)
            f.write(data)

        f.write("\n")

    except:
        raise

    else:
        subprocess.check_output("service icinga2 reload".split())

    finally:
        if not DEBUG:
            if f is not None:
                f.close()


if __name__ == "__main__":
    sys.exit(main())


#! /usr/bin/env python3 vars.http_vhosts["{{hostname}}"] = {   http_uri = "{{ uri }}"   http_vhost = "{{ vhost | default(hostname) }}"   http_ssl = {{ ssl | default('true') }}   {% if expect %}   http_expect = "{{ expect }}"   {% endif %} } # assumption: in a wildcard setup, the hostname _wildcard should be reachable # dummy configuration in case the path can't be resolved # if it's a wildcard host, assume 404 as default status # overwrite f with sys.stdout \         # autogenerated vhosts list