From: Leandro Lucarella Date: Thu, 27 Dec 2007 15:53:10 +0000 (-0300) Subject: Merge branch 'procman' X-Git-Url: https://git.llucax.com/software/pymin.git/commitdiff_plain/55efba31a241826ed31597b14f2b5eb9efe808f1?ds=inline;hp=--cc Merge branch 'procman' * procman: Bugfix: set the catched signal to None *after* calling the signal handler. Improve vrrp restorable defaults readability. Use procman.restart() to restart vrrp service. Add ProcessManager.restart() method to block until the restart is done. Use procman to manage vrrp service. Bugfix: raise a KeyError, don't return it. Bugfix: call ProcessInfo.stop() in the right way (without parameters). Bugfix: use self instead of an unbinded pi object when killing a process. Remove unused ProcessInfo.last_return attribute. Bugfix: use correct module for simbol ECHILD. Handle SIGCHLD in PyminDaemon. Add a global ProcessManager instance and functions to procman module. Implement timer in PyminDaemon using EventLoop signal handling. Support general signals handling in EventLoop. Replace time.sleep() for signal.pause() in the ProcessManager test. Improve ProcessManager to manage registerable named services. Add a ProcessManager class to manage processes. Improve ProcessManager to manage registerable named services. Add a ProcessManager class to manage processes. Conflicts: pymin/eventloop.py pymin/pymindaemon.py pymin/services/vrrp/__init__.py --- 55efba31a241826ed31597b14f2b5eb9efe808f1 diff --cc pymin/eventloop.py index c9f6ade,fe3c4ec..0f72012 --- a/pymin/eventloop.py +++ b/pymin/eventloop.py @@@ -94,8 -95,6 +96,7 @@@ class EventLoop See EventLoop class documentation for more info. """ - log.debug(u'EventLoop(%r, %r, %r, %r)', file, handler, - timer, timer_handler) ++ log.debug(u'EventLoop(%r, %r, %r)', file, handler, signals) self.poll = select.poll() self._stop = False self.__register(file) @@@ -146,35 -164,25 +167,30 @@@ Wait for events and handle then when they arrive. If once is True, then only 1 event is processed and then this method returns. """ + log.debug(u'EventLoop.loop(%s)', once) - # Flag modified by the signal handler - global timeout - # If we use a timer, we set up the signal - if self.timer is not None: - signal.signal(signal.SIGALRM, alarm_handler) - self.handle_timer() - signal.alarm(self.timer) + # List of pending signals + global signals while True: try: + log.debug(u'EventLoop.loop: polling') res = self.poll.poll() except select.error, e: - # The error is not an interrupt caused by the alarm, then raise - if e.args[0] != errno.EINTR or not timeout: + # The error is not an interrupt caused by a signal, then raise + if e.args[0] != errno.EINTR or not signals: raise LoopInterruptedError(e) - # There was a timeout, so execute the timer handler - if timeout: - log.debug(u'EventLoop.loop: timer catched, handling...') - timeout = False - self.handle_timer() - signal.alarm(self.timer) - # Not a timeout, execute the regular handler - else: - log.debug(u'EventLoop.loop: no timeout, handle event') + # If we have signals to process, we just do it + have_signals = bool(signals) + while signals: - self.handle_signal(signals.pop(0)) ++ signum = signals.pop(0) ++ log.debug(u'EventLoop.loop: processing signal %d...', signum) ++ self.handle_signal(signum) + # No signals to process, execute the regular handler + if not have_signals: ++ log.debug(u'EventLoop.loop: processing event...') self.handle() - import os # Look if we have to stop if self._stop or once: + log.debug(u'EventLoop.loop: stopped') self._stop = False break @@@ -203,7 -205,7 +219,7 @@@ if __name__ == '__main__' p = EventLoop(0, handle) -- os.write(1, 'Say something once: ') ++ os.write(1, 'Say something once:\n') p.loop(once=True) os.write(1, 'Great!\n') diff --cc pymin/pymindaemon.py index a65f19c,3881857..067a727 --- a/pymin/pymindaemon.py +++ b/pymin/pymindaemon.py @@@ -43,28 -43,35 +44,38 @@@ class PyminDaemon(eventloop.EventLoop) See PyminDaemon class documentation for more info. """ + log.debug(u'PyminDaemon(%r, %r, %r)', root, bind_addr, timer) + # Timer timeout time + self.timer = timer # Create and bind socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(bind_addr) - # Create EventLoop - eventloop.EventLoop.__init__(self, sock, timer=timer) - # Create Dispatcher - #TODO root.pymin = PyminHandler() - self.dispatcher = dispatcher.Dispatcher(root) # Signal handling - def quit(signum, frame): + def quit(loop, signum): - print "Shuting down ..." + log.debug(u'PyminDaemon quit() handler: signal %r', signum) + log.info(u'Shutting down...') - self.stop() # tell main event loop to stop - def reload_config(signum, frame): + loop.stop() # tell main event loop to stop + def reload_config(loop, signum): - print "Reloading configuration..." + log.debug(u'PyminDaemon reload_config() handler: signal %r', signum) + log.info(u'Reloading configuration...') # TODO iterate handlers list propagating reload action - signal.signal(signal.SIGINT, quit) - signal.signal(signal.SIGTERM, quit) - signal.signal(signal.SIGUSR1, reload_config) + def timer(loop, signum): + loop.handle_timer() + signal.alarm(loop.timer) + def child(loop, signum): + procman.sigchild_handler(signum) + # Create EventLoop + eventloop.EventLoop.__init__(self, sock, signals={ + signal.SIGINT: quit, + signal.SIGTERM: quit, + signal.SIGUSR1: reload_config, + signal.SIGALRM: timer, + signal.SIGCHLD: child, + }) + # Create Dispatcher + #TODO root.pymin = PyminHandler() + self.dispatcher = dispatcher.Dispatcher(root) def handle(self): r"handle() -> None :: Handle incoming events using the dispatcher." @@@ -96,7 -101,10 +107,11 @@@ def run(self): r"run() -> None :: Run the event loop (shortcut to loop())" + log.debug(u'PyminDaemon.loop()') + # Start the timer + self.handle_timer() + signal.alarm(self.timer) + # Loop try: return self.loop() except eventloop.LoopInterruptedError, e: diff --cc pymin/services/vrrp/__init__.py index 4739c52,9fdfd1a..f13db3e --- a/pymin/services/vrrp/__init__.py +++ b/pymin/services/vrrp/__init__.py @@@ -4,8 -4,8 +4,9 @@@ import o from os import path from signal import SIGTERM from subprocess import Popen, PIPE +import logging ; log = logging.getLogger('pymin.services.vrrp') + from pymin import procman from pymin.seqtools import Sequence from pymin.dispatcher import Handler, handler, HandlerError from pymin.services.util import Restorable, TransactionalHandler, \ @@@ -22,39 -24,42 +25,45 @@@ class VrrpHandler(Restorable, Parameter _persistent_attrs = ['params'] _restorable_defaults = dict( - params = dict( ipaddress='192.168.0.1', - id = '1', - prio = '', - dev = 'eth0', - ), - ) + params = dict( + ipaddress = '192.168.0.1', + id = '1', + prio = '', + dev = 'eth0', + persist = True, + ), + ) + + @property + def _command(self): + command = ['vrrpd', '-i', self.params['dev'], '-v', self.params['id']] + if self.params['prio']: + command.extend(('-p', self.params['prio'])) + command.append(self.params['ipaddress']) + return command def _service_start(self): + log.debug(u'VrrpHandler._service_start()') - if self.params['prio'] != '': - call(('vrrp', '-i', self.params['dev'], '-v', self.params['id'], - '-p', self.params['prio'], self.params['ipaddress'])) - else: - call(('vrrp', '-i', self.params['dev'], '-v', self.params['id'], \ - self.params['ipaddress'])) + procinfo = procman.get('vrrp') + procinfo.command = self._command + procinfo.persist = self.params['persist'] + procman.start('vrrp') def _service_stop(self): + log.debug(u'VrrpHandler._service_stop()') - try: - pid_filename = 'vrrpd_%(dev)s_%(id)s.pid' % self.params - log.debug(u'VrrpHandler._service_stop: getting pid from %r', - pid_filename) - pid = file(path.join(self._pid_dir, pid_filename )).read() - pid = int(pid.strip()) - log.debug(u'VrrpHandler._service_stop: killing pid %r', pid) - os.kill(pid, SIGTERM) - except (IOError, OSError), e: - log.debug(u'VrrpHandler._service_stop: error %r', e) + procman.stop('vrrp') + + def _service_restart(self): + procinfo = procman.get('vrrp') + procinfo.command = self._command + procinfo.persist = self.params['persist'] + procman.restart('vrrp') def __init__(self, pickle_dir='.', config_dir='.', pid_dir='.'): + log.debug(u'VrrpHandler(%r, %r, $r)', pickle_dir, config_dir, pid_dir) self._persistent_dir = pickle_dir self._pid_dir = pid_dir + procman.register('vrrp', None) ServiceHandler.__init__(self)