#!/usr/local/bin/python3.9
#
# Python script to enqueue an event from Sensu to send to PagerDuty.
#
# Copyright (c) 2017, PagerDuty, Inc. <info@pagerduty.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the copyright holder nor the
#     names of its contributors may be used to endorse or promote products
#     derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

import pdagent.thirdparty.argparse
import sys
import traceback


def log_exception(error, preface="Unexpected error"):
    """Prints user-friendly error message to the pdagent log"""
    from pdagent.pdqueue import logger
    message = "%s; encountered %s: %s\n%s" % (
        preface,
        error.__class__.__name__,
        str(error),
        traceback.format_exc()
    )
    logger.error(message)


class SensuEvent:
    """Class for enqueueing a Sensu check result as a PD event"""

    def __init__(self, integration_key, check_result, given_incident_key=None):
        """Constructor

        Arguments:
        :integration_key: The integration key for the integration
        :check_result: JSON string containing the result
        :given_incident_key: If specified, a custom incident key for 
            deduplication
        """
        import json
        self._integration_key = integration_key
        # Parse the body. It should be in the form of a Sensu "check result"
        # https://sensuapp.org/docs/latest/reference/checks.html#check-results
        check_json = str(check_result)
        try:
            details = json.loads(check_json)
        except Exception as e:
            jlen = len(check_result)
            log_exception(
                e,
                "Invalid JSON (length %d) or unknown error in pd-sensu" % jlen
            )
            raise e
        self._details = details
        # Normalize the event type
        action = details['action']
        event_types = {'resolve': 'resolve', 'create': 'trigger'}
        if action in event_types:
            self._event_type = event_types[action]
        else:
            self._event_type = 'trigger'
        # Set the incident key
        if given_incident_key is not None:
            self._incident_key = given_incident_key
        elif 'client' in details and 'check' in details:
            self._incident_key = '%s/%s' % (
                details['client']['name'],
                details['check']['name']
            )
        else:
            self._incident_key = details['id']
        self._description = '%s : %s' % (
            self._incident_key,
            details['check']['output']
        )

    def enqueue(self):
        from pdagent.config import load_agent_config
        from pdagent.pdagentutil import queue_event
        agent_config = load_agent_config()
        return queue_event(
            agent_config.get_enqueuer(),
            self._event_type,
            self._integration_key,
            self._incident_key,
            self._description,
            '',
            '',
            self._details,
            agent_config.get_agent_id(),
            'pd-sensu'
        )


def parse_args():
    description = "Enqueue an event from Sensu to PagerDuty."
    parser = argparse.ArgumentParser(description)
    parser.add_argument(
        '-k',
        '--integration-key',
        dest='integration_key',
        required=True,
        help="PagerDuty Sensu integration key"
    )
    parser.add_argument(
        '-i',
        '--incident-key',
        dest='incident_key',
        required=False,
        default=None,
        help="Specifies a custom incident key for deduplication"
    )
    return parser.parse_args()


def main():
    args = parse_args()
    stdin = sys.stdin.read()
    pdevent = SensuEvent(
        args.integration_key,
        stdin,
        given_incident_key=args.incident_key
    )

    try:
        pdevent.enqueue()
    except Exception as e:
        log_exception(
            e,
            preface="Uncaught exception while submitting Sensu event to queue"
        )
        raise e


if __name__ == '__main__':
    main()
