#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2015             mk@mathias-kettner.de |
# +------------------------------------------------------------------+
# Written by comNET GmbH, Ringo Hartmann
#
# 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.

import getopt
import httplib
try:
    import simplejson as json
except ImportError:
    import json
import socket
import string
import sys

from base64 import b64encode

def usage():
    sys.stderr.write("""Check_MK AppDynamics special agent

USAGE: agent_appdynamics [OPTIONS] HOST APPLICATION

ARGUMENTS:
  HOST                          The AppDynamics host
  APPLICATION                   The application to query

OPTIONS:
  -u, --user USERNAME           Login username
  -p, --password PASSWORD       Login password
  -P, --port PORT               TCP port to connect to (default: 8090)
  -t, --timeout SECONDS         Connection timeout (default: 30 seconds)
  -f FILENAME                   Read JSON from file FILENAME instead of socket
  -v, --verbose                 Be more verbose
  --debug                       Debug mode: let Python exceptions come through
  -h, --help                    Show this help message and exit
""")

short_options = 'u:p:P:t:f:hv'
long_options  = ['username=', 'password=', 'port=', 'timeout=', "filename=",
                 'help', 'verbose', 'debug' ]

opt_username = None
opt_password = None
opt_port     = 8090
opt_timeout  = 30
opt_verbose  = False
opt_debug    = False
opt_filename = None

try:
    opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
except getopt.GetoptError, err:
    sys.stderr.write('%s\n' % err)
    sys.exit(1)

for o, a in opts:
    if o in [ '-h', '--help' ]:
        usage()
        sys.exit(0)
    elif o in [ '-u', '--username' ]:
        opt_username = a
    elif o in [ '-p', '--password' ]:
        opt_password = a
    elif o in [ '-f', '--filename' ]:
        opt_filename = a
    elif o in [ '-P', '--port']:
        try:
            opt_port = int(a)
            if opt_port < 1 or opt_port > 65534:
                raise ValueError
        except ValueError:
            sys.stderr.write('Port is not a valid integer in range 1-65534\n')
            sys.exit(1)
    elif o in [ '-t', '--timeout' ]:
        try:
            opt_timeout = int(a)
        except ValueError:
            sys.stderr.write('Timeout is not a valid integer\n')
            sys.exit(1)
    elif o in [ '-v', '--verbose' ]:
        opt_verbose = True
    elif o in [ '--debug' ]:
        opt_debug = True

if len(args) < 2:
    sys.stderr.write('Too few arguments\n')
    usage()
    sys.exit(1)
else:
    arg_host, arg_application = args[0:2]

if opt_filename:
    try:
        data = json.loads(file(opt_filename).read())
    except Exception, e:
        sys.stderr.write("Cannot read JSON data from file %s: %s\n" % (opt_filename, e))
        if opt_debug:
            raise
        sys.exit(1)

else:
    url = '/controller/rest/applications/%(application)s/metric-data' \
          '?metric-path=Application%%20Infrastructure%%20Performance|*|Individual%%20Nodes|*|%(object)s|*|*' \
          '&time-range-type=BEFORE_NOW&duration-in-mins=1&output=json'

    socket.setdefaulttimeout(opt_timeout)

    data = []

    # Initialize server connection
    try:
        connection = httplib.HTTPConnection(arg_host, opt_port)

        if opt_verbose:
            sys.stdout.write('Connecting to %s:%s...\n' % (arg_host, opt_port))
        connection.connect()

        auth = b64encode('%s:%s' % (opt_username, opt_password))
        headers = { 'Authorization': 'Basic ' + auth }
        for obj in ['Agent', '*|*']:
            connection.request('GET', url % { 'application': arg_application, 'object': obj }, headers = headers)
            response = connection.getresponse()

            if response.status != 200:
                sys.stderr.write('Could not fetch data from AppDynamics server. '
                                 'HTTP %s: %s\n' % (response.status, response.reason))
                sys.exit(1)

            data += json.loads(response.read())

    except Exception, e:
        sys.stderr.write('Cannot connect to AppDynamics server. %s\n' % e)
        if opt_debug:
            raise
        sys.exit(1)

grouped_data = {}
for metric in data:
    path_parts = metric['metricPath'].split('|')
    if len(path_parts) == 7: # Unit missing
        path_parts.append('')

    base, application, section, node, provider, typename, item, unit = path_parts

    try:
        value = metric['metricValues'][0]['current']
    except IndexError:
        continue # Skip empty values

    if provider not in ('Agent', 'JMX', 'JVM'):
        continue # Skip unwanted values

    grouped_data.setdefault(node, {})\
                .setdefault(application, {})\
                .setdefault(typename, {})\
                .setdefault(item, {})[unit] = value

for node, applications in grouped_data.iteritems():
    sys.stdout.write('<<<<%s>>>>\n' % node)
    for application, types in applications.iteritems():
        for typename, items in types.iteritems():
            typename = typename.lower().replace(' ', '_')
            if typename in ['app', 'memory', 'sessions', 'web_container_runtime']:
                sys.stdout.write('<<<appdynamics_%s:sep(124)>>>\n' % (typename.replace("_runtime", "")))
                for item, values in items.iteritems():
                    if values:
                        output_items = [application, item]
                        for name, value in values.iteritems():
                            if not name:
                                output_items.append('%s' % value)
                            else:
                                output_items.append('%s:%s' % (name, value))
                        sys.stdout.write('|'.join(output_items) + '\n')
sys.stdout.write('<<<<>>>>\n')
