[CalendarServer-changes] [963] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Jan 8 09:30:53 PST 2007


Revision: 963
          http://trac.macosforge.org/projects/calendarserver/changeset/963
Author:   dreid at apple.com
Date:     2007-01-08 09:30:53 -0800 (Mon, 08 Jan 2007)

Log Message:
-----------
merge users/dreid/cluster-2 to provide support for a variety of clustering schemes including multiprocess support on a single machine with a tcp load balancer.  The default by is still a single process.

Modified Paths:
--------------
    CalendarServer/trunk/bin/caldavd
    CalendarServer/trunk/conf/caldavd-test.plist
    CalendarServer/trunk/conf/caldavd.plist
    CalendarServer/trunk/run
    CalendarServer/trunk/support/Makefile.Apple
    CalendarServer/trunk/twistedcaldav/config.py
    CalendarServer/trunk/twistedcaldav/tap.py

Added Paths:
-----------
    CalendarServer/trunk/lib-patches/Twisted/twisted.python.procutils.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.runner.procmon.patch
    CalendarServer/trunk/twistedcaldav/cluster.py

Modified: CalendarServer/trunk/bin/caldavd
===================================================================
--- CalendarServer/trunk/bin/caldavd	2007-01-08 17:22:20 UTC (rev 962)
+++ CalendarServer/trunk/bin/caldavd	2007-01-08 17:30:53 UTC (rev 963)
@@ -27,6 +27,7 @@
 configfile="";
 twistdpath="$(type -p twistd)";
 plugin_name="caldav";
+service_type="";
 
 py_version ()
 {
@@ -78,7 +79,7 @@
     
     if [ "${1--}" != "-" ]; then echo "${1}"; echo; fi;
 
-    echo "Usage: ${program} [-hX] [-u username] [-g groupname] [-T twistd] [-f caldavd.plist]";
+    echo "Usage: ${program} [-hX] [-u username] [-g groupname] [-T twistd] [-t type] [-f caldavd.plist]";
     echo "Options:";
     echo "        -h Print this help and exit";
     echo "        -X Do not daemonize";
@@ -86,12 +87,13 @@
     echo "        -g Group to run as";
     echo "        -f Configuration file to read";
     echo "        -T Path to twistd binary";
+    echo "        -t Service type (master, slave, standalone, cluster)";
     
     if [ "${1-}" == "-" ]; then return 0; fi;
     exit 64;
 }
 
-while getopts 'hXu:g:f:T:P:' option; do
+while getopts 'hXu:g:f:T:P:t:' option; do
     case "${option}" in
         '?') usage; ;;
         'h') usage -; exit 0; ;;
@@ -101,6 +103,7 @@
         'u') username="-u ${OPTARG}"; ;;
         'g') groupname="-g ${OPTARG}"; ;;
         'P') plugin_name="${OPTARG}"; ;;
+        't') service_type="-o ServerType=${OPTARG}"; ;;
     esac;
 done;
 
@@ -108,4 +111,4 @@
 
 if [ $# != 0 ]; then usage "Unrecognized arguments:" "$@"; fi;
 
-exec "${python}" "${twistdpath}" "${daemonize}" ${username} ${groupname} "${plugin_name}" ${configfile};
+exec "${python}" "${twistdpath}" "${daemonize}" ${username} ${groupname} "${plugin_name}" ${configfile} ${service_type};

Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist	2007-01-08 17:22:20 UTC (rev 962)
+++ CalendarServer/trunk/conf/caldavd-test.plist	2007-01-08 17:30:53 UTC (rev 963)
@@ -29,6 +29,11 @@
   <key>DocumentRoot</key>
   <string>twistedcaldav/test/data/</string>
 
+  <key>BindAddress</key>
+  <array>
+    <string>127.0.0.1</string>
+  </array>
+
   <key>Port</key>
   <integer>8008</integer>
 
@@ -186,5 +191,35 @@
   <array>
     <string>/principals/user/admin/</string>
   </array>
+  
+  <key>ServerType</key>
+  <string>singleprocess</string>
+  
+  <key>MultiProcess</key>
+  <dict>
+    <key>NumProcesses</key>
+    <integer>2</integer>
+
+    <key>LoadBalancer</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+
+      <key>Scheduler</key>
+      <!-- Least Connections -->
+      <string>leastconns</string>
+      <!-- Round Robin -->
+      <!-- <string>roundrobin</string> -->
+      <!-- Least Connections and Round Robin -->
+      <!-- <string>leastconnsrr</string> -->
+
+    </dict>    
+  </dict>
+
+  <key>pydirLocation</key>
+  <string>../pydirector-1.0.0/pydir.py</string>
+
+  <key>pydirConfig</key>
+  <string>conf/pydir.xml</string>
 </dict>
 </plist>

Modified: CalendarServer/trunk/conf/caldavd.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd.plist	2007-01-08 17:22:20 UTC (rev 962)
+++ CalendarServer/trunk/conf/caldavd.plist	2007-01-08 17:30:53 UTC (rev 963)
@@ -29,6 +29,10 @@
   <key>DocumentRoot</key>
   <string>/Library/CalendarServer/Documents</string>
 
+  <key>BindAddress</key>
+  <array>
+  </array>
+
   <key>Port</key>
   <integer>8008</integer>
 
@@ -132,5 +136,33 @@
   <array>
     <string>/principals/user/admin/</string>
   </array>
+  <key>ServerType</key>
+  <string>singleprocess</string>
+  
+  <key>MultiProcess</key>
+  <dict>
+    <key>NumProcesses</key>
+    <integer>0</integer>
+
+    <key>LoadBalancer</key>
+    <dict>
+      <key>Enabled</key>
+      <false/>
+
+      <key>Scheduler</key>
+      <!-- Least Connections -->
+      <string>leastconns</string>
+      <!-- Round Robin -->
+      <!-- <string>roundrobin</string> -->
+      <!-- Least Connections and Round Robin -->
+      <!-- <string>leastconnsrr</string> -->
+    </dict>    
+  </dict>
+
+  <key>pydirLocation</key>
+  <string>/usr/share/caldavd/bin/pydir++.py</string>
+
+  <key>pydirConfig</key>
+  <string>/etc/caldvad/pydir.xml</string>
 </dict>
 </plist>

Copied: CalendarServer/trunk/lib-patches/Twisted/twisted.python.procutils.patch (from rev 962, CalendarServer/branches/users/dreid/cluster-2/lib-patches/Twisted/twisted.python.procutils.patch)
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.python.procutils.patch	                        (rev 0)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.python.procutils.patch	2007-01-08 17:30:53 UTC (rev 963)
@@ -0,0 +1,13 @@
+Index: twisted/python/procutils.py
+===================================================================
+--- twisted/python/procutils.py	(revision 18545)
++++ twisted/python/procutils.py	(working copy)
+@@ -33,7 +33,7 @@
+     """
+     result = []
+     exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
+-    for p in os.environ['PATH'].split(os.pathsep):
++    for p in os.environ.get('PATH', '').split(os.pathsep):
+         p = os.path.join(p, name)
+         if os.access(p, flags):
+             result.append(p)

Copied: CalendarServer/trunk/lib-patches/Twisted/twisted.runner.procmon.patch (from rev 962, CalendarServer/branches/users/dreid/cluster-2/lib-patches/Twisted/twisted.runner.procmon.patch)
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.runner.procmon.patch	                        (rev 0)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.runner.procmon.patch	2007-01-08 17:30:53 UTC (rev 963)
@@ -0,0 +1,29 @@
+Index: twisted/runner/procmon.py
+===================================================================
+--- twisted/runner/procmon.py	(revision 18545)
++++ twisted/runner/procmon.py	(working copy)
+@@ -130,10 +130,10 @@
+         self.consistency = reactor.callLater(self.consistencyDelay,
+                                              self._checkConsistency)
+ 
+-    def addProcess(self, name, args, uid=None, gid=None):
++    def addProcess(self, name, args, uid=None, gid=None, env={}):
+         if self.processes.has_key(name):
+             raise KeyError("remove %s first" % name)
+-        self.processes[name] = args, uid, gid
++        self.processes[name] = args, uid, gid, env
+         if self.active:
+             self.startProcess(name)
+ 
+@@ -175,9 +175,9 @@
+         p = self.protocols[name] = LoggingProtocol()
+         p.service = self
+         p.name = name
+-        args, uid, gid = self.processes[name]
++        args, uid, gid, env = self.processes[name]
+         self.timeStarted[name] = time.time()
+-        reactor.spawnProcess(p, args[0], args, uid=uid, gid=gid)
++        reactor.spawnProcess(p, args[0], args, uid=uid, gid=gid, env=env)
+ 
+     def _forceStopProcess(self, proc):
+         try:

Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run	2007-01-08 17:22:20 UTC (rev 962)
+++ CalendarServer/trunk/run	2007-01-08 17:30:53 UTC (rev 963)
@@ -35,6 +35,7 @@
       install="";
     daemonize="-X";
   plugin_name="caldav";
+ service_type="singleprocess";
 
 usage ()
 {
@@ -53,12 +54,13 @@
   echo "        -d  Run caldavd as a daemon";
   echo "        -i  Perform a system install into dst; implies -s";
   echo "        -I  Perform a home install into dst; implies -s";
+  echo "        -t  Select the type of server to run (singleprocess, multiprocess, or master)";
 
   if [ "${1-}" == "-" ]; then return 0; fi;
   exit 64;
 }
 
-while getopts 'hvsfnpdP:i:I:' option; do
+while getopts 'hvsfnpdP:i:I:t:' option; do
   case "$option" in
     '?') usage; ;;
     'h') usage -; exit 0; ;;
@@ -71,6 +73,7 @@
     'P')   plugin_name="${OPTARG}"; ;;
     'i')    setup_only="true"; install="${OPTARG}"; install_flag="--root="; ;;
     'I')    setup_only="true"; install="${wd}/build/dst"; install_flag="--root="; install_home="${OPTARG}"; ;;
+    't')  service_type="${OPTARG}"; ;;
   esac;
 done;
 shift $((${OPTIND} - 1));
@@ -186,7 +189,7 @@
         -f "${config}"                                \
         -T "${twisted}/bin/twistd"                    \
         -P "${plugin_name}"                           \
-        ;
+        -t "${service_type}";
     cd /;
   fi;
 }
@@ -527,6 +530,20 @@
 fi;
 
 #
+# PyDirector
+#
+
+if ! py_have_module pydirector; then
+    pydirector="${top}/pydirector-1.0.0";
+    
+    www_get "PyDirector" "${pydirector}" http://easynews.dl.sourceforge.net/sourceforge/pythondirector/pydirector-1.0.0.tar.gz;
+    py_build "PyDirector" "${pydirector}" false;
+    py_install "PyDirector" "${pydirector}";
+
+    export PYTHONPATH="${PYTHONPATH}:${pydirector}/build/${py_platform_libdir}";
+fi;
+
+#
 # Calendar Server
 #
 

Modified: CalendarServer/trunk/support/Makefile.Apple
===================================================================
--- CalendarServer/trunk/support/Makefile.Apple	2007-01-08 17:22:20 UTC (rev 962)
+++ CalendarServer/trunk/support/Makefile.Apple	2007-01-08 17:30:53 UTC (rev 963)
@@ -63,6 +63,7 @@
 Twisted::
 	@echo "Building Twisted..."
 	$(_v) cd $(BuildDirectory)/Twisted && $(Environment) $(PYTHON) twisted/topfiles/setup.py install $(PY_INSTALL_FLAGS)
+        $(_v) cd $(BuildDirectory)/Twisted && $(Environment) $(PYTHON) twisted/runner/topfiles/setup.py build
 	$(_v) cd $(BuildDirectory)/Twisted && $(TwistedSubEnvironment) $(PYTHON) twisted/web/topfiles/setup.py build
 	$(_v) cd $(BuildDirectory)/Twisted && $(TwistedSubEnvironment) $(PYTHON) twisted/web2/topfiles/setup.py build
 

Copied: CalendarServer/trunk/twistedcaldav/cluster.py (from rev 962, CalendarServer/branches/users/dreid/cluster-2/twistedcaldav/cluster.py)
===================================================================
--- CalendarServer/trunk/twistedcaldav/cluster.py	                        (rev 0)
+++ CalendarServer/trunk/twistedcaldav/cluster.py	2007-01-08 17:30:53 UTC (rev 963)
@@ -0,0 +1,177 @@
+##
+# Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# DRI: David Reid, dreid at apple.com
+##
+
+import os
+import sys
+import tempfile
+
+from twisted.runner import procmon
+
+from twistedcaldav.config import config
+
+serviceTemplate = """
+    <service name="%(name)s">
+	<listen ip="%(bindAddress)s:%(port)s" />
+	<group name="main" scheduler="%(scheduler)s">
+	  %(hosts)s
+        </group>
+        <enable group="main" />
+    </service>
+"""
+
+configTemplate = """
+<pdconfig>
+    %(services)s
+</pdconfig>
+"""
+
+hostTemplate = '<host name="%(name)s" ip="%(bindAddress)s:%(port)s" />'
+
+
+class TwistdSlaveProcess(object):
+    prefix = "caldav"
+
+    def __init__(self, twistdLocation, configFile, interfaces, port, sslPort):
+        self.twistd = twistdLocation
+
+        self.configFile = configFile
+
+        self.port = port
+        self.sslPort = sslPort
+
+        self.pidFile = os.path.join(
+            os.path.dirname(config.PIDFile),
+            '%s.pid' % (self.getName(),))
+
+        self.interfaces = interfaces
+
+    def getName(self):
+        return '%s-%s' % (self.prefix, self.port)
+    
+    def getSSLName(self):
+        return '%s-%s' % (self.prefix, self.sslPort)
+
+    def getCommandLine(self):
+        return [
+            sys.executable,
+            self.twistd, '-n', 'caldav', 
+            '-f', self.configFile,
+            '-o', 'ServerType=singleprocess',
+            '-o', 'BindAddress=%s' % (','.join(self.interfaces),),
+            '-o', 'Port=%s' % (self.port,),
+            '-o', 'SSLPort=%s' % (self.sslPort,),
+            '-o', 'PIDFile=%s' % (self.pidFile,)]
+    
+    def getHostLine(self, ssl=None):
+        name = self.getName()
+        port = self.port
+
+        if ssl:
+            name = self.getSSLName()
+            port = self.sslPort
+
+        return hostTemplate % {'name': name,
+                               'port': port,
+                               'bindAddress': '127.0.0.1'}
+
+def makeService_multiprocess(self, options):
+    service = procmon.ProcessMonitor()
+    
+    parentEnv = {'PYTHONPATH': os.environ.get('PYTHONPATH', ''),}
+
+    hosts = []
+    sslHosts = []
+
+    port = config.Port
+    sslport = config.SSLPort
+
+    bindAddress = ['127.0.0.1']
+
+    if not config.MultiProcess['LoadBalancer']['Enabled']:
+        bindAddress = config.BindAddress
+
+    for p in xrange(0, config.MultiProcess['NumProcesses']):
+        port += 1
+        sslport += 1
+
+        process = TwistdSlaveProcess(config.twistdLocation,
+                                     options['config'],
+                                     bindAddress,
+                                     port, sslport)
+
+        service.addProcess(process.getName(),
+                           process.getCommandLine(),
+                           uid=options.parent['uid'],
+                           gid=options.parent['gid'],
+                           env=parentEnv)
+        
+        if not config.SSLOnly:
+            hosts.append(process.getHostLine())
+
+        if config.SSLEnable:
+            sslHosts.append(process.getHostLine(ssl=True))
+
+    if config.MultiProcess['LoadBalancer']['Enabled']: 
+        services = []
+
+        if not config.BindAddress:
+            config.BindAddress = ['']
+
+        for bindAddress in config.BindAddress:
+            if not config.SSLOnly:
+                services.append(serviceTemplate % {
+                        'name': 'http',
+                        'bindAddress': bindAddress,
+                        'port': config.Port,
+                        'scheduler': 
+                        config.MultiProcess['LoadBalancer']['Scheduler'],
+                        'hosts': '\n'.join(hosts)
+                        })
+            
+            if config.SSLEnable:
+                services.append(serviceTemplate % {
+                        'name': 'https',
+                        'bindAddress': bindAddress,
+                        'port': config.SSLPort,
+                        'scheduler': 
+                        config.MultiProcess['LoadBalancer']['Scheduler'],
+                        'hosts': '\n'.join(sslHosts),
+                        })
+
+        pdconfig = configTemplate % {
+            'services': '\n'.join(services),
+            }
+                
+        fd, fname = tempfile.mkstemp(prefix='pydir')
+        os.write(fd, pdconfig)
+        os.close(fd)
+        
+        service.addProcess('pydir', [sys.executable,
+                                     config.pydirLocation,
+                                     fname])
+    
+    return service
+
+def makeService_pydir(self, options):
+    service = procmon.ProcessMonitor()
+
+    service.addProcess('pydir', [sys.executable,
+                                 config.pydirLocation,
+                                 config.pydirConfig])
+
+    return service

Modified: CalendarServer/trunk/twistedcaldav/config.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/config.py	2007-01-08 17:22:20 UTC (rev 962)
+++ CalendarServer/trunk/twistedcaldav/config.py	2007-01-08 17:30:53 UTC (rev 963)
@@ -23,6 +23,7 @@
 defaultConfigFile = '/etc/caldavd/caldavd.plist'
 
 defaultConfig = {
+    'BindAddress': ['127.0.0.1'],
     'CalendarUserProxyEnabled': True,
     'DirectoryService': {
         'params': {'node': '/Search'},
@@ -46,7 +47,6 @@
     'ServerStatsFile': '/Library/CalendarServer/Documents/stats.plist',
     'UserQuotaBytes': 104857600,
     'Verbose': False,
-    'twistdLocation': '/usr/share/caldavd/bin/twistd',
     'SACLEnable': False,
     'Authentication': {
         'Basic': {
@@ -61,10 +61,23 @@
             'ServicePrincipal': '',
             },
         },
-    'AdminPrincipals': ['/principals/user/admin/']
-}
+    'AdminPrincipals': ['/principals/user/admin/'],
 
+    'twistdLocation': '/usr/share/caldavd/bin/twistd',
+    'pydirLocation': '/usr/share/caldavd/bin/pydir++.py',
+    'pydirConfig': '/etc/caldavd/pydir.xml',
 
+    'ServerType': 'singleprocess',
+
+    'MultiProcess': {
+        'NumProcesses': 10,
+        'LoadBalancer': {
+            'Enabled': True,
+            'Scheduler': 'leastconns',
+            },
+        },
+    }
+
 class Config (object):
     def __init__(self, defaults):
         self.update(defaults)

Modified: CalendarServer/trunk/twistedcaldav/tap.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/tap.py	2007-01-08 17:22:20 UTC (rev 962)
+++ CalendarServer/trunk/twistedcaldav/tap.py	2007-01-08 17:30:53 UTC (rev 963)
@@ -23,7 +23,7 @@
 
 from twisted.python import log
 
-from twisted.python.usage import Options
+from twisted.python.usage import Options, UsageError
 from twisted.python.reflect import namedClass
 
 from twisted.application import internet, service
@@ -41,6 +41,7 @@
 from twisted.web2.log import LogWrapperResource
 from twisted.web2.server import Site
 
+from twistedcaldav.cluster import makeService_multiprocess, makeService_pydir
 from twistedcaldav.config import config, parseConfig, defaultConfig
 from twistedcaldav.logging import RotatingFileAccessLoggingObserver
 from twistedcaldav.root import RootResource
@@ -102,7 +103,7 @@
                     value = value.split(',')
 
                 elif isinstance(defaultConfig[key], dict):
-                    raise usage.UsageError(
+                    raise UsageError(
                         "We do not support dict options on the command line")
 
             self.overrides[key] = value
@@ -140,7 +141,7 @@
     principalResourceClass = DirectoryPrincipalProvisioningResource
     calendarResourceClass = CalendarHomeProvisioningFile
 
-    def makeService(self, options):
+    def makeService_singleprocess(self, options):
         #
         # Setup the Directory
         #
@@ -248,19 +249,46 @@
         
         service = CalDAVService(logObserver)
 
-        if not config.SSLOnly:
-            httpService = internet.TCPServer(int(config.Port), channel)
+        if not config.BindAddress:
+            config.BindAddress = ['']
 
-            httpService.setServiceParent(service)
+        for bindAddress in config.BindAddress:
+            if not config.SSLOnly:
+                httpService = internet.TCPServer(int(config.Port), channel,
+                                                 interface=bindAddress)
+                httpService.setServiceParent(service)
 
-        if config.SSLEnable:
-            from twisted.internet.ssl import DefaultOpenSSLContextFactory
-            httpsService = internet.SSLServer(
-                int(config.SSLPort),
-                channel,
-                DefaultOpenSSLContextFactory(config.SSLPrivateKey,
-                                             config.SSLCertificate))
+            if config.SSLEnable:
+                from twisted.internet.ssl import DefaultOpenSSLContextFactory
+                httpsService = internet.SSLServer(
+                    int(config.SSLPort),
+                    channel,
+                    DefaultOpenSSLContextFactory(config.SSLPrivateKey,
+                                                 config.SSLCertificate),
+                    interface=bindAddress
+                    )
+                httpsService.setServiceParent(service)
+            
+        return service
 
-            httpsService.setServiceParent(service)
+    makeService_slave = makeService_singleprocess
+
+    makeService_multiprocess = makeService_multiprocess
+
+    makeService_master = makeService_pydir
+
+    def makeService(self, options):
+        serverType = config.ServerType
+        
+        serviceMethod = getattr(self, 'makeService_%s' % (serverType,), None)
+
+        if not serviceMethod:
+            raise UsageError(
+                ("Unknown server type %s, please choose: singleprocess, "
+                 "multiprocess, master, slave" % (serverType,)))
+
+        else:
+            return serviceMethod(options)
             
-        return service
+
+                                

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070108/aa19ce56/attachment.html


More information about the calendarserver-changes mailing list