#! /usr/bin/python3 -sP
#
# -*- coding: utf-8 -*-
# vim: ts=4 sw=4 tw=100 et ai si
#
# Copyright (C) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
# Authors: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>

"""
This is a wrapper over the ipmitool utility which helps collecting the IPMI statistics. This wrapper
periodically makes a snapshot of the IPMI statistics and prints them to the standard output.
"""

# pylint: disable=invalid-name

import sys
import time
import logging
import argparse
from pepclibs.helperlibs import Logging, ArgParse, LocalProcessManager
from pepclibs.helperlibs.Exceptions import Error

VERSION = "1.0"
OWN_NAME = "ipmi-helper"

LOG = logging.getLogger()
Logging.setup_logger(prefix=OWN_NAME)

def parse_arguments():
    """A helper function which parses the input arguments."""

    text = sys.modules[__name__].__doc__
    parser = ArgParse.ArgsParser(description=text, prog=OWN_NAME, ver=VERSION)

    text = "The IP address or host name of the BMC."
    parser.add_argument("--host", metavar="HOST", help=text)

    text = "How many times to retry in case of failure, default is 2."
    parser.add_argument("--retries", help=text, type=int, default=2)

    text = "How many snapshots to make, default is 0 (unlimited)."
    parser.add_argument("--count", help=text, type=int, default=0)

    text = "The interval between snapshots in seconds, default is 5."
    parser.add_argument("--interval", help=text, type=float, default=5)

    text = "IPMI user name (will be passed to 'ipmitool -U'). Default is 'root'."
    parser.add_argument("-U", "--user", help=text)

    text = "IPMI password (will be passed to 'ipmitool -P'). Default is \"no password\"."
    parser.add_argument("-P", "--password", help=text)

    # This is a hidden option which makes 'ipmi-helper' print paths to its dependencies and exit.
    parser.add_argument("--print-module-paths", action="store_true", help=argparse.SUPPRESS)
    return parser.parse_args()

def print_module_paths():
    """
    Print paths to all modules other than standard.
    """

    for mobj in sys.modules.values():
        path = getattr(mobj, "__file__", None)
        if not path:
            continue

        if not path.endswith(".py"):
            continue
        if not "pepclibs/" in path:
            continue

        print(path)

def main():
    """Script entry point."""

    args = parse_arguments()

    if (args.user or args.password) and not args.host:
        raise Error("please, specify the host: '--user' and '--password' require '--host'")

    if args.print_module_paths:
        print_module_paths()
        return 0

    if args.host and not args.user:
        args.user = "root"

    cmd = "ipmitool"
    if args.host:
        cmd += f" -I lanplus -H '{args.host}'"
    if args.user:
        cmd += f" -U '{args.user}'"
    if args.password:
        cmd += f" -P '{args.password}'"
    cmd += " sdr list full"

    with LocalProcessManager.LocalProcessManager() as pman:
        if not args.host:
            # Make sure the IPMI Linux kernel modules are loaded.
            pman.run_verify("modprobe ipmi_devintf")
            pman.run_verify("modprobe ipmi_si")

        interval = delta = args.interval
        retries = count = 0

        while True:
            start = time.time()
            try:
                output, _ = pman.run_verify(cmd)
            except Error:
                if retries >= args.retries:
                    # Too many failures.
                    raise
                retries += 1
                continue
            else:
                LOG.info("timestamp | %s", time.strftime("%Y_%m_%d_%T", time.localtime(start)))
                LOG.info(output)
                retries = 0
                delta = time.time() - start
            finally:
                if delta < interval:
                    time.sleep(interval-delta)

            if args.count:
                count += 1
                if count >= args.count:
                    break

# The very first script entry point."""
if __name__ == "__main__":
    try:
        sys.exit(main())
    except KeyboardInterrupt:
        LOG.error_out("interrupted, exiting")
    except Error as err:
        LOG.error_out(err, print_tb=True)
