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 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.')
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)
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
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')
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
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
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
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')
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
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
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()
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()
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)
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 )
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
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)
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)
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 _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()
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")
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
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()
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()
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)
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)
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
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)
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)
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()
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 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()
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))
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
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)
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()
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()
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)
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 )
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
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()
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
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 __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
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))
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()
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 )
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())
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)
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)