#!/usr/bin/env python3
import json
import pathlib
import subprocess


"""
This is an ugly hack.

Puppet exported resources are very nice to generate monitoring configuration
along with your Puppet resources. As you define something like an Apache
virtual host, you can create a Nagios service check for it.

But this requires a PuppetDB, and does not play nice with having no central
Puppet infra.

With its sibling script up.py, this script takes the JSON files generated by
that, and manipulates them. This script moves Nagios resources to a specific
host and does ugly trickery to fool Puppet into accepting that.

This is like exported resources, but you don't need to declare a resource as
exported.
"""


def load_json(path):
    with open(path) as f:
        return json.load(f)


def save_json(r, path):
    with open(path, "w") as f:
        json.dump(r, f)


nagios_catalog_file = pathlib.Path("build/puppet/build/output/nagios.h1.int.pdp7.net/catalog.json")

if nagios_catalog_file.exists():
    nagios_catalog = load_json(nagios_catalog_file)

    nagios_contacts = [r for r in nagios_catalog["resources"] if r["type"] == "Nagios_contact"]
    assert len(nagios_contacts) == 1, f"found multiple nagios contacts {nagios_contacts}"
    nagios_contact = nagios_contacts[0]


ail = subprocess.run(["ansible-inventory", "--list"], check=True, stdout=subprocess.PIPE)
inventory = json.loads(ail.stdout)
total_hosts_in_inventory = len(inventory["_meta"]["hostvars"].keys())
k8s_hosts_in_inventory = len(inventory["k8s"]["hosts"])
unmonitored_hosts_in_inventory = len(inventory["unmonitored"]["hosts"])

puppet_hosts_in_inventory = total_hosts_in_inventory - k8s_hosts_in_inventory - unmonitored_hosts_in_inventory

catalog_files = list(pathlib.Path("build/puppet/build/output/").glob("*/catalog.json"))

if nagios_catalog_file.exists():
    assert len(catalog_files) == puppet_hosts_in_inventory, f"catalogs {catalog_files} quantity different from total hosts in inventory {puppet_hosts_in_inventory}"


nagios_resources = []
nagios_edge_targets = []


def is_nagios_resource(r):
    return r["type"].startswith("Nagios")


def is_nagios_edge(e):
    return e["target"].startswith("Nagios")


for catalog_file in catalog_files:
    if catalog_file == nagios_catalog_file:
        continue
    catalog = load_json(catalog_file)
    nagios_resources += [r for r in catalog["resources"] if is_nagios_resource(r)]
    catalog["resources"] = [r for r in catalog["resources"] if not is_nagios_resource(r)]
    nagios_edge_targets += [e["target"] for e in catalog["edges"] if is_nagios_edge(e)]
    catalog["edges"] = [e for e in catalog["edges"] if not is_nagios_edge(e)]
    save_json(catalog, catalog_file)


if nagios_catalog_file.exists():
    nagios_contact_position = nagios_catalog["resources"].index(nagios_contact)

    def copy_parameters(r):
        for p in ["require", "notify", "owner"]:
            r["parameters"][p] = nagios_contact["parameters"][p]
        return r

    nagios_catalog["resources"] = (
        nagios_catalog["resources"][0:nagios_contact_position] +
        list(map(copy_parameters, nagios_resources)) +
        nagios_catalog["resources"][nagios_contact_position:]
    )

    nagios_catalog["edges"] += [{"source": "Class[Nagios]", "target": t} for t in nagios_edge_targets]

    save_json(nagios_catalog, nagios_catalog_file)
