#! /usr/bin/python3.7
# Copyright (C) 2018-2021 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

import daemon
from cue import config, main
import argparse
import logging
import logging.handlers
import os
import signal
import faulthandler


# On SIGSEGV, SIGFPE, SIGABRT, SIGBUS, and SIGILL signals, dump stack.  A bit
# more useful than just a core dump.
faulthandler.enable()

# Also, dump core on a SIGUSR1.  This is useful when debugging a deadlock.
faulthandler.register(signal.SIGUSR1)


# Parse our arguments
parser = argparse.ArgumentParser(description="cued: management daemon")
parser.add_argument("-d", "--daemon",
                    help="run as a daemon",
                    action="store_true")
parser.add_argument("--debug",
                    help="log DEBUG messages",
                    action="store_true")
args = parser.parse_args()


def logger_init_syslog(loglevel):
    # Set the log level for the root logger.
    logging.getLogger().setLevel(loglevel)

    syslog_h = logging.handlers.SysLogHandler(address="/dev/log")
    formatter = logging.Formatter("cued: %(levelname)7s:  %(message)s")
    syslog_h.setFormatter(formatter)
    syslog_h.setLevel(loglevel)
    logging.getLogger().addHandler(syslog_h)


def logger_init_local(loglevel):
    logging.basicConfig(
        level=loglevel,
        format="%(asctime)s %(levelname)7s: %(name)s: %(message)s")

    # Color the errors and warnings in red.
    logging.addLevelName(
        logging.ERROR,
        "\033[91m  {0}\033[0m".format(logging.getLevelName(logging.ERROR)))
    logging.addLevelName(
        logging.WARNING,
        "\033[91m{0}\033[0m".format(logging.getLevelName(logging.WARNING)))

    # Set to the requested level.
    logging.getLogger().setLevel(loglevel)


# Initialize the root logger.
try:
    loglevel = logging.DEBUG if args.debug else logging.INFO
    if config.CUE_DEBUG:
        loglevel = logging.DEBUG

    if args.daemon:
        # In daemon mode, log to syslog
        logger_init_syslog(loglevel)
    else:
        # Otherwise, log to stdout
        logger_init_local(loglevel)

    logger = logging.getLogger()
    logger.info("Starting cued")

    logger.info(
        "CUE logging set to %s, chatty deps set to %s",
        logging.getLevelName(loglevel),
        logging.getLevelName(logging.INFO)
    )

    # Some of our deps are a bit too chatty in DEBUG
    logging.getLogger("connexion").setLevel(logging.INFO)
    if loglevel == logging.DEBUG:
        logging.getLogger("sh").setLevel(logging.INFO)
    else:
        logging.getLogger("sh").setLevel(logging.WARN)


except Exception as e:
    exit("Unable to set up logging:\n{0}\n".format(e))


# Make sure we have a working directory
if os.path.isdir(config.WORKING_DIRECTORY):
    # The working directory already exists, but somebody could
    # have changed its permissions. Run chmod to be sure.
    os.chmod(config.WORKING_DIRECTORY, config.WORKING_DIRECTORY_PERMISSIONS)
else:
    try:
        os.makedirs(config.WORKING_DIRECTORY,
                    mode=config.WORKING_DIRECTORY_PERMISSIONS)
    except OSError as e:
        logger.error("Cannot create working directory")
        exit(str(e))


# Tell main it's OK to import units now.
main.prepare()


# Start it up
if args.daemon:
    # Run cued in the background.
    context = daemon.DaemonContext(
        working_directory=config.WORKING_DIRECTORY,
        signal_map={
            signal.SIGTERM: main.stop,
            signal.SIGINT: main.stop,
            signal.SIGHUP: main.restart,
        },
        umask=0o22
    )

    context.open()
    with context:
        main.start()

else:
    # Run cued in the foreground.
    signal.signal(signal.SIGINT, main.stop)
    signal.signal(signal.SIGTERM, main.stop)
    signal.signal(signal.SIGHUP, main.restart)
    main.start()
