#!/usr/bin/python3
# Copyright (C) 2020-2021 NVIDIA Corporation. ALL RIGHTS RESERVED.
# Copyright 2017 Cumulus Networks Inc, all rights reserved
#
# ASIC monitor tool
#
#
#
#
#
#
#

import sys
import signal
import argparse
import getopt
import os
import re
import subprocess
import json
import math
import time
import logging
import logging.handlers
import traceback
import cumulus.datapath_utils

# initialize the global logger
global logger
logger  = logging.getLogger('asic-monitor')
fmt     = logging.Formatter(fmt='%(name)s %(levelname)s: %(message)s')
handler = logging.handlers.SysLogHandler('/dev/log')
handler.setFormatter(fmt)
logger.setLevel(logging.INFO)
logger.addHandler(handler)

if cumulus.datapath_utils.is_platform_vx():
    logger.info('ASIC monitor is not supported on VX')
    sys.exit(0)

from cumulus.asic_monitor import AsicMonitor
from cumulus.asic_monitor import exitEvent
from cumulus.asic_monitor import process_exit_status
from cumulus.hft_collector import HFTCollector

SIGNALS_TO_NAMES_DICT = dict((getattr(signal, n), n) \
                                 for n in dir(signal) if n.startswith('SIG') and '_' not in n )

monitor   = None
collector = None
# ----------------------------------------------------------
#
def handle_signal(signal_number, frame):
    global collector
    signal_label = SIGNALS_TO_NAMES_DICT.get(signal_number,
                                             'Unnamed signal: %d' % signal_number)
    logger.info('received signal %s' % signal_label)
    if signal_number == signal.SIGUSR1:
        signal_handler.toggle_log = True
    elif signal_number == signal.SIGUSR2:
        signal_handler.collect_debug = True
    elif signal_number == signal.SIGHUP:
        collector.hft_config_change_event.set()
    elif signal_number == signal.SIGTERM:
        if exitEvent is None:
            do_exit()
        else:
            exitEvent.set()
        signal_handler.sigterm_flag = True
    else:
        signal_handler.exit_flag = True

# ==========================================================
#
class SignalHandler(object):
    def __init__(self, signal_list):
        super(SignalHandler,self).__init__()
        self.exit_flag = False
        self.sigterm_flag = False
        self.toggle_log = False
        self.collect_debug = False
        for signal_number in signal_list:
            signal.signal(signal_number, handle_signal)


global signal_handler
# contingency planning
signal_handler = SignalHandler([signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGUSR1, signal.SIGUSR2])

# -------------------------------------------------
#
# check to see if an instance is already running
#
def already_running(pidfile):
    myname=os.path.basename(sys.argv[0])
    try:
        if not os.path.isfile(pidfile):
            return False
        oldpid = re.findall('\D*(\d+).*', (open(pidfile, 'r').readline()))[0]
        if not os.path.exists('/proc/%s' % oldpid):
            return False
        if myname not in open('/proc/%s/cmdline' % oldpid, 'r').readline():
            return False
        sys.stderr.write("%s already running as process %s\n" % (myname, oldpid))
        return True
    except Exception as e:
        logger.error("unable to validate pidfile %s: %s" % (pidfile, str(e)))


# ----------------------------------------------------------
#
def do_exit():
    global monitor
    global collector
    if monitor:
        monitor.JoinThreads()
    if collector:
        collector.JoinThreads()

    logger.info('Asic-monitor service exited with exit_status %d' % (cumulus.asic_monitor.process_exit_status))
    sys.exit(cumulus.asic_monitor.process_exit_status)


# ----------------------------------------------------------
#
def main(argv) :
    pidfile = "/var/run/asic-monitor.pid"
    if already_running(pidfile):
        sys.exit(0)
    else:
        open(pidfile, 'w').write(str(os.getpid()))
    exit_flag = False

    global monitor
    global collector
    # create the asic monitor
    monitor = AsicMonitor(signal_handler)
    if monitor == None:
        logger.error('monitor object was not created')
        return

    collector = HFTCollector(signal_handler)
    if collector == None:
        logger.error('collector object was not created')
        return

   # Take the day off
    while not exitEvent.wait(60*60*24):
        pass

    do_exit()

# ----------------------------------------------------------
#
#                        e n t r y
#
# ----------------------------------------------------------

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



