Example #1
0
    def __init__(self, app):
        """ Set up the parameters of a new runner.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem
              paths to open and replace the existing `sys.stdin`,
              `sys.stdout`, `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that
              will be used as the PID file for the daemon. If
              ``None``, no PID file will be used.

            * `pidfile_timeout`: Used as the default acquisition
              timeout value supplied to the runner's PID lock file.

            * `run`: Callable that will be invoked when the daemon is
              started.
            
            """
        self.parse_args()
        self.app = app
        self.daemon_context = DaemonContext()
        self.daemon_context.stdin = open(app.stdin_path, 'r')
        self.daemon_context.stdout = open(app.stdout_path, 'w+')
        self.daemon_context.stderr = open(
            app.stderr_path, 'w+', buffering=0)

        self.pidfile = None
        if app.pidfile_path is not None:
            self.pidfile = make_pidlockfile(
                app.pidfile_path, app.pidfile_timeout)
        self.daemon_context.pidfile = self.pidfile
Example #2
0
    def open(self):
        # Call super
        DaemonContext.open(self)

        # Needfuls.doit()
        self.logger.info('Initializing...')

        # RPC connection
        self.connection = Connection(self.config['rpchost'])

        self.logger.info('Loading plugins...')
        # Import and create plugin objects
        self.plugins = [
            plugin(self.connection, self.config, self.logger.handler)
            for plugin in [
                getattr(
                    __import__(
                        'rpcdaemon.plugins.' + module.lower(),
                        fromlist=[module]
                    ),
                    module)
                for module in self.config['plugins'].split()
            ]
        ]

        # Setup worker with plugins and crank it up
        self.logger.info('Starting worker...')
        self.worker = Worker(self.connection, self.plugins,
                             handler=self.logger.handler)
        self.worker.daemon = True  # Daemon thread
        self.worker.start()
        self.logger.info('Started.')
Example #3
0
 def __init__(self, context: DaemonContext = None):
     if context is None:
         raise TypeError('__init__() requires a DaemonContext when called'
                         ' for the first time')
     self._initialized = True
     # Set daemon as active until stopped
     self._active = True
     # Read daemon config
     self._conf = Config('/etc/libreeye/')
     # Configure logging
     os.makedirs(os.path.dirname(self._conf.daemon_logfile), exist_ok=True)
     logging.basicConfig(level=logging.DEBUG,
                         format=('[%(asctime)s] %(threadName)s - '
                                 '%(filename)s:%(lineno)d: %(message)s'),
                         datefmt='%d/%m %H:%M:%S',
                         filename=self._conf.daemon_logfile)
     # Configure DaemonContext
     context.signal_map = {signal.SIGTERM: self.terminate}
     context.stdout = logging.root.handlers[0].stream
     context.stderr = logging.root.handlers[0].stream
     # Create sched
     self._sched = sched.scheduler(time.time, time.sleep)
     # Process dict
     self._cameras = {
         name: {
             'running': False
         }
         for name in self._conf.cameras
     }
     # Storage list
     self._storage = dict()
     self._storage['local'] = LocalStorage(self._conf.storage.local)
     if self._conf.storage.youtube is not None:
         self._storage['youtube'] = YoutubeStorage(
             self._conf.storage.youtube)
Example #4
0
    def __init__(self, app):
        """ Set up the parameters of a new runner.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem
              paths to open and replace the existing `sys.stdin`,
              `sys.stdout`, `sys.stderr`.

            * `pidfile_path`: Filesystem path to a file that will be
              used as the PID file for the daemon.

            * `run`: Callable that will be invoked when the daemon is
              started.
            
            """
        self.parse_args()
        self.app = app
        self.daemon_context = DaemonContext()
        self.daemon_context.stdin = open(app.stdin_path, 'r')
        self.daemon_context.stdout = open(app.stdout_path, 'w+')
        self.daemon_context.stderr = open(
            app.stderr_path, 'w+', buffering=0)

        self.pidfile = make_pidlockfile(app.pidfile_path)
        self.daemon_context.pidfile = self.pidfile
Example #5
0
    def start(self, command, config, instances, pid, queue_size, frequency, identification):
        '''
        Handles the Wishbone start command.
        '''

        config = self.config.load(config)
        self.pid = PIDFile(pid)

        if instances == 1:
            print ("Starting 1 instance to background with pid %s." % (os.getpid()))
            try:
                with DaemonContext(stdout=sys.stdout, stderr=sys.stderr, files_preserve=self.__getCurrentFD(), detach_process=True):
                    self.pid.create([os.getpid()])
                    instance = RouterBootstrap(config, debug=False, queue_size=queue_size, frequency=frequency, identification=identification)
                    instance.start()
            except Exception as err:
                sys.stdout.write("Failed to start instance.  Reason: %s\n" % (err))
        else:
            try:
                print "Starting %s instances in background." % (instances)
                with DaemonContext(stdout=sys.stdout, stderr=sys.stderr, files_preserve=self.__getCurrentFD(), detach_process=True):
                    pids = []
                    processes = []
                    for counter in xrange(instances):
                        processes.append(RouterBootstrapProcess(config, debug=False, queue_size=queue_size, frequency=frequency, identification=identification))
                        processes[-1].start()
                        pids.append(processes[-1].pid)
                    self.pid.create(pids)
                    for process in processes:
                        process.join()

            except Exception as err:
                sys.stdout.write("Failed to start instance.  Reason: %s\n" % (err))
def daemonise():
    from daemon import DaemonContext
    from pidfile import PidFile
    daemon = DaemonContext(pidfile=PidFile("/var/run/doorbot.pid"))
    daemon.open()

    logging.info('Daemonised doorbot')
Example #7
0
def get_daemon_context(config: KaztronConfig):
    import os
    import pwd
    import grp
    from pathlib import Path

    from daemon import DaemonContext, pidfile

    bot_dir = Path(sys.modules['__main__'].__file__).resolve().parent
    pid = pidfile.TimeoutPIDLockFile(config.get('core', 'daemon_pidfile'))
    daemon_log = open(config.get('core', 'daemon_log'), 'w+')
    daemon_context = DaemonContext(
        working_directory=str(bot_dir),
        umask=0o002,
        pidfile=pid,
        stdout=daemon_log,
        stderr=daemon_log
    )
    username = config.get('core', 'daemon_user', None)
    group = config.get('core', 'daemon_group', None)
    if username:
        pw = pwd.getpwnam(username)
        daemon_context.uid = pw.pw_uid
        daemon_context.gid = pw.pw_gid
        os.environ['HOME'] = pw.pw_dir
    if group:
        daemon_context.gid = grp.getgrnam(group).gr_gid
    return daemon_context
Example #8
0
    def __daemon(self):
        """
        Daemonizes the process; returns a non-zero exit code in case of failure.
        """

        # Daemonize
        try:
            # Create and check PID file
            oPidLockFile = make_pidlockfile(self.__oArguments.pid, 0)
            if is_pidfile_stale(oPidLockFile):
                oPidLockFile.break_lock()
            if oPidLockFile.is_locked():
                sys.stderr.write(
                    'ERROR[Daemon]: Daemon process already running; PID=%s\n' %
                    oPidLockFile.read_pid())
                return errno.EEXIST

            # Create daemon context
            oDaemonContext = DaemonContext(pidfile=oPidLockFile)
            oDaemonContext.signal_map = {signal.SIGTERM: self.__signal}
            oDaemonContext.open()
            emit_message('[%s]' % os.getpid())

            # Redirect standard error to syslog
            syslog.openlog('LogWatcher', syslog.LOG_PID, syslog.LOG_DAEMON)
            sys.stderr = Logger(self.__syslog)

            # Execute
            return self.__spawnWatchers(self.__oConfigObj)
        except Exception as e:
            sys.stderr.write(
                'ERROR[Daemon]: Failed to fork to background; %s\n' % str(e))
            return errno.ESRCH
Example #9
0
    def __daemon(self):
        """
        Daemonizes the process; returns a non-zero exit code in case of failure.
        """

        # Daemonize
        try:
            # Create and check PID file
            oPidLockFile = make_pidlockfile(self.__oArguments.pid, 0)
            if is_pidfile_stale(oPidLockFile):
                oPidLockFile.break_lock()
            if oPidLockFile.is_locked():
                iPid = oPidLockFile.read_pid()
                logger.error(f"daemon: Process already running; PID={iPid}")
                return errno.EEXIST

            # Create daemon context
            oDaemonContext = DaemonContext(pidfile=oPidLockFile)
            oDaemonContext.signal_map = {signal.SIGTERM: self.__signal}
            oDaemonContext.open()
            emit_message(f"daemon: Forked to background; PID={os.getpid()}")

            # Redirect standard error to syslog
            oHandler = SysLogHandler(address="/dev/log")
            oHandler.setLevel(logger.level)
            oHandler.setFormatter(
                logging.Formatter(
                    "%(name)s[%(process)d]: %(levelname)s: %(message)s"))
            logger.addHandler(oHandler)

            # Execute
            return self.__updater()
        except Exception as e:
            logger.error(f"daemon: Failed to fork to background; {str(e)}")
            return errno.ESRCH
Example #10
0
def daemonise():
    from daemon import DaemonContext
    from pidfile import PidFile
    daemon = DaemonContext(pidfile=PidFile("/var/run/doorbot.pid"))
    daemon.open()

    logging.info('Daemonised doorbot')
Example #11
0
def start(logging_config, daemon_config, seneschal_config):
    syslog.openlog('seneschal', 0, syslog.LOG_USER)
    engine = Engine(seneschal_config)
    pidfile, daemon_options = check_daemon_options(daemon_config)
    if is_pidfile_stale(pidfile):
        syslog.syslog(syslog.LOG_NOTICE, 'breaking stale PID file')
        pidfile.break_lock()
    # The remaining entries in daemon_options will be passed as-is to
    # daemon.DaemonContext.
    context = DaemonContext(pidfile=pidfile, **daemon_options)
    context.signal_map = make_signal_map()
    syslog.syslog(syslog.LOG_NOTICE, 'starting daemon context')
    try:
        with context:  # Will fail if daemon already running
            pid = os.getpid()
            syslog.syslog(syslog.LOG_NOTICE, 'daemon running as: %s' % pid)
            config_logging(logging_config)
            logger.debug('========================================')
            logger.info('daemon running pid=%s', pid)
            logger.debug('args: %r', sys.argv)
            logger.debug('daemon_options: %r', daemon_options)
            logger.debug('seneschal_config: %r', seneschal_config)
            while Engine.running:
                engine.sweep()
                time.sleep(1)
                # TODO: Long polling times, may result in an unacceptable
                # delay during daemon shutdown.
    except Exception as e:
        syslog.syslog(syslog.LOG_ERR, str(e))
        logger.exception(repr(e))
        raise
    finally:
        syslog.syslog(syslog.LOG_NOTICE, 'exiting')
        logger.info('exiting')
Example #12
0
def transfer(app, transfer_job_id):
    transfer_job = app.get_transfer_job(transfer_job_id)
    if transfer_job is None:
        log.error('Invalid transfer job ID: %s' % transfer_job_id)
        return False
    port_range = app.config.get('app:main', 'transfer_worker_port_range')
    try:
        port_range = [int(p) for p in port_range.split('-')]
    except Exception as e:
        log.error('Invalid port range set in transfer_worker_port_range: %s: %s' % (port_range, str(e)))
        return False
    protocol = transfer_job.params['protocol']
    if protocol not in ('http', 'https', 'scp'):
        log.error('Unsupported protocol: %s' % protocol)
        return False
    state_result = StateResult(result=dict(state=transfer_job.states.RUNNING, info='Transfer process starting up.'))
    listener_server = ListenerServer(range(port_range[0], port_range[1] + 1), ListenerRequestHandler, app, transfer_job, state_result)
    # daemonize here (if desired)
    if not debug:
        daemon_context = DaemonContext(files_preserve=[listener_server.fileno()], working_directory=os.getcwd())
        daemon_context.open()
        # If this fails, it'll never be detected.  Hopefully it won't fail since it succeeded once.
        app.connect_database()  # daemon closed the database fd
        transfer_job = app.get_transfer_job(transfer_job_id)
    listener_thread = threading.Thread(target=listener_server.serve_forever)
    listener_thread.setDaemon(True)
    listener_thread.start()
    # Store this process' pid so unhandled deaths can be handled by the restarter
    transfer_job.pid = os.getpid()
    app.sa_session.add(transfer_job)
    app.sa_session.flush()
    terminal_state = None
    if protocol in ['http', 'https']:
        for transfer_result_dict in http_transfer(transfer_job):
            state_result.result = transfer_result_dict
            if transfer_result_dict['state'] in transfer_job.terminal_states:
                terminal_state = transfer_result_dict
    elif protocol in ['scp']:
        # Transfer the file using scp
        transfer_result_dict = scp_transfer(transfer_job)
        # Handle the state of the transfer
        state = transfer_result_dict['state']
        state_result.result = transfer_result_dict
        if state in transfer_job.terminal_states:
            terminal_state = transfer_result_dict
    if terminal_state is not None:
        transfer_job.state = terminal_state['state']
        for name in ['info', 'path']:
            if name in terminal_state:
                transfer_job.__setattr__(name, terminal_state[name])
    else:
        transfer_job.state = transfer_job.states.ERROR
        transfer_job.info = 'Unknown error encountered by transfer worker.'
    app.sa_session.add(transfer_job)
    app.sa_session.flush()
    return True
Example #13
0
def transfer( app, transfer_job_id ):
    transfer_job = app.get_transfer_job( transfer_job_id )
    if transfer_job is None:
        log.error( 'Invalid transfer job ID: %s' % transfer_job_id )
        return False
    port_range = app.config.get( 'app:main', 'transfer_worker_port_range' )
    try:
        port_range = [ int( p ) for p in port_range.split( '-' ) ]
    except Exception as e:
        log.error( 'Invalid port range set in transfer_worker_port_range: %s: %s' % ( port_range, str( e ) ) )
        return False
    protocol = transfer_job.params[ 'protocol' ]
    if protocol not in ( 'http', 'https', 'scp' ):
        log.error( 'Unsupported protocol: %s' % protocol )
        return False
    state_result = StateResult( result=dict( state=transfer_job.states.RUNNING, info='Transfer process starting up.' ) )
    listener_server = ListenerServer( range( port_range[0], port_range[1] + 1 ), ListenerRequestHandler, app, transfer_job, state_result )
    # daemonize here (if desired)
    if not debug:
        daemon_context = DaemonContext( files_preserve=[ listener_server.fileno() ], working_directory=os.getcwd() )
        daemon_context.open()
        # If this fails, it'll never be detected.  Hopefully it won't fail since it succeeded once.
        app.connect_database()  # daemon closed the database fd
        transfer_job = app.get_transfer_job( transfer_job_id )
    listener_thread = threading.Thread( target=listener_server.serve_forever )
    listener_thread.setDaemon( True )
    listener_thread.start()
    # Store this process' pid so unhandled deaths can be handled by the restarter
    transfer_job.pid = os.getpid()
    app.sa_session.add( transfer_job )
    app.sa_session.flush()
    terminal_state = None
    if protocol in [ 'http', 'https' ]:
        for transfer_result_dict in http_transfer( transfer_job ):
            state_result.result = transfer_result_dict
            if transfer_result_dict[ 'state' ] in transfer_job.terminal_states:
                terminal_state = transfer_result_dict
    elif protocol in [ 'scp' ]:
        # Transfer the file using scp
        transfer_result_dict = scp_transfer( transfer_job )
        # Handle the state of the transfer
        state = transfer_result_dict[ 'state' ]
        state_result.result = transfer_result_dict
        if state in transfer_job.terminal_states:
            terminal_state = transfer_result_dict
    if terminal_state is not None:
        transfer_job.state = terminal_state[ 'state' ]
        for name in [ 'info', 'path' ]:
            if name in terminal_state:
                transfer_job.__setattr__( name, terminal_state[ name ] )
    else:
        transfer_job.state = transfer_job.states.ERROR
        transfer_job.info = 'Unknown error encountered by transfer worker.'
    app.sa_session.add( transfer_job )
    app.sa_session.flush()
    return True
Example #14
0
class DaemonRunner(object):
    def __init__(self, app, outpath=None):
        self.daemon_context = DaemonContext()
        self.app = app
        if outpath:
            self.daemon_context.stdout = open(outpath, 'a')

    def start(self):
        self.daemon_context.open()
        self.app.run()
        status()
Example #15
0
    def actionStartFCGI(self):
        from flup.server.fcgi import WSGIServer
        from daemon import DaemonContext
        from lockfile import FileLock
        from os import getpid

        ctx = DaemonContext(working_directory=".", pidfile=FileLock("/tmp/wl-fcgi"))
        ctx.stderr = open("error.log", "w+")
        with ctx:
            open("wl-fcgi.pid", "w").write(str(getpid()))
            WSGIServer(app, bindAddress="fcgi.sock", umask=0000).run()
Example #16
0
    def close(self):
        # We might get called more than once, or before worker exists
        if self.is_open and self.worker and self.worker.is_alive():
            self.logger.info('Stopping worker...')
            self.worker.should_stop = True
            self.worker.join(5)  # Wait up to 5 seconds
            if self.worker.is_alive():
                self.logger.warn(
                    'Error stopping worker. Shutting down uncleanly.'
                )
            self.logger.info('Stopped.')

        DaemonContext.close(self)
Example #17
0
    def open( self ):

        self.files_preserve =\
            list( tuple(self.files_preserve) + tuple( logger.handler.stream for logger in self.loggers ) )
        _DaemonContext.open( self )
        gevent.reinit()

        ## not reliable w/ gevent, unfortunateley .. use stderr redirect instead
        #log = logging.getLogger('UNHANDLED')
        #sys.excepthook = lambda tp, value, tb:\
        #    log.error( ''.join( traceback.format_exception( tp, value, tb ) ) )

        gevent.signal(signal.SIGTERM, self.run_exit_hooks, signal.SIGTERM, None )
Example #18
0
    def __init__(self, app, action):  # RNC
        """ Set up the parameters of a new runner.

            :param app: The application instance; see below.
            :return: ``None``.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem paths
              to open and replace the existing `sys.stdin`, `sys.stdout`,
              `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that will
              be used as the PID file for the daemon. If ``None``, no PID
              file will be used.

            * `pidfile_timeout`: Used as the default acquisition timeout
              value supplied to the runner's PID lock file.

            * `run`: Callable that will be invoked when the daemon is
              started.

            """
        # RNC modification
        self.action = action  # RNC
        if action not in self.action_funcs:  # RNC
            raise ValueError("Bad action: {} (permitted: {})".format(
                action, '|'.join(self.action_funcs.keys())))

        self.app = app
        self.daemon_context = DaemonContext()
        # !!! would need to deal with sudo here
        self.daemon_context.stdin = open(app.stdin_path, 'rt')
        console = '/dev/tty'
        # RNC hacks for /dev/tty
        if app.stdout_path == console:
            self.daemon_context.stdout = open(
                app.stdout_path, 'w+b', buffering=0)
        else:
            self.daemon_context.stdout = open(app.stdout_path, 'w+t')
        if app.stderr_path == console:
            self.daemon_context.stderr = open(
                app.stderr_path, 'w+b', buffering=0)
        else:
            self.daemon_context.stderr = open(
                    app.stderr_path, 'w+t', buffering=0)
        self.pidfile = None
        if app.pidfile_path is not None:
            self.pidfile = make_pidlockfile(
                    app.pidfile_path, app.pidfile_timeout)
        self.daemon_context.pidfile = self.pidfile
Example #19
0
def start_daemon():
    daemon_context = DaemonContext(
        working_directory=settings.RUN_FILES,
        umask=settings.UMASK,
        pidfile=pidfile.TimeoutPIDLockFile(settings.PID_FILE),
    )

    daemon_context.signal_map = {
        signal.SIGTERM: cleanup,
        signal.SIGHUP: 'terminate',
    }

    with daemon_context:
        main(settings.LOG_FILE)
Example #20
0
    def open(self):

        self.files_preserve = \
            list(tuple(self.files_preserve) + tuple(logger.handler.stream for logger in self.loggers))
        _DaemonContext.open(self)
        gevent.reinit()

        ## not reliable w/ gevent, unfortunateley .. use stderr redirect instead
        # log = logging.getLogger('UNHANDLED')
        # sys.excepthook = lambda tp, value, tb:\
        #    log.error( ''.join( traceback.format_exception( tp, value, tb ) ) )

        gevent.signal(signal.SIGTERM, self.run_exit_hooks, signal.SIGTERM,
                      None)
Example #21
0
    def _daemonize(self, func, config):
        from daemon import DaemonContext
        try:
            from daemon.pidfile import TimeoutPIDLockFile as PIDLockFile
        except:
            from daemon.pidlockfile import PIDLockFile

        pidlock = PIDLockFile('/var/run/fedmsg/%s.pid' % self.name)
        output = file('/var/log/fedmsg/%s.log' % self.name, 'a')
        daemon = DaemonContext(pidfile=pidlock, stdout=output, stderr=output)
        daemon.terminate = self._handle_signal

        with daemon:
            return func(**config)
Example #22
0
    def _daemonize(self):
        from daemon import DaemonContext
        try:
            from daemon.pidfile import TimeoutPIDLockFile as PIDLockFile
        except:
            from daemon.pidlockfile import PIDLockFile

        pidlock = PIDLockFile('/var/run/fedmsg/%s.pid' % self.name)
        output = file('/var/log/fedmsg/%s.log' % self.name, 'a')
        daemon = DaemonContext(pidfile=pidlock, stdout=output, stderr=output)
        daemon.terminate = self._handle_signal

        with daemon:
            return self.run()
Example #23
0
    def _daemonize(self, func, config):
        from daemon import DaemonContext

        try:
            from daemon.pidfile import TimeoutPIDLockFile as PIDLockFile
        except:
            from daemon.pidlockfile import PIDLockFile

        pidlock = PIDLockFile("/var/run/fedmsg/%s.pid" % self.name)
        output = file("/var/log/fedmsg/%s.log" % self.name, "a")
        daemon = DaemonContext(pidfile=pidlock, stdout=output, stderr=output)
        daemon.terminate = self._handle_signal

        with daemon:
            return func(**config)
def main():
    """Daemonize and handle unexpected exceptions"""
    parser = argparse.ArgumentParser(
        description="Intel® Manager for Lustre* software Agent")
    parser.add_argument("--foreground", action="store_true")
    parser.add_argument("--publish-zconf", action="store_true")
    parser.add_argument("--pid-file", default="/var/run/chroma-agent.pid")
    args = parser.parse_args()

    # FIXME: at startup, if there is a PID file hanging around, find any
    # processes which are children of that old PID, and kill them: prevent
    # orphaned processes from an old agent run hanging around where they
    # could cause trouble (think of a 2 hour mkfs)

    if not args.foreground:
        if os.path.exists(args.pid_file):
            pid = None
            try:
                pid = int(open(args.pid_file).read())
                os.kill(pid, 0)
            except (ValueError, OSError, IOError):
                # Not running, delete stale PID file
                sys.stderr.write("Removing stale PID file\n")
                try:
                    os.remove(args.pid_file)
                    os.remove(args.pid_file + ".lock")
                except OSError, e:
                    import errno
                    if e.errno != errno.ENOENT:
                        raise e

                if pid is not None:
                    kill_orphans_of(pid)
            else:
                # Running, we should refuse to run
                raise RuntimeError("Daemon is already running (PID %s)" % pid)
        else:
            if os.path.exists(args.pid_file + ".lock"):
                sys.stderr.write("Removing stale lock file\n")
                os.remove(args.pid_file + ".lock")

        signal.signal(signal.SIGHUP, signal.SIG_IGN)
        context = DaemonContext(pidfile=PIDLockFile(args.pid_file))
        context.open()

        daemon_log_setup()
        console_log_setup()
        daemon_log.info("Starting in the background")
Example #25
0
def run_backend(opts):
    """
    Start main backend daemon

    :param opts: Munch object with command line options

    Expected **opts** fields:
        - `config_file` - path to the backend config file
        - `daemonize` - boolean flag to enable daemon mode
        - `pidfile` - path to the backend pidfile

        - `daemon_user`
        - `daemon_group`
    """
    cbe = None
    try:
        context = DaemonContext(
            pidfile=lockfile.FileLock(opts.pidfile),
            # gid=grp.getgrnam("copr").gr_gid,
            # uid=pwd.getpwnam("copr").pw_uid,
            gid=grp.getgrnam(opts.daemon_user).gr_gid,
            uid=pwd.getpwnam(opts.daemon_group).pw_uid,
            detach_process=opts.daemonize,
            umask=0o22,
            stderr=sys.stderr)
        with context:
            cbe = CoprBackend(opts.config_file, ext_opts=opts)
            cbe.run()
    except (Exception, KeyboardInterrupt):
        sys.stderr.write("Killing/Dying\n")
        raise
Example #26
0
def start(daemon=True, **kwargs):
    lock = PIDLockFile(os.path.join(RAMMON_PATH, "rammon.pid"))
    if lock.is_locked():
        try:
            Process(lock.read_pid())
            print("Rammon is already running")
            sys.exit(1)
        except NoSuchProcess:
            print(
                "Rammon was stopped, however it was stopped uncleanly leaving behind a pidfile.\n"
                "Breaking pidfile lock...")
            lock.break_lock()
    if daemon:
        logger.info("Starting rammon as a daemon...")
    else:
        logger.info("Starting rammon in the foreground...")

    if daemon:
        if try_systemd_start():
            logger.info("Starting with systemd...")
            sys.exit(0)
        else:
            mon = RamMonitor()
            set_handlers(mon)
            logger.info("Starting without systemd...")
            with DaemonContext(umask=0o077,
                               pidfile=lock,
                               detach_process=daemon):
                mon.start()
    else:
        with lock:
            mon = RamMonitor()
            set_handlers(mon)
            mon.start()
Example #27
0
    def start(self):
        '''Maps to the CLI command and starts one or more Wishbone processes in background.
        '''

        router_config = ConfigFile(self.config, 'SYSLOG').dump()
        pid_file = PIDFile(self.pid)

        with DaemonContext(stdout=sys.stdout,
                           stderr=sys.stderr,
                           detach_process=True):
            if self.instances == 1:
                sys.stdout.write("\nWishbone instance started with pid %s\n" %
                                 (os.getpid()))
                sys.stdout.flush()
                pid_file.create([os.getpid()])
                self.initializeRouter(router_config)
            else:
                for instance in range(self.instances):
                    self.routers.append(
                        gipc.start_process(self.initializeRouter,
                                           args=(router_config, ),
                                           daemon=True))

                pids = [str(p.pid) for p in self.routers]
                print(("\nInstances started in foreground with pid %s\n" %
                       (", ".join(pids))))
                pid_file.create(pids)

            self.bootstrapBlock()
Example #28
0
def main():
    options = parseOptions()

    if options.pidFile:
        from daemon import pidlockfile
        pidfile = pidlockfile.PIDLockFile(options.pidFile)
        try:
            pidfile.acquire(timeout=1.0)
            pidfile.release()
        except LockFailed:
            raise
    else:
        pidfile = None

    if options.daemonMode:
        from daemon import DaemonContext
        with DaemonContext(pidfile=pidfile,
                           working_directory=options.working_directory):
            run(options)
    else:
        if pidfile:
            with pidfile:
                run(options)
        else:
            run(options)
Example #29
0
    def handle(self, *args, **options):
        '''
        Handle management command processing.
        '''
        logger.info('Processing \'fulfill\' management command...')

        # Get command line arguments from 'options' dict.
        daemon = options['daemon']
        server = options['server'] or daemon
        tokens = options['order_tokens']

        logger.debug('Received the following arguments...')
        logger.debug(options)

        # Fulfill any orders specified on the command line.
        if tokens:
            self.fulfill_orders(tokens=tokens)

        # Enter the server loop if the '--server' option was specified.
        if server:
            # Set up SIGINT signal to call on ctrl-c.
            signal.signal(  # pragma: no cover
                signal.SIGINT, lambda sig, frame: self.exit_callback())

            # Initalize task queue.
            self.initialize_task_queue()

            # Begin server loop.
            if daemon:
                logger.info('Daemonizing server process...')
                with DaemonContext():
                    self.server_callback(*args, **options)
            else:
                self.server_callback(*args, **options)
    def execute(self, *args, **options):
        if options["daemon"]:
            pid_file = options["pid-file"]
            if os.path.exists(pid_file + ".lock") or os.path.exists(pid_file):
                try:
                    pid = int(open(pid_file).read())
                    os.kill(pid, 0)
                except (ValueError, OSError, IOError):
                    # Not running, delete stale PID file
                    sys.stderr.write("Removing stale PID file\n")
                    import errno

                    try:
                        os.remove(pid_file)
                    except OSError as e:
                        if e.errno != errno.ENOENT:
                            raise e
                    try:
                        os.remove(pid_file + ".lock")
                    except OSError as e:
                        if e.errno != errno.ENOENT:
                            raise e
                else:
                    # Running, we should refuse to run
                    raise RuntimeError("Daemon is already running (PID %s)" %
                                       pid)

            with DaemonContext(pidfile=PIDLockFile(pid_file)):
                self._execute_inner(*args, **options)
        else:
            self._execute_inner(*args, **options)
Example #31
0
def run_backend(opts):
    """
    Start main backend daemon

    :param opts: Bunch object with command line options

    Expected **opts** fields:
        - `config_file` - path to the backend config file
        - `daemonize` - boolean flag to enable daemon mode
        - `pidfile` - path to the backend pidfile

    """
    cbe = None
    try:
        context = DaemonContext(
            pidfile=lockfile.FileLock(opts.pidfile),
            gid=grp.getgrnam("copr").gr_gid,
            uid=pwd.getpwnam("copr").pw_uid,
            detach_process=opts.daemonize,
            umask=0o22,
            stderr=sys.stderr,
            signal_map={
                signal.SIGTERM: "terminate",
                signal.SIGHUP: "terminate",
            },
        )
        with context:
            cbe = CoprBackend(opts.config_file, ext_opts=opts)
            cbe.run()
    except (Exception, KeyboardInterrupt):
        sys.stderr.write("Killing/Dying\n")
        if cbe is not None:
            cbe.terminate()
        raise
Example #32
0
def main (interrupt=None):
  args = parser.parse_args()
  config = ConfigParser()
  dirname = os.path.dirname(os.path.realpath(sys.argv[0]))
  if args.config is None:
    configfile = None
    for afile in [ os.path.expanduser('~/.relaykeys.cfg'),
                    os.path.join(dirname, 'relaykeys.cfg') ]:
      if len(config.read([afile])) > 0:
        configfile = afile
        break
  else:
    if len(config.read([args.config])) == 0:
      raise ValueError("Could not read config file: {}".format(args.config))
    configfile = args.config
  if "server" not in config.sections():
    config["server"] = {}
  serverconfig = config["server"]
  if serverconfig.getboolean("rewritepasswordonce", False):
    serverconfig["password"] = mkpasswd(24, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
    del serverconfig["rewritepasswordonce"]
    if "client" in config.sections():
      config["client"]["password"] = serverconfig["password"]
    with open(configfile, "w") as f:
      config.write(f)
  isdaemon = args.daemon or serverconfig.getboolean("daemon", False) if os.name =='posix' else False
  if isdaemon:
    pidfile = os.path.realpath(args.pidfile or serverconfig.get("pidfile", None))
    with DaemonContext(working_directory=os.getcwd(),
                       pidfile=PIDLockFile(pidfile)):
      init_logger(dirname, True, args, serverconfig)
      return do_main(args, serverconfig, interrupt)
  else:
    init_logger(dirname, False, args, serverconfig)
    return do_main(args, serverconfig, interrupt)
Example #33
0
def daemonize(name, main):
    run_dir = user_data_dir + sep + 'run'
    pidf = pidlockfile.PIDLockFile(run_dir + sep + name + '.pid')
    pidf.acquire(timeout=1.0)
    pidf.release()
    with DaemonContext(pidfile=pidf):
        _main_wrapper(name, main)
Example #34
0
def daemonize(args, callback):
    with DaemonContext():
        create_process = False
        lock = Lock(LOCKFILE, os.getpid(), args.name, args.sea_ep[0],
                    args.sea_ep[1], args.port)
        if lock.is_locked():
            lock_pid = lock.get_pid()
            if not lock.is_same_file(args.name, args.sea_ep[0],
                                    args.sea_ep[1]) \
                    or not is_process_running(lock_pid):
                try:
                    os.kill(lock_pid, signal.SIGQUIT)
                except OSError:
                    pass
                except TypeError:
                    pass
                lock.break_lock()
                create_process = True
        else:
            create_process = True

        if create_process:
            lock.acquire()
            callback(args.name, season=args.sea_ep[0], episode=args.sea_ep[1],
                     serve=True, port=args.port)
            lock.release()
Example #35
0
def daemonize(args, callback):
    with DaemonContext():
        from touchandgo.logger import log_set_up
        log_set_up(True)
        log = logging.getLogger('touchandgo.daemon')
        log.info("running daemon")
        create_process = False
        lock = Lock(LOCKFILE, os.getpid(), args.name, args.sea_ep[0],
                    args.sea_ep[1], args.port)
        if lock.is_locked():
            log.debug("lock active")
            lock_pid = lock.get_pid()
            if not lock.is_same_file(args.name, args.sea_ep[0],
                                     args.sea_ep[1]) \
                    or not is_process_running(lock_pid):
                try:
                    log.debug("killing process %s" % lock_pid)
                    os.kill(lock_pid, signal.SIGQUIT)
                except OSError:
                    pass
                except TypeError:
                    pass
                lock.break_lock()
                create_process = True
        else:
            create_process = True

        if create_process:
            log.debug("creating proccess")
            lock.acquire()
            callback()
            lock.release()
        else:
            log.debug("same daemon process")
    def __init__(self, app):
        """ Set up the parameters of a new runner.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem
              paths to open and replace the existing `sys.stdin`,
              `sys.stdout`, `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that
              will be used as the PID file for the daemon. If
              ``None``, no PID file will be used.

            * `pidfile_timeout`: Used as the default acquisition
              timeout value supplied to the runner's PID lock file.

            * `run`: Callable that will be invoked when the daemon is
              started.
            
            """
        self.parse_args()
        self.app = app
        self.daemon_context = DaemonContext()
        self.daemon_context.stdin = open(app.stdin_path, 'r')
        self.daemon_context.stdout = open(app.stdout_path, 'w+')
        self.daemon_context.stderr = open(
            app.stderr_path, 'w+', buffering=0)

        self.pidfile = None
        if app.pidfile_path is not None:
            self.pidfile = make_pidlockfile(
                app.pidfile_path, app.pidfile_timeout)
        self.daemon_context.pidfile = self.pidfile
Example #37
0
 def start(self) -> None:
     """
     Starts the daemon.
     """
     if not self.__get_pid():
         with DaemonContext(pidfile=pidfile.PIDLockFile(self.__file_path),
                            working_directory=WADES_DIR_PATH):
             self.run()
Example #38
0
def start_server(config):
    weblogger = logging.getLogger('plight_httpd')
    weblogger.setLevel(config['web_log_level'])
    if weblogger.handlers == []:
        weblogging_handler = RotatingFileHandler(config['web_log_file'],
                                              mode='a',
                                              maxBytes=config['web_log_filesize'],
                                              backupCount=config['web_log_rotation_count'])
        weblogger.addHandler(weblogging_handler)

    applogger = logging.getLogger('plight')
    applogger.setLevel(config['log_level'])
    if applogger.handlers == []:
        applogging_handler = RotatingFileHandler(config['log_file'],
                                              mode='a',
                                              maxBytes=config['log_filesize'],
                                              backupCount=config['log_rotation_count'])
        applogger.addHandler(applogging_handler)

    pidfile = PIDLockFile(PID_FILE)
    context = DaemonContext(pidfile=pidfile,
                            uid=pwd.getpwnam(config['user']).pw_uid,
                            gid=grp.getgrnam(config['group']).gr_gid,
                            files_preserve = [
                                weblogging_handler.stream,
                                applogging_handler.stream,
                            ],)
    context.stdout = applogging_handler.stream
    context.stderr = applogging_handler.stream
    context.open()
    os.umask(0022)

    try:
        try:
            log_message('Plight is starting...')
            node_status = plight.NodeStatus(config['state_file'])
            server_class = BaseHTTPServer.HTTPServer
            http = server_class((config['host'],
                                 config['port']),
                                 plight.StatusHTTPRequestHandler)
            http.serve_forever()
        except SystemExit, sysexit:
            log_message("Stopping... " + str(sysexit))
        except Exception, ex:
            log_message("ERROR: " + str(ex))
Example #39
0
def run_as_daemon(ssm_inst):
    """
    Given an SSM object, start it as a daemon process.
    """
    log.info("The SSM will run as a daemon.")
    # We need to preserve the file descriptor for any log files.
    log_files = [x.stream for x in log.handlers]
    dc = DaemonContext(files_preserve=log_files)
    
    try:
        # Note: because we need to be compatible with python 2.4, we can't use
        # with dc:
        # here - we need to call the open() and close() methods 
        # manually.
        dc.open()
        try:
            ssm_inst.startup()
        except Exception, err:
            print err
            print type(err)
            print dir(err)
            log.info("SSM failed to start: " + str(err))
            raise
        
        # Only an exception will break this loop.
        # A SystemExit exception will be raised if the process is killed.
        while True:
            
            if ssm_inst.is_dead():
                raise ssm_inst.get_death_exception()
                
            # Process all the messages one at a time before continuing
            try:
                while ssm_inst.process_outgoing():
                    pass
            except ssm.SsmException, err:
                # SsmException if the message is rejected by the consumer.
                # We can wait and try again.
                log.error('Error in message processing: '+str(err))
            except EncryptException, err:
                # EncryptException if something went wrong trying to encrypt
                # or sign. Give up.
                log.error("Failed to encrypt or sign:" + str(err))
                raise
Example #40
0
    def __init__(self, redirect_output = '/tmp/ocsp_responder.log',
                 chroot = None,
                 detach = True,
                 pidfile = '/tmp/ocsp_responder.pid'):

        self.redirect_output = file(redirect_output, 'a')
        self.chroot = chroot
        self.detach = detach
        self.pidfile = pidfile

        if self.pidfile:
            self.pidfile = LockFile(pidfile)
        if not self.detach:
            self.redirect_output = sys.stdout

        DaemonContext.__init__(self,
                               stdout = self.redirect_output,
                               stderr = self.redirect_output,
                               detach_process = self.detach,
                               pidfile = self.pidfile)
Example #41
0
def start_server(config, node):
    weblogger = logging.getLogger('plight_httpd')
    weblogger.setLevel(config['web_log_level'])
    if weblogger.handlers == []:
        weblogging_handler = RotatingFileHandler(config['web_log_file'],
                                                 mode='a',
                                                 maxBytes=config[
                                                     'web_log_filesize'],
                                                 backupCount=config[
                                                     'web_log_rotation_count'])
        weblogger.addHandler(weblogging_handler)

    applogger = logging.getLogger('plight')
    applogger.setLevel(config['log_level'])
    if applogger.handlers == []:
        applogging_handler = RotatingFileHandler(
            config['log_file'],
            mode='a',
            maxBytes=config['log_filesize'],
            backupCount=config['log_rotation_count'])
        applogger.addHandler(applogging_handler)

    # if pidfile is locked, do not start another process
    if PID.is_locked():
        sys.stderr.write('Plight is already running\n')
        sys.exit(1)

    context = DaemonContext(pidfile=PID,
                            uid=pwd.getpwnam(config['user']).pw_uid,
                            gid=grp.getgrnam(config['group']).gr_gid,
                            umask=0o022,
                            files_preserve=[
                                weblogging_handler.stream,
                                applogging_handler.stream,
                            ],)
    context.stdout = applogging_handler.stream
    context.stderr = applogging_handler.stream
    context.open()
    os.umask(0o022)

    try:
        try:
            log_message('Plight is starting...')
            server_class = BaseHTTPServer.HTTPServer
            http = server_class((config['host'],
                                 config['port']),
                                plight.StatusHTTPRequestHandler)
            http.RequestHandlerClass._node_status = node
            http.serve_forever()
        except SystemExit as sysexit:
            log_message("Stopping... " + str(sysexit))
        except Exception as ex:
            log_message("ERROR: " + str(ex))
    finally:
        log_message('Plight has stopped...')
        context.close()
Example #42
0
    def _daemonize(self):
        import psutil
        from daemon import DaemonContext
        try:
            from daemon.pidfile import TimeoutPIDLockFile as PIDLockFile
        except:
            from daemon.pidlockfile import PIDLockFile

        pidlock = PIDLockFile('/var/run/fedmsg/%s.pid' % self.name)

        pid = pidlock.read_pid()
        if pid and not psutil.pid_exists(pid):
            self.log.warn("PID file exists but with no proc:  coup d'etat!")
            pidlock.break_lock()

        output = file('/var/log/fedmsg/%s.log' % self.name, 'a')
        daemon = DaemonContext(pidfile=pidlock, stdout=output, stderr=output)
        daemon.terminate = self._handle_signal

        with daemon:
            return self.run()
Example #43
0
def daemon():
    def die_in_a_fire(signum, stack):
        for thread in threads:
            thread.kill()

    import signal
    from daemon import DaemonContext
    try:
        from daemon.pidfile import TimeoutPIDLockFile as PIDLockFile
    except:
        from daemon.pidlockfile import PIDLockFile

    config = appconfig("config:" + find_config_file())

    #pidlock = PIDLockFile('/var/run/fedoracommunity/worker.pid')
    #output = file('/var/log/fedoracommunity/worker.log', 'a')
    pidlock = PIDLockFile(
        config.get('cache-worker.pidfile', '/tmp/fedoracommunity-worker.pid')
    )
    output = file(
        config.get('cache-worker.logfile', '/tmp/fedoracommunity-worker.log'),
        'a')

    daemon = DaemonContext(pidfile=pidlock, stdout=output, stderr=output)
    daemon.terminate = die_in_a_fire

    n = int(config.get('cache-worker.threads', '8'))
    with daemon:
        log.info("Creating %i threads" % n)
        for i in range(n):
            threads.append(Thread())

        for thread in threads:
            thread.start()

        # I used to do thread.join() here, but that makes it so the
        # signal_handler never gets fired.  Crazy python...
        while any([not thread.die for thread in threads]):
            time.sleep(2)
Example #44
0
    def __init__(self, args=None):
        # Parse args
        if args is None:
            args = {}

        options, _ = getopt.getopt(sys.argv[1:], 'c:d')
        options = dict(options)

        config_file = options.get('-c', '/usr/local/etc/rpcdaemon.conf')
        daemonize = '-d' not in options

        # Parse config
        self.config = Config(config_file, 'Daemon')

        # Initialize logger
        self.logger = Logger(
            name='rpcdaemon',
            level = self.config['loglevel'],
            path = self.config['logfile'] if daemonize else None,
            handler = None if daemonize else logging.StreamHandler()
        )

        self.pidfile = PIDFile(self.config['pidfile']) if daemonize else None;

        # TOOD: plugin.check thread pool?
        self.timeout = int(self.config.get('check_interval', 1))

        # Clamp in case we exit before worker exists
        self.worker = None

        # Initialize daemon
        DaemonContext.__init__(
            self,
            detach_process=daemonize,
            files_preserve=[self.logger.handler.stream.fileno()],
            pidfile=self.pidfile,
            stdout=self.logger.handler.stream,
            stderr=self.logger.handler.stream
        )
Example #45
0
	def start(self, detachProcess=True):
		pidFile = TimeoutPIDLockFile(self._pidFile)

		context = DaemonContext(
			working_directory=self._runDir,
			umask=0o002,
			pidfile=pidFile,
			detach_process=detachProcess,
		)

		context.signal_map = {
			signal.SIGTERM: 'terminate',
			signal.SIGHUP: 'terminate',
			signal.SIGUSR1: 'terminate',
		}

		if self._isRunningAndBreak(pidFile):
			raise AlreadyRunning("PID file locked and process not stale")

		self._context = context
		try:
			context.open()
			self._setupLogging()
		except:
			if self.logger is None:
				self._setupLogging()
			self.logger.warn("Exception while entering context", exc_info=True)
			try:
				context.close()
			except:
				pass
			return

		try:
			self.run()
		except Exception as e:
			self.logger.error("Exception in run()", exc_info=e)
		finally:
			self.logger.debug("Shutting down daemon")
			self.shutdown()
			try:
				self._fHandler.close()
			except:
				pass
			try:
				context.close()
			except:
				pass
Example #46
0
def start(**keywords):
    args = {}
    args.update(
        dev_install = False,
        mark_read = None,
        debug_level = None,
        )
    args.update(keywords)
    try:
        config = democraticd.config.Config(
            dev_install = args['dev_install'],
            debug_level = args['debug_level'],
            mark_read = args['mark_read'],
            )
    except:
        args['dev_install'] = not args['dev_install']
        config = democraticd.config.Config(
            dev_install = args['dev_install'],
            debug_level = args['debug_level'],
            mark_read = args['mark_read'],
            )            
    del args['dev_install']
    del args['debug_level']
    del args['mark_read']
    
    log_file = open(config.log_filename, 'wt+')
    
    context = DaemonContext()
    context.uid = config.uid
    context.gid = config.gid
    context.stdout = log_file
    context.stderr = log_file

    print('Starting daemon, logging to ' + config.log_filename)
    with context:
        DemocraticDaemon(config, **args).start()
Example #47
0
    def handle_daemon(self, name, daemon):
        """
        Executes the daemon command.

        :param str name: The name of the daemon.
        :param * daemon: The daemon, i.e. object with main method.
        """
        self.output = EnarkshStyle(self.input, self.output)

        log = logging.getLogger('enarksh')
        log.setLevel(logging.INFO)
        log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

        if self.option('daemonize'):
            config = Config.get()

            log_file_name = os.path.join(C.HOME, config.get_enarksh_log_dir(), name + '.log')
            pid_file_name = os.path.join(C.HOME, config.get_enarksh_lock_dir(), name + '.pid')

            log_handler = logging.handlers.RotatingFileHandler(log_file_name,
                                                               maxBytes=config.get_enarksh_max_log_size(),
                                                               backupCount=config.get_enarksh_log_back())
            log_handler.setLevel(logging.DEBUG)
            log_handler.setFormatter(log_formatter)
            log.addHandler(log_handler)

            output = open(log_file_name, 'ab', 0)

            context = DaemonContext()
            context.working_directory = C.HOME
            context.umask = 0o002
            context.pidfile = PIDLockFile(pid_file_name, False)
            context.stdout = output
            context.stderr = output
            context.files_preserve = [log_handler.stream]

            with context:
                daemon.main()
        else:
            log_handler = logging.StreamHandler(sys.stdout)
            log_handler.setLevel(logging.DEBUG)
            log_handler.setFormatter(log_formatter)
            log.addHandler(log_handler)

            daemon.main()
    def __init__(self, app, parser):
        """ Set up the parameters of a new runner.

            The `app` argument must have the following attributes:

            * `stdin_path`: Filesystem path to open and replace `sys.stdin`.

            * `stdout_logger`, `stderr_logger`: Loggers to redirect
               the existing `sys.stdout` and `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that
              will be used as the PID file for the daemon. If
              ``None``, no PID file will be used.

            * `pidfile_timeout`: Used as the default acquisition
              timeout value supplied to the runner's PID lock file.

            * `run`: Callable that will be invoked when the daemon is
              started.

            The `parser` argument must be an optparse.OptionParser() object.

            """
        self.app = app
        self.parser = parser
        (options, args) = parser.parse_args()
        self.args = args
        self.options = options
        self.parse_args()
        self.daemon_context = DaemonContext()
        self.daemon_context.stdin = open(app.stdin_path, 'r')
        self.stdout_logger = app.stdout_logger
        self.stderr_logger = app.stderr_logger
        self.daemon_context.files_preserve = []
        self.loggers_preserve = []

        self.pidfile = None
        if app.pidfile_path is not None:
            self.pidfile = make_pidlockfile(
                app.pidfile_path, app.pidfile_timeout)
        self.daemon_context.pidfile = self.pidfile
Example #49
0
 def _start(self):
     """ Open the daemon context and run the application.
     """
     self.daemon_context = DaemonContext()
     self.daemon_context.pidfile = self.pidfile
     #self.daemon_context.stdin = open(stdin_path, 'r')
     self.daemon_context.stdout = open(self.stdout_path, 'w+')
     self.daemon_context.stderr = open(self.stderr_path, 'w+', buffering=0)
     if is_pidfile_stale(self.pidfile):
         self.pidfile.break_lock()
     #print "Here"
     try:
         self.daemon_context.open()
     except TimeoutPIDLockFile.AlreadyLocked:
         pidfile_path = self.pidfile.path
         raise RunnerStartFailureError(
             "PID file %(pidfile_path)r already locked" % vars())
     #print "Here 2"
     message = self.start_message % os.getpid()
     logger.info(message)
     emit_message(message, self.daemon_context.stdout)
     self.app_run()
Example #50
0
    def __init__(self, callback, pidpath, timeout=1, parser=None):
        """
        Parameters
        ----------
        callback : function
            A callback function called when a daemon process starts.  It is
            called without arguments.
        pidpath : str
            Absolute path of the PID file.
        """
        argspec = inspect.getargspec(callback)
        if len(argspec.args) != 0:
            msg = ('callback is called without arguments: {0}'.format(argspec))
            raise DaemonRunnerError(msg)

        self.callback = callback
        self.pidfile = self._make_pidlockfile(pidpath, timeout)

        self.daemon_context = DaemonContext()
        self.daemon_context.pidfile = self.pidfile

        self._parser = self._init_argparser(parser)
        self._logger = None
Example #51
0
    def __init__(
            self,
            name = 'seriald',
            config_file = 0,
            log_file = None,
            pidfile_path = 0,
            socket_path = 0,
            reply_length_strict = False,
            data_length = 1024,
            data_encoding = 'utf-8',
            daemon_context = None,
            serial_context = None,
            **kwargs
    ):

        self.name = name
        self.config_file = config_file
        if self.config_file == 0:
            self.config_file = '/etc/{name}.conf'.format(name = self.name)
            
        self.log_file = log_file
        # log file will be used even if user specified None
        if self.log_file is None:
            self.log_file = os.path.join(
                tempfile.gettempdir(), '{name}.log'.format(
                    name = self.name))
            
        self.pidfile_path = pidfile_path
        if self.pidfile_path == 0:
            self.pidfile_path = '/var/run/{name}.pid'.format(name = self.name)

        self.socket_path = socket_path
        if self.socket_path == 0:
            self.socket_path = '/var/run/{name}.socket'.format(name = self.name)
            
        self.reply_length_strict = reply_length_strict
        self.data_length = data_length
        self.data_encoding = data_encoding
        
        self.daemon_context = daemon_context
        if self.daemon_context is None:
            self.daemon_context = DaemonContext(
                signal_map = {
                    signal.SIGHUP: self.__accept_signal,
                    signal.SIGINT: self.__accept_signal,
                    signal.SIGQUIT: self.__accept_signal,
                    signal.SIGTERM: self.__accept_signal,
                }
            )
            for attr in filter(lambda s: not s.startswith('_'),
                               dir(self.daemon_context)):
                if kwargs.get(attr) is not None:
                    setattr(self.daemon_context, attr, kwargs.get(attr))
            
        self.serial_context = serial_context
        if self.serial_context is None:
            self.serial_context = Serial()
            for attr in filter(lambda s: not s.startswith('_'),
                               dir(self.serial_context)):
                if kwargs.get(attr) is not None:
                    setattr(self.serial_context, attr, kwargs.get(attr))
Example #52
0
class SerialDaemon():
    """A wrapper class for Serial and DaemonContext with inet socket support.

    Creates a DaemonContext object and a Serial object using the passed
    arguments. Some arguments do not take effect after the daemon is started
    and hence can be altered anytime after initialization until it is started
    by calling <daemon>.start()

    Communication with the daemon is done on a port number specified during
    initialization (or anytime before start), defaulting to 57001. Data is
    decoded using the user specified encoding (default is UTF-8) and must be
    either exactly 'device', in which case the daemon will reply with the full
    path to the device file it is communicating with (serial_context.port),
    or it must be in the following format:
        <0-F><0-F0-F...0-F><data to be sent to device>
    where the first byte of data always signifies how many (base 16) bytes
    following it give the the number (base 16) of bytes that are to be read
    from device after the data is sent to it. 0 bytes are read if data[0] is
    0 or is not a valid hex number. <data[0] number of bytes> + 1 are always
    discarded from the beginning of data. For example:
        22F8921 sends 8921 to device and reads 2F (47) bytes of data
        X78192 sends 78192 to device and dos not read a reply
        3A2G9130 sends 9130 to device BUT does not read a reply since A2G is
            not a valid hex number. Note that these 3 bytes are still discarded

    This class does not inherit from either DaemonContext or Serial.
    The only export method is start() used to run the daemon.

    Accepted options for the constructor:

    name
        :Default: ``None``

        The name of the daemon, used for syslog and the default
        name of the pidfile and configuration files. Changes to this value
        after the daemon has started will only be reflected in syslog.

    config_file
        :Default: ``'/etc/<name>.conf'``

        Configuration file used to set some of the hereby listed parameters.
        All but name, daemon_context and serial_context are supported.
        Reloading of the configuration without restarting is done by sending
        SIGHUP to the daemon but please note that changes to pidfile_path,
        socket_path and log_file require restart to take effect.
        The format is as follows:
            <option_name> = <option value>
        Option names are case-INsensitive and ``_`` may be replaced by ``-``.
        Spaces around ``=`` are optional and have no effect.
        Option values may optionally be enclosed in either single or double
        quotes. # and any text following it on the line are ignored.

    log_file
        :Default: ``/tmp/<name>.log``

        Log file used to log exceptions during daemon run.

    pidfile_path
        :Default: ``'/var/run/<name>.pid'``

        Path to the pidfile. A pidfile lock is created and passed to
        DaemonContext. Alternatively, you may pass a pid lockfile directly by
        setting <daemon>.daemon_context.pidfile to the lockfile after
        initialization but before start. Changing either of them after the
        daemon is started requires a restart.

    socket_path
        :Default: ``'/var/run/<name>.socket'``

        Path for the unix daemon socket which the daemon will be listening on.
        Changing this after the daemon is started requires a restart. Also see
        documentation for serial.py.

    data_length
        :Default: ``1024``

        Number of bytes to be read from the socket. This MUST be at least the
        number of bytes that have been sent, otherwise the remainder is read
        afterwards and is confused for a new packet. See above for details on
        the data format.

    data_encoding
        :Default: ``'utf-8'``

        Valid encoding (accepted by the str.decode() and bytes() methods) for
        the data read from and sent to the socket.

    reply_length_strict
        :Default: ``False``

        If True daemon will not send data read from device unless the length
        matches the expected reply length given as part of the data sent over
        the socket. See above for details on the data format.

    daemon_context
        :Default: ``None``

        If this is not None, it must be a DaemonContext object and is used
        instead of creating a new one. All options relating to DaemoonContext
        are then ignored.

    serial_context
        :Default: ``None``

        If this is not None, it must be a Serial object and is used instead of
        creating a new one. All options relating to Serial are then ignored.

    In addition to the above arguments, SerialDaemon accepts all arguments
    valid for DaemonContext and Serial and uses them to create the
    corresponding objects (unless daemon_context or serial_context are given)
    """
    
    def __init__(
            self,
            name = 'seriald',
            config_file = 0,
            log_file = None,
            pidfile_path = 0,
            socket_path = 0,
            reply_length_strict = False,
            data_length = 1024,
            data_encoding = 'utf-8',
            daemon_context = None,
            serial_context = None,
            **kwargs
    ):

        self.name = name
        self.config_file = config_file
        if self.config_file == 0:
            self.config_file = '/etc/{name}.conf'.format(name = self.name)
            
        self.log_file = log_file
        # log file will be used even if user specified None
        if self.log_file is None:
            self.log_file = os.path.join(
                tempfile.gettempdir(), '{name}.log'.format(
                    name = self.name))
            
        self.pidfile_path = pidfile_path
        if self.pidfile_path == 0:
            self.pidfile_path = '/var/run/{name}.pid'.format(name = self.name)

        self.socket_path = socket_path
        if self.socket_path == 0:
            self.socket_path = '/var/run/{name}.socket'.format(name = self.name)
            
        self.reply_length_strict = reply_length_strict
        self.data_length = data_length
        self.data_encoding = data_encoding
        
        self.daemon_context = daemon_context
        if self.daemon_context is None:
            self.daemon_context = DaemonContext(
                signal_map = {
                    signal.SIGHUP: self.__accept_signal,
                    signal.SIGINT: self.__accept_signal,
                    signal.SIGQUIT: self.__accept_signal,
                    signal.SIGTERM: self.__accept_signal,
                }
            )
            for attr in filter(lambda s: not s.startswith('_'),
                               dir(self.daemon_context)):
                if kwargs.get(attr) is not None:
                    setattr(self.daemon_context, attr, kwargs.get(attr))
            
        self.serial_context = serial_context
        if self.serial_context is None:
            self.serial_context = Serial()
            for attr in filter(lambda s: not s.startswith('_'),
                               dir(self.serial_context)):
                if kwargs.get(attr) is not None:
                    setattr(self.serial_context, attr, kwargs.get(attr))
                    
    def __run(self):

        with open(self.log_file, 'a') as log_file:
            try:
                soc = None
                # flush doesn't work in daemon mode for ttyS?
                # close and reopen instead
                device = self.serial_context.port
                is_ttyS = True
                try:
                    # is it a number? Serial defaults to /dev/ttyS? if so
                    device += 0
                except TypeError:
                    # not a number, assume string
                    try:
                        if not device.startswith('/dev/ttyS'):
                            raise AttributeError
                    except AttributeError:
                        # not a string or not a ttyS? device
                        # assume flushing works
                        is_ttyS = False
                else:
                    device = '/dev/ttyS{num}'.format(num = device)
                                
                while True:
                    if not soc or soc.fileno() < 0:
                        logsyslog(LOG_INFO, 'Waiting for connection')
                        soc, soc_addr = self.socket.accept()
                        logsyslog(LOG_INFO, ('Connected to {addr}').format(
                            addr = soc_addr))

                    data = soc.recv(self.data_length).decode(
                        self.data_encoding)
                    if data == '':
                        logsyslog(LOG_INFO, 'Closing connection')
                        soc.close()
                        continue
                    elif data == 'device':
                        logsyslog(LOG_INFO, 'Device path requested')
                        try:
                            soc.sendall(device.encode(self.data_encoding))
                        except ConnectionResetError:
                            soc.close()
                        continue

                    logsyslog(LOG_INFO, 'Read from socket: {data}'.format(
                        data = data))

                    reply_length_byte_length = 0
                    try:
                        reply_length_byte_length = int(data[0], 16)
                        reply_length = int(
                            data[1 : reply_length_byte_length + 1], 16)
                    except ValueError:
                        reply_length = 0
                    data = data[reply_length_byte_length + 1:]

                    if not self.serial_context.isOpen():
                        # first time in the loop
                        logsyslog(LOG_INFO, 'Opening serial port')
                        self.serial_context.open()
                        
                    logsyslog(LOG_INFO, 'Sending {data}'.format(
                        data = data))
                    # discard any input or output
                    self.serial_context.flushOutput()
                    self.serial_context.flushInput()
                    self.serial_context.write(data.encode(self.data_encoding))
                    
                    if is_ttyS:
                        self.serial_context.close()
                        self.serial_context.open()
                    else:
                        self.serial_context.flush()
                            
                    logsyslog(LOG_INFO, ('Will read {length} bytes').format(
                        length = reply_length))
                    
                    if reply_length > 0:
                        reply = self.serial_context.read(reply_length)
                        reply_decoded = reply.decode(self.data_encoding)
                        logsyslog(LOG_INFO, 'Received {data}'.format(
                            data = reply_decoded))
                        if len(reply_decoded) == reply_length \
                           or not self.reply_length_strict:
                            try:
                                soc.sendall(reply)
                            except ConnectionResetError:
                                soc.close()
                                continue

            except:
                traceback.print_exc(file = log_file)
                
        self.__stop()
                
    def __load_config(self):
        def reset_invalid_value(opt):
            logsyslog(LOG_ERR,
                      ('{conf}: Invalid value for ' +
                       '{option}').format(
                           conf = self.config_file,
                           option = opt))
            return getattr(self, opt)

        conf = _openfile(self.config_file, 'r')
        if conf is not None:
            with conf:
            
                regex_pat = regex.compile(r"""\s* (?|
                    (?P<option>
                      reply_length_strict |
                      data[-_]length |
                      data[-_]encoding |
                      log[-_]file |
                      pidfile[-_]path |
		      socket[-_]path
		    ) \s* (?: =\s* )?
		    (?|
                      " (?P<value> [^"]+ ) " |
		      ' (?P<value> [^']+ ) ' |
		        (?P<value> [^#\r\n]+ )
		    ) )
                    """, regex.X|regex.I)
                
                line_num = 0
                for line in conf:
                    line_num += 1
                    
                    if line.startswith('#'):
                        continue
                    
                    match = regex_pat.match(line.strip())
                    if match:
                        # translate the option name to the object's attribute
                        opt = match.group('option').lower().replace('-', '_')
                        
                        if opt.endswith(('file',
                                         'dir',
                                         'path',
                                         'encoding')):
                            # value is a string
                            val = match.group('value')
                        elif opt == 'reply_length_strict':
                            # value must be a boolean
                            if val.lower() not in ['0', '1', 'false', 'true']:
                                val = reset_invalid_value(opt)
                            elif val.lower() in ['0', 'false']:
                                val = False
                            else:
                                val = True
                        else:
                            # value must be numeric and positive
                            val = int(match.group('value'))
                            if val <= 0:
                                val = reset_invalid_value(opt)
                                
                        setattr(self, opt, val)
                        
                    else:
                        logsyslog(LOG_ERR, ('{conf}: Invalid syntax at line ' +
                                            '{line}').format(
                                                conf = self.config_file,
                                                line = line_num))
                        
            logsyslog(LOG_INFO, 'Loaded configuration from {conf}'.format(
                conf = self.config_file))

    def start(self):
        """
        Load config, daemonize, connect to serial port, listen on socket
        """
        opensyslog(ident = self.name, facility = LOG_DAEMON)
        
        self.__load_config()
        if self.pidfile_path is not None:
            self.daemon_context.pidfile = lockfile.FileLock(self.pidfile_path)
            
        if _pidfile_isbusy(self.daemon_context.pidfile):
            logsyslog(LOG_ERR, 'Already running (pidfile is locked)')
            closesyslog()
            return
        
        if _socket_isbusy(self.socket_path):
            logsyslog(LOG_ERR, 'Already running (socket is in use)')
            closesyslog()
            return
        
        self.daemon_context.open()
        with _openfile(self.daemon_context.pidfile.path, 'w',
                      fail = self.__stop) as file:
            file.write('{pid}'.format(pid = os.getpid()))
        # opening the serial port here doesn't work
        # open it in __run instead
        # self.serial_context.open()
        logsyslog(LOG_INFO, 'Started')

        self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.socket.bind(self.socket_path)
        self.socket.listen(1)
        logsyslog(LOG_INFO, ('Listening on socket {socket}').format(
            socket = self.socket_path))
        self.__run()
        
    def __stop(self):
        pid = _get_pid(self.daemon_context.pidfile.path)
        if pid is None:
            return

        logsyslog(LOG_INFO, 'Stopping')
        
        os.remove(self.socket.getsockname())
        os.remove(self.daemon_context.pidfile.path)
        
        self.socket.close()
        
        if self.serial_context.isOpen():
            self.serial_context.close()
        self.daemon_context.close()
        
        try:
            os.kill(pid, signal.SIGKILL)
        except OSError:
            logsyslog(LOG_ERR, 'Could not stop process id {pid}'.format(
                pid = pid))
        closesyslog()
        
    def __accept_signal(self, sig, frame):
        if sig == signal.SIGHUP:
            self.__load_config()
        else:
            logsyslog(LOG_INFO, 'Caught signal {sig}'.format(sig = sig))
            self.__stop()
Example #53
0
    def __init__( self, pidfile, **kwargs ):

        argv = list(sys.argv)
        filename = self.filename = os.path.abspath( argv.pop(0) )
        path = os.path.dirname(filename)
        kwargs.setdefault( 'working_directory', path )

        if isinstance( pidfile, basestring ):
            if pidfile[0] != '/':
                pidfile = '%s/%s' % (path, pidfile )

            pidfile = PIDLockFile( pidfile )

        if argv:
            cmd = argv.pop(0)
            if cmd=='stop':
                self._stop( pidfile )
                sys.exit(0)

            elif cmd=='restart':
                self._stop( pidfile )
                c = 10
                while pidfile.is_locked():
                    c-=1
                    gevent.sleep(1)
                    if not c:
                        raise Exception('Cannot stop daemon (Timed out)')

                # should just work without this - but it does not :/
                cmd = [sys.executable, filename]+argv
                cmd.append('&')
                os.system( ' '.join(cmd) )
                exit(0)
            """
            elif cmd!='start':
                sys.stderr.write('try %s %s start|stop|restart\r\n' % (sys.executable, sys.argv[0]))
                exit(0)
            """

        if pidfile.is_locked():
            sys.stderr.write( 'Daemon seems to be already running\r\n' )
            sys.exit(-1)

        self.exit_hooks = kwargs.pop('exit_hooks',[])
        files_preserve = kwargs.pop('files_preserve',[])
        stderr = kwargs.get('stderr')
        if stderr:
            files_preserve.append( stderr )

        for logger in kwargs.pop('loggers',()):
            for handler in logger.handlers:
                if hasattr( handler, 'stream' ):
                    files_preserve.append( handler.stream )

        self.loggers = []
        filename = os.path.basename( self.filename)

        try:
            from setproctitle import setproctitle
            setproctitle( filename )
        except ImportError:
            import ctypes
            try:
                libc = ctypes.CDLL("libc.so.6")
                libc.prctl(15, filename, 0, 0, 0)
            except:
                pass


        _DaemonContext.__init__( self, pidfile=pidfile, files_preserve=files_preserve, **kwargs )
Example #54
0
class Runner(object):
    """ Controller for a callable running in a separate background process.

    The first command-line argument is the action to take:

    * 'start': Become a daemon and call `app.run()`.
    * 'stop': Exit the daemon process specified in the PID file.
    * 'restart': Stop, then start.
    * 'status': Show the status of the process.

    """

    start_message = "started with pid %d"
    status_message_running = "process is running (%d)"
    status_message_not_running = "process is not running"

    def __init__(self):
        """ Set up the parameters of a new runner.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem
              paths to open and replace the existing `sys.stdin`,
              `sys.stdout`, `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that
              will be used as the PID file for the daemon. If
              ``None``, no PID file will be used.

            * `pidfile_timeout`: Used as the default acquisition
              timeout value supplied to the runner's PID lock file.

        """
        self.options = {}
        self.pidfile_timeout = 6.0
        self.stdout_path = None
        self.stderr_path = None
        self.pidfile_path = None
        self.userid = None
        self.args = None
        self.parse_args()
        self.pidfile = None
        self.pidfile_path = os.path.join(self.options['pid_dir'], self.options['service'] + ".pid")
        self.pidfile = make_pidlockfile(
            self.pidfile_path, self.pidfile_timeout)
        if self.pidfile.is_locked() and not is_pidfile_stale(self.pidfile) \
          and self.action == 'start':
            print("Process already running. Exiting.")
            sys.exit(1)
        if (not self.pidfile.is_locked() or is_pidfile_stale(self.pidfile)) \
          and (self.action == 'stop' or self.action == 'kill'):
            print("Process not running. Exiting.")
            sys.exit(1)

    def app_run(self):
        """
        The running process of the application
        """
        raise RunnerInvalidActionError("Action: %(action)r is not implemented" % vars(self))

    def app_shutdown(self):
        """
        The shutdown process of the application
        """
        raise RunnerInvalidActionError("Action: %(action)r is not implemented" % vars(self))

    def _usage_exit(self, args):
        """ Emit a usage message, then exit.
        """
        usage_exit_code = 2
        message = "usage: use --help to get help" % vars()
        emit_message(message)
        sys.exit(usage_exit_code)

    def parse_args(self):
        """ Parse command-line arguments.
        """
        args = jnt_parse_args()
        self.options = vars(args)
        self.action = args.command
        self.args = args
        self.stdout_path = os.path.join(self.options['log_dir'], self.options['service'] + "_out.log")
        self.stderr_path = os.path.join(self.options['log_dir'], self.options['service'] + "_err.log")
        self.pidfile_path = os.path.join(self.options['pid_dir'], self.options['service'] + ".pid")
        if self.options['user'] and self.options['user'] != "":
            self.userid = pwd.getpwnam(self.options['user']).pw_uid
            if self.userid != os.getuid():
                #print self.userid
                os.setuid(self.userid)
        try:
            os.makedirs(self.options['pid_dir'])
            os.makedirs(self.options['home_dir'])
            os.makedirs(self.options['conf_dir'])
            os.makedirs(self.options['log_dir'])
        except OSError as exc: # Python >2.5
            if exc.errno == errno.EEXIST:
                pass
            else: raise
        if self.action not in self.action_funcs:
            self._usage_exit(args)

    def _start(self):
        """ Open the daemon context and run the application.
        """
        self.daemon_context = DaemonContext()
        self.daemon_context.pidfile = self.pidfile
        #self.daemon_context.stdin = open(stdin_path, 'r')
        self.daemon_context.stdout = open(self.stdout_path, 'w+')
        self.daemon_context.stderr = open(self.stderr_path, 'w+', buffering=0)
        if is_pidfile_stale(self.pidfile):
            self.pidfile.break_lock()
        #print "Here"
        try:
            self.daemon_context.open()
        except TimeoutPIDLockFile.AlreadyLocked:
            pidfile_path = self.pidfile.path
            raise RunnerStartFailureError(
                "PID file %(pidfile_path)r already locked" % vars())
        #print "Here 2"
        message = self.start_message % os.getpid()
        logger.info(message)
        emit_message(message, self.daemon_context.stdout)
        self.app_run()

    def _front(self):
        """ Open the daemon context and run the application.
        """
        if is_pidfile_stale(self.pidfile):
            self.pidfile.break_lock()
        self.pidfile.__enter__()
        message = self.start_message %  os.getpid()
        emit_message(message, sys.stdout)
        try:
            self.app_run()
        except KeyboardInterrupt:
            pass
        finally:
            if self.pidfile:
                try:
                    self.pidfile.__exit__(None, None, None)
                except:
                    pass
        self.app_shutdown()

    def _terminate_daemon_process(self):
        """ Terminate the daemon process specified in the current PID file.
            """
        pid = self.pidfile.read_pid()
        try:
            os.kill(pid, signal.SIGTERM)
        except OSError as exc:
            raise RunnerStopFailureError(
                "Failed to terminate %(pid)d: %(exc)s" % vars())

    def _kill_daemon_process(self):
        """ Terminate the daemon process specified in the current PID file.
            """
        pid = self.pidfile.read_pid()
        try:
            os.kill(pid, signal.SIGKILL)
        except OSError, exc:
            raise RunnerStopFailureError(
                "Failed to kill %(pid)d: %(exc)s" % vars())
Example #55
0
def main():
    try:
        import twisted
    except ImportError:
        print "Orbited requires Twisted, which is not installed. See http://twistedmatrix.com/trac/ for installation instructions."
        sys.exit(1)

    #################
    # This corrects a bug in Twisted 8.2.0 for certain Python 2.6 builds on Windows
    #   Twisted ticket: http://twistedmatrix.com/trac/ticket/3868
    #     -mario
    try:
        from twisted.python import lockfile
    except ImportError:
        from orbited import __path__ as orbited_path
        sys.path.append(os.path.join(orbited_path[0],"hotfixes","win32api"))
        from twisted.python import lockfile
        lockfile.kill = None
    #################

    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option(
        "-c",
        "--config",
        dest="config",
        default=None,
        help="path to configuration file"
    )
    parser.add_option(
        "-v",
        "--version",
        dest="version",
        action="store_true",
        default=False,
        help="print Orbited version"
    )
    parser.add_option(
        "-p",
        "--profile",
        dest="profile",
        action="store_true",
        default=False,
        help="run Orbited with a profiler"
    )
    parser.add_option(
        "-q",
        "--quickstart",
        dest="quickstart",
        action="store_true",
        default=False,
        help="run Orbited on port 8000 and MorbidQ on port 61613"
    )
    parser.add_option( 
        "-d", 
        "--daemon", 
        dest="daemon", 
        action="store_true", 
        default=False, 
        help="run Orbited as a daemon (requires the python-daemon package)"
        )
    parser.add_option(
        "--pid-file",
        dest="pidfile",
        default="/var/run/orbited/orbited.pid",
        help=("use PIDFILE as the orbited daemon pid file",
              "; defaults to '/var/run/orbited/orbited.pid'"),
        )
    
    MemoryUtil.add_options_to_parser(parser)
    
    (options, args) = parser.parse_args()

    if args:
        print 'the "orbited" command does not accept positional arguments. type "orbited -h" for options.'
        sys.exit(1)

    if options.version:
        print "Orbited version: %s" % (version,)
        sys.exit(0)
    
    global logger
    
    if options.quickstart:
        logging.basicConfig()
        logger = logging.getLogger(__name__)
        config.map['[listen]'].append('http://:8000')
        config.map['[listen]'].append('stomp://:61613')
        config.map['[access]'][('localhost',61613)] = ['*']
        logger.info("Quickstarting Orbited")
    else:
        # load configuration from configuration
        # file and from command line arguments.
        config.setup(options=options)
        logging.config.fileConfig(options.config)
        logger = logging.getLogger(__name__)
        logger.info("Starting Orbited with config file %s" % options.config)
    
    if options.daemon:
        try:
            from daemon import DaemonContext
            from daemon.pidfile import PIDLockFile
            pidlock = PIDLockFile(options.pidfile)
            daemon = DaemonContext(pidfile=pidlock)
            logger.debug('daemonizing with pid file %r', options.pidfile)
            daemon.open()
            logger.debug('daemonized!')
        except Exception, exc:
            logger.debug(exc)
class DaemonRunner(object):
    """ Controller for a callable running in a separate background process.

        The first command-line argument is the action to take:

        * 'start': Become a daemon and call `app.run()`.
        * 'stop': Exit the daemon process specified in the PID file.
        * 'restart': Stop, then start.

        """

    start_message = "started with pid %(pid)d"

    def __init__(self, app):
        """ Set up the parameters of a new runner.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem
              paths to open and replace the existing `sys.stdin`,
              `sys.stdout`, `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that
              will be used as the PID file for the daemon. If
              ``None``, no PID file will be used.

            * `pidfile_timeout`: Used as the default acquisition
              timeout value supplied to the runner's PID lock file.

            * `run`: Callable that will be invoked when the daemon is
              started.
            
            """
        self.parse_args()
        self.app = app
        self.daemon_context = DaemonContext()
        self.daemon_context.stdin = open(app.stdin_path, 'r')
        self.daemon_context.stdout = open(app.stdout_path, 'w+')
        self.daemon_context.stderr = open(
            app.stderr_path, 'w+', buffering=0)

        self.pidfile = None
        if app.pidfile_path is not None:
            self.pidfile = make_pidlockfile(
                app.pidfile_path, app.pidfile_timeout)
        self.daemon_context.pidfile = self.pidfile

    def _usage_exit(self, argv):
        """ Emit a usage message, then exit.
            """
        progname = os.path.basename(argv[0])
        usage_exit_code = 2
        action_usage = "|".join(self.action_funcs.keys())
        message = "usage: %(progname)s %(action_usage)s" % vars()
        emit_message(message)
        sys.exit(usage_exit_code)

    def parse_args(self, argv=None):
        """ Parse command-line arguments.
            """
        if argv is None:
            argv = sys.argv

        min_args = 2
        if len(argv) < min_args:
            self._usage_exit(argv)

        self.action = argv[1]
        if self.action not in self.action_funcs:
            self._usage_exit(argv)

    def _start(self):
        """ Open the daemon context and run the application.
            """
        if is_pidfile_stale(self.pidfile):
            self.pidfile.break_lock()

        try:
            self.daemon_context.open()
        except pidlockfile.AlreadyLocked:
            pidfile_path = self.pidfile.path
            raise DaemonRunnerStartFailureError(
                "PID file %(pidfile_path)r already locked" % vars())

        pid = os.getpid()
        message = self.start_message % vars()
        emit_message(message)

        self.app.run()

    def _terminate_daemon_process(self):
        """ Terminate the daemon process specified in the current PID file.
            """
        pid = self.pidfile.read_pid()
        try:
            os.kill(pid, signal.SIGTERM)
        except OSError as exc:
            raise DaemonRunnerStopFailureError(
                "Failed to terminate %(pid)d: %(exc)s" % vars())

    def _stop(self):
        """ Exit the daemon process specified in the current PID file.
            """
        if not self.pidfile.is_locked():
            pidfile_path = self.pidfile.path
            raise DaemonRunnerStopFailureError(
                "PID file %(pidfile_path)r not locked" % vars())

        if is_pidfile_stale(self.pidfile):
            self.pidfile.break_lock()
        else:
            self._terminate_daemon_process()

    def _restart(self):
        """ Stop, then start.
            """
        self._stop()
        self._start()

    action_funcs = {
        'start': _start,
        'stop': _stop,
        'restart': _restart,
        }

    def _get_action_func(self):
        """ Return the function for the specified action.

            Raises ``DaemonRunnerInvalidActionError`` if the action is
            unknown.

            """
        try:
            func = self.action_funcs[self.action]
        except KeyError:
            raise DaemonRunnerInvalidActionError(
                "Unknown action: %(action)r" % vars(self))
        return func

    def do_action(self):
        """ Perform the requested action.
            """
        func = self._get_action_func()
        func(self)
Example #57
0
     log.error('System will exit.')
     log.info(LOG_BREAK)
     sys.exit(1)    
 
 if len(brokers) == 0:
     log.error('No brokers available.')
     log.error('System will exit.')
     log.info(LOG_BREAK)
     sys.exit(1)
     
 log.info('The SSM will run as a daemon.')
 
 # We need to preserve the file descriptor for any log files.
 rootlog = logging.getLogger()
 log_files = [x.stream for x in rootlog.handlers]
 dc = DaemonContext(files_preserve=log_files)
     
 try:
     ssm = Ssm2(brokers, 
                cp.get('messaging','path'),
                cert=cp.get('certificates','certificate'),
                key=cp.get('certificates','key'),
                listen=cp.get('messaging','destination'),
                use_ssl=cp.getboolean('broker','use_ssl'),
                capath=cp.get('certificates', 'capath'),
                check_crls=cp.getboolean('certificates', 'check_crls'),
                pidfile=pidfile)
     
     log.info('Fetching valid DNs.')
     dns = get_dns(options.dn_file)
     ssm.set_dns(dns)