#!/usr/bin/python
# PagerDuty

# -*- coding: utf-8 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2018             mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk is free software;  you can redistribute it and/or modify it
# under the  terms of the  GNU General Public License  as published by
# the Free Software Foundation in version 2.  check_mk is  distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
# tails. You should have  received  a copy of the  GNU  General Public
# License along with GNU Make; see the file  COPYING.  If  not,  write
# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
# Boston, MA 02110-1301 USA.
r"""
Send notification messages to PagerDuty
===================================

"""
from __future__ import unicode_literals
import sys
import requests
import re
import os

from typing import AnyStr, Dict, Optional, Tuple  # pylint: disable=unused-import

import cmk.password_store


def cmk_links(context):
    # type: (Dict) -> Tuple[Optional[str], Optional[str]]
    if context.get("PARAMETER_URL_PREFIX"):
        url_prefix = context["PARAMETER_URL_PREFIX"]
    elif context.get("PARAMETER_URL_PREFIX_MANUAL"):
        url_prefix = context["PARAMETER_URL_PREFIX_MANUAL"]
    elif context.get("PARAMETER_URL_PREFIX_AUTOMATIC") == "http":
        url_prefix = "http://%s/%s" % (context["MONITORING_HOST"], context["OMD_SITE"])
    elif context.get("PARAMETER_URL_PREFIX_AUTOMATIC") == "https":
        url_prefix = "https://%s/%s" % (context["MONITORING_HOST"], context["OMD_SITE"])
    else:
        url_prefix = None

    if url_prefix:
        base_url = re.sub('/check_mk/?', '', url_prefix)
        host_url = base_url + context['HOSTURL']

        if context['WHAT'] == 'SERVICE':
            service_url = base_url + context['SERVICEURL']
            return host_url, service_url

        return host_url, None

    return None, None


def collect_context():
    # type: () -> Dict
    return {
        var[7:]: value.decode("utf-8")
        for (var, value) in os.environ.items()
        if var.startswith("NOTIFY_")
    }


def retrieve_from_passwordstore(parameter):
    value = parameter.split()

    if len(value) == 2:
        if value[0] == 'store':
            value = cmk.password_store.load().get(value[1])
        else:
            value = value[1]
    else:
        value = value[0]

    return value


def pagerduty_event_type(event):
    return {
        "PROBLEM": "trigger",
        "ACKNOWLEDGEMENT": "acknowledge",
        "RECOVERY": "resolve",
        "FLAPPINGSTART": "trigger",
        "FLAPPINGSTOP": "resolve",
    }[event]


def pagerduty_severity(state):
    return {
        "CRITICAL": "critical",
        "DOWN": "critical",
        "WARNING": "warning",
        "OK": "info",
        "UP": "info",
        "UNKNOWN": "error",
        "UNREACHABLE": "error",
    }[state]


def pagerduty_msg(context):
    # type: (Dict) -> Dict
    """Build the PagerDuty incident payload"""

    host_url, service_url = cmk_links(context)

    if context.get('WHAT', None) == "SERVICE":
        state = context["SERVICESTATE"]
        incident_key = '{SERVICEDESC}/{HOSTNAME}:{HOSTADDRESS}'.format(**context).replace(" ", "")
        incident = "{SERVICESTATE}: {SERVICEDESC} on {HOSTNAME}".format(**context)
        output = context["SERVICEOUTPUT"]
        incident_url = service_url
    else:
        state = context["HOSTSTATE"]
        incident_key = '{HOSTNAME}:{HOSTADDRESS}'.format(**context).replace(" ", "")
        incident = '{HOSTNAME} is {HOSTSTATE}'.format(**context)
        output = context["HOSTOUTPUT"]
        incident_url = host_url

    msg_payload = {
        "routing_key": retrieve_from_passwordstore(context.get('PARAMETER_ROUTING_KEY')),
        "event_action": pagerduty_event_type(context.get('NOTIFICATIONTYPE')),
        "dedup_key": incident_key,
        "payload": {
            "summary": incident,
            "source":
                context.get('HOSTADDRESS', context.get('HOSTNAME', 'Undeclared Host identifier')),
            "severity": pagerduty_severity(state),
            "custom_details": {
                "info": output,
                "host": context.get('HOSTNAME'),
                "host_address": context.get('HOSTADDRESS'),
            }
        }
    }
    if incident_url:
        msg_payload.update({"client": "Check_MK", "client_url": incident_url})

    return msg_payload


def post_request(message_constructor, success_code=200):
    context = collect_context()

    url = retrieve_from_passwordstore(context.get("PARAMETER_WEBHOOK_URL"))

    r = requests.post(url=url, json=message_constructor(context))

    if r.status_code == success_code:
        sys.exit(0)
    else:
        sys.stderr.write(
            "Failed to send notification. Status: %i, Response: %s\n" % (r.status_code, r.text))
        sys.exit(2)


if __name__ == "__main__":
    # PagerDuty replies with 202 because the request is further processed
    # by them. Thus their reply only includes field validation checks.
    post_request(pagerduty_msg, success_code=202)
