Commit 1e3a7beb authored by Thibault VINCENT's avatar Thibault VINCENT
Browse files

console logging + daemonize option

parent 71e26b4b
Loading
Loading
Loading
Loading
+68 −39
Original line number Diff line number Diff line
@@ -5,22 +5,17 @@ from optparse import OptionParser
from sjrpc.core import RpcError
from ccnode.ccnode import CCNode
import ConfigParser
import sys
import sys, os, atexit
import logging
import logging.handlers
import signal
import threading
from daemon import DaemonContext
from time import sleep
from math import exp

try:
    import daemon
    DAEMONIZE = True
except ImportError:
    DAEMONIZE = False

from ccnode import __version__

MAX_AUTH_TIMEOUT = 10
DEFAULT_CONFIG_FILE = '/etc/cc-node.conf'
DEFAULT_PID_FILE = '/var/run/cc-node.pid'
DEFAULT_CONFIGURATION = {
@@ -35,8 +30,6 @@ DEFAULT_CONFIGURATION = {
    'force_xen' : 'no',
}

MAX_AUTH_TIMEOUT = 10

def run_node(options):
    '''
    '''
@@ -53,45 +46,48 @@ def run_node(options):

    logger = logging.getLogger()
    logger.setLevel(level)
    if options['stdout']:
        handler = logging.StreamHandler()
    else:
        facility = logging.handlers.SysLogHandler.LOG_DAEMON
        handler = logging.handlers.SysLogHandler(address='/dev/log',
                                                            facility=facility)
    fmt = logging.Formatter('cc-node: %(levelname)s %(message)s')
    handler.setFormatter(fmt)
    handler.setFormatter(logging.Formatter('cc-node: %(levelname)s %(message)s')
                                                                            )
    logger.handlers = []
    logger.addHandler(handler)
    
    # setup SIGINT handler
    # setup SIGINT/SIGTERM handler
    def shutdown_handler(signum, frame):
        '''
        Handler called when SIGINT emited
        Handler called when SIGINT/SIGTERM emited
        '''
        logging.info('SIGINT received, node shutdown in progress')
        logging.error('Letal signal received, node shutdown in progress')
        try:
            '''
            #FIXME REGRESSION
            if node:
                logging.debug('Closing server connection')
                node.manager.shutdown()
            '''
            pass
        except:
            pass
        sys.exit(0)
        finally:
            os._exit(1)
    
    # register SIGINT and SIGTERM handler
    signal.signal(signal.SIGINT, shutdown_handler)
    signal.signal(signal.SIGTERM, shutdown_handler)
    
    # re-authentication thread
    def authentication(node):
        timeout = 1
        while node:
            if node.get_manager().is_running():
                logging.debug('Sending authentication request')
                result = node.authentify(options['login'], options['password'])
                if result:
                    logging.info('Authentication suscessfull')
                logging.info('Sending authentication request')
                if node.authentify(options['login'], options['password']):
                    logging.error('Authentication suscessfull')
                    return
                else:
                    logging.error('Authentication failure')
                    timeout += 0.1
                    if timeout >= MAX_AUTH_TIMEOUT:
                        timeout = MAX_AUTH_TIMEOUT
@@ -101,46 +97,48 @@ def run_node(options):
    none = None
    auth_thread = None
    try:
        logging.info('Initializing node client')
        logging.error('Initializing node client')
        try:
            node = CCNode(options['address'], int(options['port']),
                          options['detect_hypervisor'] == 'yes',
                          options['command_execution'] == 'yes',
                          force_xen=(options['force_xen'] == 'yes'))
        except Exception as err:
            logging.critical('Client initialization failure: `%s`:`%s`'
                                                            % (repr(err), err))
            logging.error('Client initialization failure: `%s`:`%s`', repr(err),
                                                                            err)
            raise err
        
        # start main loop and auth thread
        logging.debug('Starting authentication thread')
        logging.info('Starting authentication thread')
        auth_thread = threading.Thread(target=authentication, args=(node,),
                                                                    name='Auth')
        auth_thread.daemon = True
        auth_thread.start()
        logging.debug('Starting node main loop')
        logging.info('Starting main loop')
        node.run()
    
    except Exception as err:
        logging.error('run_node: `%s` -> `%s`', repr(err), err)
        if auth_thread:
            del auth_thread
            auth_thread = None
        if node:
            node.manager.shutdown()
            del node
            node = None
    finally:
        return

if __name__ == '__main__':
    
    usage = 'usage: %prog [OPTION...]'
    op = OptionParser(usage, version='%%prog %s' % __version__)
    op = OptionParser(version='%%prog %s' % __version__)
    op.add_option('-c', '--config', default=DEFAULT_CONFIG_FILE,
                  help='configuration file (default: %default)')
    op.add_option('-d', '--daemonize', default=False, action='store_true',
                  help='run as daemon and write pid file')
    op.add_option('-p', '--pid-file', default=DEFAULT_PID_FILE,
    op.add_option('-p', '--pidfile', default=DEFAULT_PID_FILE,
                  help='pid file (default: %default)')
    op.add_option('-s', '--stdout', action='store_true', default=False,
                  help='log on standard output instead of syslog')
    
    cliopts, args = op.parse_args()
    
@@ -164,7 +162,38 @@ if __name__ == '__main__':
            else:
                options[opt] = default
    
    # Merge command options and .conf file options
    for opt in ('daemonize', 'pidfile', 'stdout'):
        if getattr(cliopts, opt) is not None:
            options[opt] = getattr(cliopts, opt)
    
    # Create option set for the daemonization process
    daemon_opts = {}
    daemonize = options['daemonize']
    if isinstance(daemonize, str):
        daemonize = daemonize in ('yes', 'true')
    daemon_opts['detach_process'] = daemonize
    if not daemonize:
        daemon_opts['stderr'] = sys.stderr
        daemon_opts['stdout'] = sys.stderr
    if options['pidfile']:
        #daemon_opts['pidfile'] = lockfile.FileLock(options['pidfile'])
        pidfile = open(cliopts.pidfile, 'w')
        daemon_opts['files_preserve'] = [pidfile]
    
    with DaemonContext(**daemon_opts):
        # write pid in pidfile
        if pidfile is not None:
            pidfile.write('%s' % os.getpid())
            pidfile.flush()
        # register pidfile cleaning
        @atexit.register
        def clean_pidfile():
            pidfile.seek(0)
            pidfile.truncate()
            pidfile.flush()
        # run node
        while True:
           run_node(options)
       logging.warning('Critical error, restarting node !')
           logging.critical('Critical error, restarting node !')
           sleep(2)
+1 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ Standards-Version: 3.9.1

Package: cc-node
Architecture: all
Depends: ${misc:Depends}, ${python:Depends}, python-sjrpc ( >= 8 ), python-psutil
Depends: ${misc:Depends}, ${python:Depends}, python-sjrpc ( >= 9 ), python-psutil, python-daemon
Recommends: python-libvirt
XB-Python-Version: ${python:Versions}
Description: CloudControl node
+6 −6
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="CloudControl node"
NAME=cc-node
DAEMON=/usr/bin/cc-node
DAEMON_ARGS=""
PIDFILE=/var/run/$NAME.pid
DAEMON_OPTS="-d -p $PIDFILE"

# Defaults:
USER=root
@@ -29,6 +29,7 @@ GROUP=root

# Load various rcS variables
. /lib/init/vars.sh

# Override the VERBOSE variable so we always have feedback messages
VERBOSE=yes

@@ -52,11 +53,10 @@ VERBOSE=yes
#
do_start()
{
    start-stop-daemon --start --quiet --background --name $NAME \
            --exec $(readlink -f $(which python)) --test > /dev/null || return 2
    start-stop-daemon --start --quiet --background --make-pidfile \
            --pidfile $PIDFILE --chuid $USER:$GROUP --exec $DAEMON \
            -- $DAEMON_OPTS || return 1
    start-stop-daemon --start --quiet --name $NAME --test \
            --exec $(readlink -f $(which python)) > /dev/null || return 2
    start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$GROUP \
            --exec $DAEMON -- $DAEMON_OPTS || return 1
}

#