#!/usr/bin/python

#-------------------------------------------------------------------------------
#
#   Copyright (C) 2017 Cumulus Networks, Inc. All rights reserved
#
#   This software is subject to the Cumulus Networks End User License
#   Agreement available  at the following locations:
#
#   Internet: https://cumulusnetworks.com/downloads/eula/latest/view/
#   Cumulus Linux systems: /usr/share/cumulus/EULA.txt
#
#-------------------------------------------------------------------------------

"""
This daemon handles everything related to a chassis running Cumulus Linux.
"""

#-------------------------------------------------------------------------------
#
#   Import the necessary modules
#
#-------------------------------------------------------------------------------

try:
    import argparse
    import chassisd.chassisd_accton
    import chassisd.chassisd_cmdsrv
    import cumulus.chassis
    import logging
    import logging.handlers
    import signal
    import sys
    import threading
except ImportError, e:
    raise ImportError (str(e) + "- required module not found")

#-------------------------------------------------------------------------------
#
#   Global Variables
#
#-------------------------------------------------------------------------------

# The handle used for logging messages
logger = logging.getLogger("cumulus-chassisd")

# stopEvent is set when we should exit.
stopEvent = threading.Event()

# Class instances within cumulus-chassisd
actchd = None
cmdsrv = None

# The return code - assume the worst
retVal = 1

#-------------------------------------------------------------------------------
#
#   Functions
#
#-------------------------------------------------------------------------------

def ParseCmdLine():
    """
    Parse the command line options using the standard argparse library.
    """
    # The default values for the arguments
    _DEFAULT_LOG_LEVEL          = "WARNING"

    parser = argparse.ArgumentParser(description="The Cumulus Linux Chassis Daemon")
    parser.add_argument("--loglevel", "-l", default=_DEFAULT_LOG_LEVEL,
                        help="The logging level for output")
    parser.add_argument("--noAcctonChassisd", action="store_true",
                        help="Don't start the Accton Chassisd")
    parser.add_argument("--noCmdSrv", action="store_true",
                        help="Don't start the command line interface")
    args, cmdline = parser.parse_known_args()
    return(args, cmdline)

def InitLogging(cmdargs):
    """
    Set up the logging according to the command line parameters provided.
    """
    facility = logging.handlers.SysLogHandler.LOG_DAEMON
    handler = logging.handlers.SysLogHandler(address="/dev/log", facility=facility)
    formatter = logging.Formatter("cumulus-chassisd[%(process)d]: %(message)s", None)
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    logLevel = getattr(logging, cmdargs.loglevel.upper(), None)
    if not isinstance(logLevel, int):
        raise ValueError("Invalid log level: %s" % cmdargs.loglevel)
        exit(-1)
    logger.setLevel(logLevel)

def SignalHandler(signum, frame):
    """
    Handles any signals registered for and received while code is running.
    """
    global retVal
    if signum in [signal.SIGTERM, signal.SIGINT]:
        retVal = 0
        stopEvent.set()

#-------------------------------------------------------------------------------
#
#   The Main Program
#
#-------------------------------------------------------------------------------

def main():
    global actchd
    global cmdsrv

    # Parse the command line parameters and initialize logging.
    cmdargs, cmdline = ParseCmdLine()
    InitLogging(cmdargs)
    logger.info("Beginning execution of cumulus-chassisd")

    # Get a chassis object for this chassis
    try:
        chassis = cumulus.chassis.probe()
    except (ImportError, RuntimeError, AssertionError) as e:
        logger.error("Unable to determine chassis type: %s" % (e,))

    # Start the accton chassisd on an Accton chassis.
    if chassis.GetChassisName() == "accton_omp800" and not cmdargs.noAcctonChassisd:
        actchd = chassisd.chassisd_accton.chassisd_accton(chassis, cmdline, stopEvent)
        cmdline = actchd.cmdline

    # Start the command line interface server
    if not cmdargs.noCmdSrv:
        cmdsrv = chassisd.chassisd_cmdsrv.chassisd_cmdsrv(chassis, cmdline, stopEvent, actchd)
        cmdline = cmdsrv.cmdline

    # Wait until we exit
    while not stopEvent.wait(24*60*60):
        pass

    # Signal threads to stop and wait until they do
    modules = [mod for mod in [actchd, cmdsrv] if mod is not None]
    for mod in modules:
        mod.SignalThreads()
    for mod in modules:
        mod.JoinThreads()

    # Get out of here
    logger.info("cumulus-chassisd shutdown is complete")
    sys.exit(retVal)


if __name__ == '__main__':
    signal.signal(signal.SIGTERM, SignalHandler)
    signal.signal(signal.SIGINT, SignalHandler)
    main()

