[CalendarServer-changes] [9371] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Mon Jun 18 11:24:20 PDT 2012
Revision: 9371
http://trac.macosforge.org/projects/calendarserver/changeset/9371
Author: sagen at apple.com
Date: 2012-06-18 11:24:20 -0700 (Mon, 18 Jun 2012)
Log Message:
-----------
SIGHUP now restarts the service allowing *all* configuration changes to be applied.
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/tap/caldav.py
CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
CalendarServer/trunk/twistedcaldav/test/util.py
Added Paths:
-----------
CalendarServer/trunk/calendarserver/tap/test/reexec.tac
Modified: CalendarServer/trunk/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/caldav.py 2012-06-18 18:20:10 UTC (rev 9370)
+++ CalendarServer/trunk/calendarserver/tap/caldav.py 2012-06-18 18:24:20 UTC (rev 9371)
@@ -22,6 +22,7 @@
]
import os
+import signal
import socket
import stat
import sys
@@ -562,7 +563,50 @@
env=PARENT_ENVIRONMENT)
+class ReExecService(MultiService, LoggingMixIn):
+ """
+ A MultiService which catches SIGHUP and re-exec's the process.
+ """
+ def __init__(self, pidfilePath, reactor=None):
+ """
+ @param pidFilePath: Absolute path to the pidfile which will need to be
+ removed
+ @type pidFilePath: C{str}
+ """
+ self.pidfilePath = pidfilePath
+ if reactor is None:
+ from twisted.internet import reactor
+ self.reactor = reactor
+ MultiService.__init__(self)
+
+ def reExec(self):
+ """
+ Removes pidfile, registers an exec to happen after shutdown, then
+ stops the reactor.
+ """
+ try:
+ self.log_info("Removing pidfile: %s" % (self.pidfilePath,))
+ os.remove(self.pidfilePath)
+ except OSError:
+ pass
+ self.reactor.addSystemEventTrigger("after", "shutdown", os.execv,
+ sys.executable, [sys.executable] + sys.argv)
+ self.reactor.stop()
+
+ def sighupHandler(self, num, frame):
+ self.log_info("SIGHUP received - restarting")
+ self.reactor.callFromThread(self.reExec)
+
+ def startService(self):
+ self.previousHandler = signal.signal(signal.SIGHUP, self.sighupHandler)
+ MultiService.startService(self)
+
+ def stopService(self):
+ signal.signal(signal.SIGHUP, self.previousHandler)
+ MultiService.stopService(self)
+
+
class CalDAVServiceMaker (LoggingMixIn):
implements(IPlugin, IServiceMaker)
@@ -637,30 +681,7 @@
else:
return "%s: %s" % (frame.f_code.co_name, frame.f_lineno)
- import signal
- def sighup_handler(num, frame):
- self.log_info("SIGHUP received at %s" % (location(frame),))
- # Reload the config file
- try:
- config.reload()
- except ConfigurationError, e:
- self.log_error("Invalid configuration: {0}".format(e))
-
- # If combined service send signal to all caldavd children
- if hasattr(service, "processMonitor"):
- service.processMonitor.signalAll(signal.SIGHUP, "caldav")
-
- # FIXME: There is no memcachepool.getCachePool
- # Also, better option is probably to add a hook to
- # the config object instead of doing things here.
- #self.log_info("Suggesting new max clients for memcache.")
- #memcachepool.getCachePool().suggestMaxClients(
- # config.Memcached.MaxClients
- #)
-
- signal.signal(signal.SIGHUP, sighup_handler)
-
return service
@@ -1063,6 +1084,9 @@
"""
s = ErrorLoggingMultiService()
+ # Add a service to re-exec the master when it receives SIGHUP
+ ReExecService(config.PIDFile).setServiceParent(s)
+
# Make sure no old socket files are lying around.
self.deleteStaleSocketFiles()
Added: CalendarServer/trunk/calendarserver/tap/test/reexec.tac
===================================================================
--- CalendarServer/trunk/calendarserver/tap/test/reexec.tac (rev 0)
+++ CalendarServer/trunk/calendarserver/tap/test/reexec.tac 2012-06-18 18:24:20 UTC (rev 9371)
@@ -0,0 +1,14 @@
+from twisted.application import service
+from calendarserver.tap.caldav import ReExecService
+
+class TestService(service.Service):
+ def startService(self):
+ print "START"
+ def stopService(self):
+ print "STOP"
+
+application = service.Application("ReExec Tester")
+reExecService = ReExecService("twistd.pid")
+reExecService.setServiceParent(application)
+testService = TestService()
+testService.setServiceParent(reExecService)
Modified: CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/test/test_caldav.py 2012-06-18 18:20:10 UTC (rev 9370)
+++ CalendarServer/trunk/calendarserver/tap/test/test_caldav.py 2012-06-18 18:24:20 UTC (rev 9371)
@@ -28,11 +28,13 @@
from twisted.python.usage import Options, UsageError
from twisted.python.reflect import namedAny
from twisted.python import log
+from twisted.python.procutils import which
from twisted.internet.interfaces import IProcessTransport, IReactorProcess
from twisted.internet.protocol import ServerFactory
-from twisted.internet.defer import Deferred
+from twisted.internet.defer import Deferred, inlineCallbacks
from twisted.internet.task import Clock
+from twisted.internet import reactor
from twisted.application.service import IService, IServiceCollection
from twisted.application import internet
@@ -51,7 +53,7 @@
from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-from twistedcaldav.test.util import TestCase
+from twistedcaldav.test.util import TestCase, CapturingProcessProtocol
from calendarserver.tap.caldav import (
CalDAVOptions, CalDAVServiceMaker, CalDAVService, GroupOwnedUNIXServer,
@@ -1159,3 +1161,31 @@
self.assertIn(option, commandLine)
self.assertEquals(commandLine[commandLine.index(option) - 1], '-o')
+
+
+
+
+
+class ReExecServiceTests(TestCase):
+
+ @inlineCallbacks
+ def test_reExecService(self):
+ """
+ Verify that sending a HUP to the test reexec.tac causes startService
+ and stopService to be called again by counting the number of times
+ START and STOP appear in the process output.
+ """
+ tacFilePath = os.path.join(os.path.dirname(__file__), "reexec.tac")
+ twistd = which("twistd")[0]
+ deferred = Deferred()
+ proc = reactor.spawnProcess(
+ CapturingProcessProtocol(deferred, None), twistd,
+ [twistd, '-n', '-y', tacFilePath],
+ env=os.environ
+ )
+ reactor.callLater(3, proc.signalProcess, "HUP")
+ reactor.callLater(6, proc.signalProcess, "TERM")
+ output = yield deferred
+ self.assertEquals(output.count("START"), 2)
+ self.assertEquals(output.count("STOP"), 2)
+
Modified: CalendarServer/trunk/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/util.py 2012-06-18 18:20:10 UTC (rev 9370)
+++ CalendarServer/trunk/twistedcaldav/test/util.py 2012-06-18 18:24:20 UTC (rev 9371)
@@ -24,7 +24,6 @@
from twisted.python.failure import Failure
from twisted.internet.base import DelayedCall
from twisted.internet.defer import succeed, fail, inlineCallbacks, returnValue
-from twisted.internet.error import ProcessDone
from twisted.internet.protocol import ProcessProtocol
from twext.python.memcacheclient import ClientFactory
@@ -670,8 +669,7 @@
"""
The process is over, fire the Deferred with the output.
"""
- if why.check(ProcessDone) and not self.error:
+ if why.value.exitCode == 0 and not self.error:
self.deferred.callback(''.join(self.output))
else:
- self.deferred.errback(ErrorOutput(''.join(self.error)))
-
+ self.deferred.errback(ErrorOutput(repr(''.join(self.error))))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120618/a083a173/attachment-0001.html>
More information about the calendarserver-changes
mailing list