<reponame>rcmelendez/devo-lapua-docker<gh_stars>0
# -*- coding: utf-8 -*-
import socket
import json
from utils.constants import STATUS, KO_MESSAGE, LAPUA_VERSION, OK_MESSAGE
from utils.config import get_config
import readline
import argparse
from devo.common import Configuration, get_log, set_formatter, \
    get_rotating_file_handler
from devo.sender import Sender
import logging
from datetime import datetime
import time
import psutil
import subprocess


def get_logger(path=None, conf=None, name=None):
    """
    gets the logger with the format
    :param path: path to file logging
    :param conf: conf file
    :param name: process name
    :return: the logger
    """
    f = "%(asctime)s|%(levelname)s|" + name + "|" + \
        "|%(process)d|%(thread)d|%(filename)s|%(funcName)s|%(message)s"

    file_handler = get_rotating_file_handler(path=path,
                                             file_name="{}.log".format(name),
                                             msg_format=f,
                                             max_size=2097152,
                                             backup_count=5)

    logger = get_log(name=name, level=logging.INFO, handler=file_handler)
    try:
        con = Sender.for_logging(config=conf)
    except Exception as error:
        logger.error(error)
        raise Exception("Review 'log_sender' params in configuration file")

    con.setFormatter(set_formatter(f))
    logger.addHandler(con)
    if conf.get("console", False):
        logger.addHandler(__get_console_handler(f))

    return logger


def __get_config():
    """
    Reads the config from input.
    :return: the configuration in the file
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--config',
                        help="Configuration file", required=True)
    args = parser.parse_args()
    print("Reading config ", args.config)
    log_conf = Configuration()
    log_conf.load_config(args.config)
    return log_conf


def __get_console_handler(f):
    """
    Adds the console handler to the logger
    :param f: format
    :return:
    """
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(logging.Formatter(f))
    return console_handler


def __receive():
    size = __SOCKET.recv(8).decode('utf-8')
    return __SOCKET.recv(int(size)).decode('utf-8')


def __run_job(job_name):
    __LOG.info("STARTING JOB: {}".format(job_name))
    __SOCKET.send(
        json.dumps({"command": "run", "data": job_name}).encode('utf-8'))
    resp_start = __receive()
    if resp_start.startswith(OK_MESSAGE):
        __LOG.info("JOB {} SUCCESSFULLY STARTED".format(job_name))
    else:
        __LOG.info("ERROR STARTING JOB: {}".format(job_name))
    __receive()


def __quit():
    __SOCKET.send(
        json.dumps({"command": "quit", "data": None}).encode('utf-8'))
    __SOCKET.close()


def __check_jobs():
    __SOCKET.send(
        json.dumps({"command": "list", "data": "*"}).encode('utf-8'))
    resp = __receive()
    if resp == KO_MESSAGE:
        __LOG.error('Error listing jobs. Launch exception to manage '
                    'server status')
        raise Exception('Error listing jobs.')
    else:
        status = json.loads(resp)
        running_jobs = []
        stopped_jobs = []
        for k, v in status.items():
            k = k.replace('.json', '')
            if v == STATUS.RUNNING:
                running_jobs.append(k)
            else:
                stopped_jobs.append(k)
        __LOG.info('RUNNING {} jobs: [{}]'
                   .format(len(running_jobs), running_jobs))
        __LOG.info('STOPPED {} jobs: [{}]'
                   .format(len(stopped_jobs), stopped_jobs))
    if len(stopped_jobs) and __MONITOR_CONF.get('jobs').get('run_all'):
        for job in stopped_jobs:
            job_name = job.split('(')[0].strip()
            __run_job(job_name)


def __find_lapua_process():
    launch_command = __MONITOR_CONF.get("server").get("launch_command")
    for p in psutil.process_iter():
        try:
            if "python" in p.name() and \
                    launch_command.split(' ') == p.cmdline():
                __LOG.info("Process found: {} with pid {} username {}. "
                           "Memory used {}% Total threads: {}"
                           .format(launch_command, p.pid, p.username(),
                                   p.memory_percent(), p.num_threads()))
                return p
        except Exception as ex:
            __LOG.warning("no privileges for: {} user {} - Error: {}"
                          .format(p.pid, p.username(), ex))
    return None


def __launch_lapua():
    launch_command = __MONITOR_CONF.get("server").get("launch_command")
    cwd = __MONITOR_CONF.get("server").get("cwd", '.')
    __LOG.info("Starting lapua: {} at {}".format(launch_command, cwd))
    try:
        sp = subprocess.Popen(launch_command.split(' '), cwd=cwd)
        __LOG.info("Executed lapua: {} at {}. Return code: {} PID: {}"
                   .format(launch_command, cwd, sp.returncode, sp.pid))
    except Exception as ex:
        __LOG.error("ERROR LAUNCHING LAPUA INSTANCE: {}".format(ex))


if __name__ == '__main__':
    __SLEEP_SECS = 60
    __MONITOR_CONF = __get_config()
    __NAME = __MONITOR_CONF['name']
    __LOG = get_logger(path=__MONITOR_CONF['logging'].get('path', './'),
                       conf=__MONITOR_CONF['logging'],
                       name=__NAME)
    __LOG.info("Init main loop Lapua Monitor")
    attempts = 0
    while True:
        try:
            start = datetime.now()
            __LOG.info("Init Lapua server validation")
            connected = False
            try:
                __LOG.info("Reading server config: {}".format(
                    __MONITOR_CONF.get("server").get("config_file")))
                __SERVER_CONF = get_config(
                    __MONITOR_CONF.get("server").get("config_file"))
                __LOG.info("Trying to connect to: {}:{}"
                           .format(__SERVER_CONF['server']['address'],
                                   __SERVER_CONF['server']['port']))
                __SOCKET = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                __SOCKET.connect((__SERVER_CONF['server']['address'],
                                  __SERVER_CONF['server']['port']))
                readline.set_completer_delims(' \t\n')
                __LOG.info("Connected to: {}:{}"
                           .format(__SERVER_CONF['server']['address'],
                                   __SERVER_CONF['server']['port']))
                __check_jobs()
                __LOG.info("Disconnect from: {}:{}"
                           .format(__SERVER_CONF['server']['address'],
                                   __SERVER_CONF['server']['port']))
                __quit()
                attempts = 0
                connected = True
                lapua_p = __find_lapua_process()
                if lapua_p is None:
                    __LOG.error("Connected by client but process not found")
            except Exception as excpt:
                __LOG.error("Error: {}".format(excpt))
                __LOG.info("Error with client searching for process")
                lapua_p = __find_lapua_process()
                if lapua_p:
                    attempts += 1
                    __LOG.info("Process found: {} Attempts: {}"
                               .format(lapua_p, attempts))
                    if attempts >= 10:
                        __LOG.error("LAPUA CLIENT UNABLE TO CONNECT AFTER: {} "
                                    "ATTEMPTS, KILLING PROCESS {}"
                                    .format(attempts, lapua_p.pid))
                        attempts = 0
                        lapua_p.kill()
                        __launch_lapua()
                else:
                    __LOG.info("LAPUA NOT FOUND RUNNING. STARTING NEW SERVER")
                    __launch_lapua()

            diff_seconds = (datetime.now() - start).total_seconds()
            if diff_seconds < __SLEEP_SECS:
                __LOG.info("Sleeping: {} seconds"
                           .format(__SLEEP_SECS-diff_seconds))
                time.sleep(__SLEEP_SECS-
                           (datetime.now() - start).total_seconds())
        except Exception as excpt:
            __LOG.error("Error in main loop: {}".format(excpt))

# -*- coding: utf-8 -*-
import socket
import json
from utils.constants import STATUS, KO_MESSAGE, LAPUA_VERSION, OK_MESSAGE
from utils.config import get_config
import readline
import argparse
from devo.common import Configuration, get_log, set_formatter, \
    get_rotating_file_handler
from devo.sender import Sender
import logging
from datetime import datetime
import time
import psutil
import subprocess


def get_logger(path=None, conf=None, name=None):
    """
    gets the logger with the format
    :param path: path to file logging
    :param conf: conf file
    :param name: process name
    :return: the logger
    """
    f = "%(asctime)s|%(levelname)s|" + name + "|" + \
        "|%(process)d|%(thread)d|%(filename)s|%(funcName)s|%(message)s"

    file_handler = get_rotating_file_handler(path=path,
                                             file_name="{}.log".format(name),
                                             msg_format=f,
                                             max_size=2097152,
                                             backup_count=5)

    logger = get_log(name=name, level=logging.INFO, handler=file_handler)
    try:
        con = Sender.for_logging(config=conf)
    except Exception as error:
        logger.error(error)
        raise Exception("Review 'log_sender' params in configuration file")

    con.setFormatter(set_formatter(f))
    logger.addHandler(con)
    if conf.get("console", False):
        logger.addHandler(__get_console_handler(f))

    return logger


def __get_config():
    """
    Reads the config from input.
    :return: the configuration in the file
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--config',
                        help="Configuration file", required=True)
    args = parser.parse_args()
    print("Reading config ", args.config)
    log_conf = Configuration()
    log_conf.load_config(args.config)
    return log_conf


def __get_console_handler(f):
    """
    Adds the console handler to the logger
    :param f: format
    :return:
    """
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(logging.Formatter(f))
    return console_handler


def __receive():
    size = __SOCKET.recv(8).decode('utf-8')
    return __SOCKET.recv(int(size)).decode('utf-8')


def __run_job(job_name):
    __LOG.info("STARTING JOB: {}".format(job_name))
    __SOCKET.send(
        json.dumps({"command": "run", "data": job_name}).encode('utf-8'))
    resp_start = __receive()
    if resp_start.startswith(OK_MESSAGE):
        __LOG.info("JOB {} SUCCESSFULLY STARTED".format(job_name))
    else:
        __LOG.info("ERROR STARTING JOB: {}".format(job_name))
    __receive()


def __quit():
    __SOCKET.send(
        json.dumps({"command": "quit", "data": None}).encode('utf-8'))
    __SOCKET.close()


def __check_jobs():
    __SOCKET.send(
        json.dumps({"command": "list", "data": "*"}).encode('utf-8'))
    resp = __receive()
    if resp == KO_MESSAGE:
        __LOG.error('Error listing jobs. Launch exception to manage '
                    'server status')
        raise Exception('Error listing jobs.')
    else:
        status = json.loads(resp)
        running_jobs = []
        stopped_jobs = []
        for k, v in status.items():
            k = k.replace('.json', '')
            if v == STATUS.RUNNING:
                running_jobs.append(k)
            else:
                stopped_jobs.append(k)
        __LOG.info('RUNNING {} jobs: [{}]'
                   .format(len(running_jobs), running_jobs))
        __LOG.info('STOPPED {} jobs: [{}]'
                   .format(len(stopped_jobs), stopped_jobs))
    if len(stopped_jobs) and __MONITOR_CONF.get('jobs').get('run_all'):
        for job in stopped_jobs:
            job_name = job.split('(')[0].strip()
            __run_job(job_name)


def __find_lapua_process():
    launch_command = __MONITOR_CONF.get("server").get("launch_command")
    for p in psutil.process_iter():
        try:
            if "python" in p.name() and \
                    launch_command.split(' ') == p.cmdline():
                __LOG.info("Process found: {} with pid {} username {}. "
                           "Memory used {}% Total threads: {}"
                           .format(launch_command, p.pid, p.username(),
                                   p.memory_percent(), p.num_threads()))
                return p
        except Exception as ex:
            __LOG.warning("no privileges for: {} user {} - Error: {}"
                          .format(p.pid, p.username(), ex))
    return None


def __launch_lapua():
    launch_command = __MONITOR_CONF.get("server").get("launch_command")
    cwd = __MONITOR_CONF.get("server").get("cwd", '.')
    __LOG.info("Starting lapua: {} at {}".format(launch_command, cwd))
    try:
        sp = subprocess.Popen(launch_command.split(' '), cwd=cwd)
        __LOG.info("Executed lapua: {} at {}. Return code: {} PID: {}"
                   .format(launch_command, cwd, sp.returncode, sp.pid))
    except Exception as ex:
        __LOG.error("ERROR LAUNCHING LAPUA INSTANCE: {}".format(ex))


if __name__ == '__main__':
    __SLEEP_SECS = 60
    __MONITOR_CONF = __get_config()
    __NAME = __MONITOR_CONF['name']
    __LOG = get_logger(path=__MONITOR_CONF['logging'].get('path', './'),
                       conf=__MONITOR_CONF['logging'],
                       name=__NAME)
    __LOG.info("Init main loop Lapua Monitor")
    attempts = 0
    while True:
        try:
            start = datetime.now()
            __LOG.info("Init Lapua server validation")
            connected = False
            try:
                __LOG.info("Reading server config: {}".format(
                    __MONITOR_CONF.get("server").get("config_file")))
                __SERVER_CONF = get_config(
                    __MONITOR_CONF.get("server").get("config_file"))
                __LOG.info("Trying to connect to: {}:{}"
                           .format(__SERVER_CONF['server']['address'],
                                   __SERVER_CONF['server']['port']))
                __SOCKET = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                __SOCKET.connect((__SERVER_CONF['server']['address'],
                                  __SERVER_CONF['server']['port']))
                readline.set_completer_delims(' \t\n')
                __LOG.info("Connected to: {}:{}"
                           .format(__SERVER_CONF['server']['address'],
                                   __SERVER_CONF['server']['port']))
                __check_jobs()
                __LOG.info("Disconnect from: {}:{}"
                           .format(__SERVER_CONF['server']['address'],
                                   __SERVER_CONF['server']['port']))
                __quit()
                attempts = 0
                connected = True
                lapua_p = __find_lapua_process()
                if lapua_p is None:
                    __LOG.error("Connected by client but process not found")
            except Exception as excpt:
                __LOG.error("Error: {}".format(excpt))
                __LOG.info("Error with client searching for process")
                lapua_p = __find_lapua_process()
                if lapua_p:
                    attempts += 1
                    __LOG.info("Process found: {} Attempts: {}"
                               .format(lapua_p, attempts))
                    if attempts >= 10:
                        __LOG.error("LAPUA CLIENT UNABLE TO CONNECT AFTER: {} "
                                    "ATTEMPTS, KILLING PROCESS {}"
                                    .format(attempts, lapua_p.pid))
                        attempts = 0
                        lapua_p.kill()
                        __launch_lapua()
                else:
                    __LOG.info("LAPUA NOT FOUND RUNNING. STARTING NEW SERVER")
                    __launch_lapua()

            diff_seconds = (datetime.now() - start).total_seconds()
            if diff_seconds < __SLEEP_SECS:
                __LOG.info("Sleeping: {} seconds"
                           .format(__SLEEP_SECS-diff_seconds))
                time.sleep(__SLEEP_SECS-
                           (datetime.now() - start).total_seconds())
        except Exception as excpt:
            __LOG.error("Error in main loop: {}".format(excpt))
# -*- coding: utf-8 -*- gets the logger with the format     :param path: path to file logging     :param conf: conf file     :param name: process name     :return: the logger Reads the config from input.     :return: the configuration in the file Adds the console handler to the logger     :param f: format     :return: