#!/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.


def parse_docker_container_diskstat(info):
    version = docker_get_version(info)  # pylint: disable=undefined-variable
    if version is None:
        pre_parsed = _parse_docker_container_diskstat_agent(info)
    else:
        pre_parsed = _parse_docker_container_diskstat_plugin(info)

    disks = {}
    timestamp = pre_parsed["time"]

    for _device_id, device in pre_parsed["devices"].items():
        # Filter out unwanted things
        if device["name"].startswith("loop"):
            continue

        # Skip devices without counts
        if "ios" not in device or "bytes" not in device:
            continue

        disks[device["name"]] = timestamp, device

    return disks


def _parse_docker_container_diskstat_plugin(info):
    raw = docker_json_get_obj(info[1])

    devices = {}
    for major_minor, name in raw["names"].iteritems():
        major, minor = map(int, major_minor.split(':', 1))
        devices[(major, minor)] = {
            "name": name,
            "bytes": {},
            "ios": {},
        }

    for entry in raw["io_service_bytes_recursive"]:
        device = devices.get((entry["major"], entry["minor"]))
        if device:
            device["bytes"][entry["op"]] = entry["value"]

    for entry in raw["io_serviced_recursive"]:
        device = devices.get((entry["major"], entry["minor"]))
        if device:
            device["ios"][entry["op"]] = entry["value"]

    return {"time": raw["time"], "devices": devices}


def _parse_docker_container_diskstat_agent(info):
    sections = {}

    for line in info:

        if line[0] == "[io_service_bytes]":
            phase = "bytes"
        elif line[0] == "[io_serviced]":
            phase = "ios"
        elif line[0] == '[names]':
            phase = "names"
        elif line[0] == '[time]':
            phase = "time"
        else:
            if line[0] == "Total":
                continue

            if phase == "time":
                sections["time"] = int(line[0])
                continue

            devices = sections.setdefault("devices", {})

            if phase == "names":
                major, minor = map(int, line[1].split(":"))
            else:
                major, minor = map(int, line[0].split(":"))

            device_id = major, minor
            device = devices.setdefault(device_id, {})

            if phase == "names":
                device["name"] = line[0]
            else:
                device_phase = device.setdefault(phase, {})
                device_phase[line[1]] = int(line[2])

    return sections


def _prepare_diskdata(device_name, timestamp, device):
    # type: (str, str, int, dict) -> Tuple(bool, dict)
    uninitialized = False

    diskdata = {}
    counter_template = "diskstat.%s.%%s" % device_name

    for io_op in ('read', 'write'):
        for unit in ('ios', 'bytes'):
            key = "%s_%s" % (io_op, 'ios' if unit == 'ios' else 'throughput')
            try:
                diskdata[key] = get_rate(counter_template % key,
                                         timestamp,
                                         device[unit][io_op.title()],
                                         onwrap=RAISE)
            except KeyError:
                # KeyError: Containers counters are not initialized
                #           (may be because disk is not *ever* used by container)
                pass
            except MKCounterWrapped:
                # MKCounterWrapped: Checkmk counter is not initialized
                uninitialized = True

    return uninitialized, diskdata


def check_docker_container_diskstat(item, params, parsed):
    disks = {}
    uninitialized = False
    for device_name, (timestamp, device) in parsed.items():

        this_uninitialized, diskdata = _prepare_diskdata(device_name, timestamp, device)
        uninitialized = uninitialized or this_uninitialized

        # omit empty disks
        if diskdata:
            disks[device_name] = diskdata

    if uninitialized or not disks:
        raise MKCounterWrapped("")

    return check_diskstat_dict(item, params, disks)


check_info["docker_container_diskstat"] = {
    "parse_function": parse_docker_container_diskstat,
    "inventory_function": lambda parsed: inventory_diskstat_generic([(None, key)
                                                                     for key in parsed]),
    "check_function": check_docker_container_diskstat,
    "service_description": "Disk IO %s",
    "has_perfdata": True,
    "group": "diskstat",
    "includes": ["docker.include", "diskstat.include"],
}
