#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2014             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.

import os
import errno
import sys
import getopt
import subprocess


def agent_ipmi_sensors_usage():
    sys.stderr.write("""Check_MK IPMI Sensors

USAGE: agent_ipmi_sensors [OPTIONS] HOST
       agent_ipmi_sensors --help

ARGUMENTS:
  HOST                              Host name or IP address

OPTIONS:
  --help                            Show this help message and exit.
  --debug                           Debug output
  --ipmi-command IPMI-CMD           Possible values are 'freeipmi' or 'ipmitool'.
                                    If no command is specified 'freeipmi' is used.
  -u USER                           Username
  -p PASSWORD                       Password
  -l LEVEL                          Privilege level
                                    Possible are 'user', 'operator', 'admin'

FreeIPMI OPTIONS:
  -D DRIVER                         Specify IPMI driver.
  --quiet-cache                     Do not output information about cache creation/deletion.
  --sdr-cache-recreate              Automatically recreate the sensor data repository (SDR) cache.
  --interpret-oem-data              Attempt to interpret OEM data.
  --output-sensor-state             Output sensor state in output.
  --ignore-not-available-sensors    Ignore not-available (i.e. N/A) sensors in output.
  --driver-type DRIVER-TYPE         Specify the driver type to use instead of doing an auto selection.
  --output-sensor-thresholds        Output sensor thresholds in output.
  -k KEY                            Specify the K_g BMC key to use when authenticating
                                    with the remote host for IPMI 2.0.
""")


def parse_data(data, excludes):
    for line in data:
        if line.startswith("ID"):
            continue
        elif excludes:
            has_excludes = False
            for exclude in excludes:
                if exclude in line:
                    has_excludes = True
                    break
            if not has_excludes:
                sys.stdout.write("%s\n" % line)
        else:
            sys.stdout.write("%s\n" % line)


def agent_ipmi_sensors_main(cmdline_args):
    short_options = 'u:p:l:D:k:'
    long_options = [
        'help', 'debug', 'ipmi-command=', 'quiet-cache', 'sdr-cache-recreate', 'interpret-oem-data',
        'output-sensor-state', 'ignore-not-available-sensors', 'driver-type=',
        'output-sensor-thresholds'
    ]

    opt_debug = False
    hostname = None
    username = None
    password = None
    privilege_lvl = None
    ipmi_cmd_type = None

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

    additional_opts = []
    for o, a in opts:
        if o in ['--help']:
            agent_ipmi_sensors_usage()
            sys.exit(0)
        elif o in ['--debug']:
            opt_debug = True

        # Common options
        elif o in ['--ipmi-command']:
            ipmi_cmd_type = a
        elif o in ['-u']:
            username = a
        elif o in ['-p']:
            password = a
        elif o in ['-l']:
            privilege_lvl = a

        # FreeIPMI options
        elif o in ['-D']:
            additional_opts += ["%s" % o, "%s" % a]
        elif o in ['--driver-type']:
            additional_opts += ["%s=%s" % (o, a)]
        elif o in ['-k']:
            additional_opts += ["%s" % o, "%s" % a]
        elif o in ['--quiet-cache']:
            additional_opts.append(o)
        elif o in ['--sdr-cache-recreate']:
            additional_opts.append(o)
        elif o in ['--interpret-oem-data']:
            additional_opts.append(o)
        elif o in ['--output-sensor-state']:
            additional_opts.append(o)
        elif o in ['--ignore-not-available-sensors']:
            additional_opts.append(o)
        elif o in ['--output-sensor-thresholds']:
            additional_opts.append(o)

    if len(args) == 1:
        hostname = args[0]
    else:
        sys.stderr.write("ERROR: Please specify exactly one host.\n")
        sys.exit(1)

    if not (username and password and privilege_lvl):
        sys.stderr.write("ERROR: Credentials are missing.\n")
        sys.exit(1)

    os.environ["PATH"] = "/usr/local/sbin:/usr/sbin:/sbin:" + os.environ["PATH"]

    if ipmi_cmd_type in [None, 'freeipmi']:
        ipmi_cmd = [ "ipmi-sensors",
                     "-h", hostname, "-u", username,
                     "-p", password, "-l", privilege_lvl ] + \
                     additional_opts
        queries = {"_sensors": ([], [])}
    elif ipmi_cmd_type == 'ipmitool':
        ipmi_cmd = ["ipmitool", "-H", hostname, "-U", username, "-P", password, "-L", privilege_lvl]
        # As in check_mk_agent
        queries = {
            "": (["sensor", "list"], ['command failed', 'discrete']),
            "_discrete": (["sdr", "elist", "compact"], [])
        }

    else:
        sys.stderr.write("ERROR: Unknown IPMI command '%s'.\n" % ipmi_cmd_type)
        sys.exit(1)

    ipmi_cmd_str = subprocess.list2cmdline(ipmi_cmd)

    if opt_debug:
        sys.stderr.write("Executing: '%s'\n" % ipmi_cmd_str)

    errors = []
    for section, (types, excludes) in queries.iteritems():
        sys.stdout.write("<<<ipmi%s:sep(124)>>>\n" % section)
        try:
            try:
                p = subprocess.Popen(ipmi_cmd + types,
                                     shell=False,
                                     close_fds=True,
                                     stdin=open(os.devnull),
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
            except OSError, e:
                if e.errno == errno.ENOENT:  # No such file or directory
                    raise Exception("Could not find '%s' command (PATH: %s)"\
                                    % (ipmi_cmd_type, os.environ.get("PATH")))
                else:
                    raise

            stdout, stderr = p.communicate()
            if stderr:
                errors.append(stderr)
            parse_data(stdout.splitlines(), excludes)
        except Exception, e:
            errors.append(e)

    if errors:
        sys.stderr.write("ERROR: '%s'.\n" % ", ".join(errors))
        sys.exit(1)

    sys.exit(0)


if __name__ == "__main__":
    agent_ipmi_sensors_main(sys.argv[1:])
