[CalendarServer-changes] [224] CalendarServer/trunk/bin/dircaldavd

source_changes at macosforge.org source_changes at macosforge.org
Mon Oct 2 14:19:58 PDT 2006


Revision: 224
          http://trac.macosforge.org/projects/calendarserver/changeset/224
Author:   cdaboo at apple.com
Date:     2006-10-02 14:19:58 -0700 (Mon, 02 Oct 2006)

Log Message:
-----------
Temporary caldavd-like file that uses OpenDirectory authenticator (credentials checker) instead of property-based password checker.

Added Paths:
-----------
    CalendarServer/trunk/bin/dircaldavd

Added: CalendarServer/trunk/bin/dircaldavd
===================================================================
--- CalendarServer/trunk/bin/dircaldavd	                        (rev 0)
+++ CalendarServer/trunk/bin/dircaldavd	2006-10-02 21:19:58 UTC (rev 224)
@@ -0,0 +1,462 @@
+#!/usr/bin/env python
+
+##
+# 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: Cyrus Daboo, cdaboo at apple.com
+##
+
+import sys
+import os
+import getopt
+import signal
+from tempfile import mkstemp
+
+try:
+    #
+    # plistlib is only included in Mac OS distributions of Python.
+    # This may change in Python 2.6, see:
+    #   https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1555501&group_id=5470
+    #
+    from plistlib import readPlist
+except ImportError:
+    from twistedcaldav.py.plistlib import readPlist
+
+sys.path.insert(0, "/usr/share/caldavd/lib/python")
+
+"""
+Parse the command line and read in a configuration file and then launch the server.
+"""
+
+class caldavd(object):
+    """
+    Runs the caldav server.
+    """
+    
+    def __init__(self):
+        # Option defaults
+        self.plistfile = "/etc/caldavd/caldavd.plist"
+
+        self.verbose = False
+        self.daemonize = True
+        self.docroot = "/Library/CalendarServer/Documents"
+
+        self.repo = "/etc/caldavd/repository.xml"
+        self.doacct = False
+        self.doacl = False
+
+        self.port = 8008
+        self.dossl = False
+        self.sslport = 8443
+        self.onlyssl = False
+        self.keyfile = "/etc/certificates/Default.key"
+        self.certfile = "/etc/certificates/Default.crt"
+
+        self.serverlogfile = "/var/log/caldavd/server.log"
+        self.errorlogfile = "/var/log/caldavd/error.log"
+        self.pidfile = "/var/run/caldavd.pid"
+        
+        self.twistd = "/usr/share/caldavd/bin/twistd"
+
+        self.maxsize  =  1048576    # 1 Mb
+        self.quota    =  104857600  # 100 Mb
+        
+        self.action = None
+    
+    def printit(self):
+        """
+        Print out details about the current configuration.
+        """
+
+        print "Current Configuration"
+        print ""
+        print "Configuration File:               %s" % (self.plistfile,)
+        print ""
+        print "Run as daemon:                    %s" % (self.daemonize,)
+        print "Document Root:                    %s" % (self.docroot,)
+        print "Repository Configuration:         %s" % (self.repo,)
+        print "Generate Accounts in Repository:  %s" % (self.doacct,)
+        print "Reset ACLs on Generated Accounts: %s" % (self.doacl,)
+        print "Non-ssl Port:                     %s" % (self.port,)
+        print "Use SSL:                          %s" % (self.dossl,)
+        print "SSL Port:                         %s" % (self.sslport,)
+        print "Only Use SSL:                     %s" % (self.onlyssl,)
+        print "SSL Private Key File:             %s" % (self.keyfile,)
+        print "SSL Certificate File:             %s" % (self.certfile,)
+        print "Server Log File:                  %s" % (self.serverlogfile,)
+        print "Error Log File:                   %s" % (self.errorlogfile,)
+        print "PID File:                         %s" % (self.pidfile,)
+        print "twistd Location:                  %s" % (self.twistd,)
+        print "Maximum Calendar Resource Size:   %d bytes" % (self.maxsize,)
+        print "Global per-user quota limit:      %d bytes" % (self.quota,)
+
+    def run(self):
+        """
+        Run the caldavd server using the provided options and configuration.
+
+        @raise: C:{ValueError} if options or configuration are wrong.
+        """
+
+        # Parse command line options and config file
+        self.commandLine()
+        if self.action is None:
+            return
+        
+        # Dispatch action
+        {"start":   self.start,
+         "stop":    self.stop,
+         "restart": self.restart}[self.action]()
+
+    def start(self):
+        """
+        Start the caldavd server.
+        """
+        
+        print "Starting CalDAV Server",
+        try:
+            fd, tac = mkstemp(prefix="caldav")
+            os.write(fd, self.generateTAC())
+            os.close(fd)
+        except Exception, e:
+            print "        [Failed]"
+            print "Unable to create temporary file for server configuration."
+            print e
+            sys.exit(1)
+        
+        # Create arguments for twistd
+        args = [os.path.basename(sys.executable)]
+        args.append(self.twistd)
+        if not self.daemonize:
+            args.append("-n")
+        args.append("--logfile=%s" % (self.errorlogfile,))
+        args.append("--pidfile=%s" % (self.pidfile,))
+        args.append("-y")
+        args.append(tac)
+
+        # Create environment for twistd
+        environment = dict(os.environ)
+        environment["PYTHONPATH"] = ":".join(sys.path)
+
+        # spawn the twistd python process
+        try:
+            os.spawnve(os.P_WAIT, sys.executable, args, environment)
+        except OSError, why:
+            print "        [Failed]"
+            print "Error: %s" % (why[1],)
+        
+        # Get rid of temp file
+        try:
+            os.unlink(tac)
+        except:
+            pass
+        print "        [Done]"
+    
+    def stop(self):
+        """
+        Stop the caldavd server.
+        """
+        
+        if os.path.exists(self.pidfile):
+            try:
+                pid = int(open(self.pidfile).read())
+            except ValueError:
+                sys.exit("Pidfile %s contains non-numeric value" % self.pidfile)
+            try:
+                print "Stopping CalDAV Server",
+                os.kill(pid, signal.SIGTERM)
+                print "        [Done]"
+            except OSError, why:
+                print "        [Failed]"
+                print "Error: %s" % (why[1],)
+        else:
+            print "CalDAV server is not running"
+    
+    def restart(self):
+        """
+        Restart the caldavd server.
+        """
+        self.stop()
+        self.start()
+        
+    def commandLine(self):
+        """
+        Parse the command line options into the config object.
+        
+        @return: the C{str} for the requested action, or C{None} when
+            immediate exit is called for.
+        @raise: C{ValueError} when a problem occurs with the options.
+        """
+        options, args = getopt.getopt(sys.argv[1:], "hvf:XT:p")
+        
+        # Process the plist file first, then the options, so that command line
+        # options get to override plist options
+        pls = [p for p in options if p[0] == "-f"]
+        if len(pls) == 1:
+            self.plistfile = pls[0][1]
+        if not os.path.exists(self.plistfile):
+            print "Configuration file does not exist: %s" % (self.plistfile,)
+            raise ValueError
+        self.parsePlist()
+    
+        # Parse all the options
+        do_print = False
+        for option, value in options:
+            if option == "-h":
+                self.usage()
+                return
+            elif option == "-v":
+                self.verbose = True
+            elif option == "-f":
+                # We should have handled this already
+                pass
+            elif option == "-X":
+                self.daemonize = False
+            elif option == "-T":
+                self.twistd = value
+            elif option == "-p":
+                do_print = True
+            else:
+                print "Unrecognized option: %s" % (option,)
+                self.usage()
+                raise ValueError
+        
+        # Print out config if requested
+        if do_print:
+            self.printit()
+            return
+    
+        # Process arguments
+        if len(args) == 0:
+            print "No arguments given. One of start, stop or restart must be present."
+            self.usage()
+            raise ValueError
+        elif len(args) > 1:
+            print "Too many arguments given. Only one of start, stop or restart must be present."
+            self.usage()
+            raise ValueError
+        elif args[0] not in ("start", "stop", "restart"):
+            print "Wrong arguments given: %s" % (args[0],)
+            self.usage()
+            raise ValueError
+        
+        # Verify that configuration is valid
+        if not self.validate():
+            raise ValueError
+    
+        self.action = args[0]
+    
+    def parsePlist(self):
+        root = readPlist(self.plistfile)
+        
+        # dict that maps between plist keys and class attributes
+        mapper = {
+                   "Verbose":                    "verbose",
+                   "RunStandalone":              "daemonize",
+                   "DocumentRoot":               "docroot",
+                   "Port":                       "port",
+                   "SSLEnable":                  "dossl",
+                   "SSLPort":                    "sslport",
+                   "SSLOnly":                    "onlyssl",
+                   "SSLPrivateKey":              "keyfile",
+                   "SSLCertificate":             "certfile",
+                   "ServerLogFile":              "serverlogfile",
+                   "ErrorLogFile":               "errorlogfile",
+                   "PIDFile":                    "pidfile",
+                   "Repository":                 "repo",
+                   "CreateAccounts":             "doacct",
+                   "ResetAccountACLs":           "doacl",
+                   "twistdLocation":             "twistd",
+                   "MaximumAttachmentSizeBytes": "maxsize",
+                   "UserQuotaBytes":             "quota",
+                  }
+        
+        for k,v in root.items():
+            if mapper.has_key(k) and hasattr(self, mapper[k]):
+                setattr(self, mapper[k], v)
+
+    def validate(self):
+        
+        result = True
+
+        if not os.path.exists(self.docroot):
+            print "Document Root does not exist: %s" % (self.docroot,)
+            result = False
+
+        if not os.path.exists(self.repo):
+            print "Repository File does not exist: %s" % (self.repo,)
+            result = False
+
+        if self.dossl and not os.path.exists(self.keyfile):
+            print "SSL Private Key File does not exist: %s" % (self.keyfile,)
+            result = False
+
+        if self.dossl and not os.path.exists(self.certfile):
+            print "SSL Certificate File does not exist: %s" % (self.certfile,)
+            result = False
+
+        if not self.dossl and self.onlyssl:
+            self.dossl = True
+
+        if not self.daemonize:
+            self.errorlogfile = "-"
+
+        if not os.path.exists(self.twistd):
+            print "twistd does not exist: %s" % (self.twistd,)
+            result = False
+            
+        return result
+
+    def usage(self):
+        default = caldavd()
+        print """Usage: caldavd [options] start|stop|restart
+Options:
+    -h          Print this help and exit
+    -v          Be verbose
+    -f config   Specify path to configuration file [""" + default.plistfile + """]
+    -X          Do not daemonize
+    -T twistd   Specify path to twistd [""" + default.twistd + """]
+    -p          Print current configuration and exit
+"""
+    
+    def generateTAC(self):
+        return """
+import os
+from os.path import dirname, join
+
+docroot   = "%(docroot)s"
+repo      = "%(repo)s"
+doacct    =  %(doacct)s
+doacl     =  %(doacl)s
+dossl     =  %(dossl)s
+keyfile   = "%(keyfile)s"
+certfile  = "%(certfile)s"
+onlyssl   =  %(onlyssl)s
+port      =  %(port)d
+sslport   =  %(sslport)d
+maxsize   =  %(maxsize)d
+quota     =  %(quota)d
+serverlog = "%(serverlogfile)s"
+
+
+if not dossl and onlyssl:
+    dossl = True
+
+if os.path.exists(docroot):
+    print "Document root is: %%s" %% (docroot,)
+else:
+    raise IOError("No such docroot: %%s" %% (docroot,))
+
+if os.path.exists(repo):
+    print "Repository configuration is: %%s" %% (repo,)
+else:
+    raise IOError("No such repo: %%s" %% (repo,))
+
+if dossl:
+    if os.path.exists(keyfile):
+        print "Using SSL private key file: %%s" %% (keyfile,)
+    else:
+        raise IOError("SSL Private Key file does not exist: %%s" %% (keyfile,))
+
+    if os.path.exists(certfile):
+        print "Using SSL certificate file: %%s" %% (certfile,)
+    else:
+        raise IOError("SSL Certificate file does not exist: %%s" %% (certfile,))
+
+from twisted.application.service  import Application, IServiceCollection, MultiService
+from twisted.application.internet import TCPServer
+from twisted.cred.portal          import Portal
+from twisted.web2.auth            import basic
+from twisted.web2.dav             import davxml, auth
+from twisted.web2.log             import LogWrapperResource
+from twisted.web2.server          import Site
+from twisted.web2.channel.http    import HTTPFactory
+from twistedcaldav.directory      import DirectoryCredentialsChecker
+
+if dossl:
+    from twisted.application.internet import SSLServer
+    from twisted.internet.ssl         import DefaultOpenSSLContextFactory
+
+from twistedcaldav.logging    import RotatingFileAccessLoggingObserver
+from twistedcaldav.repository import RepositoryBuilder
+
+class Web2Service(MultiService):
+    def __init__(self, logObserver):
+        self.logObserver = logObserver
+        MultiService.__init__(self)
+
+    def startService(self):
+        MultiService.startService(self)
+        self.logObserver.start()
+
+    def stopService(self):
+        MultiService.stopService(self)
+        self.logObserver.stop()
+
+builder = RepositoryBuilder(docroot,
+                            doAccounts=doacct,
+                            resetACLs=doacl,
+                            maxsize=maxsize,
+                            quota=quota)
+builder.buildFromFile(repo)
+rootresource = builder.docRoot.collection.resource
+
+application = Application("CalDAVServer")
+parent      = IServiceCollection(application)
+web2        = Web2Service(RotatingFileAccessLoggingObserver(serverlog))
+web2.setServiceParent(parent)
+parent = web2
+
+portal = Portal(auth.DavRealm())
+portal.registerChecker(DirectoryCredentialsChecker())
+
+credentialFactories = (basic.BasicCredentialFactory(""),)
+
+loginInterfaces = (auth.IPrincipal,)
+
+site = Site(LogWrapperResource(auth.AuthenticationWrapper(rootresource, 
+                                                          portal,
+                                                          credentialFactories,
+                                                          loginInterfaces)))
+
+factory     = HTTPFactory(site)
+
+if not onlyssl:
+    print "Starting http server"
+    server = TCPServer(port, factory).setServiceParent(parent)
+
+if dossl:
+    print "Starting https server"
+    sslContext = DefaultOpenSSLContextFactory(keyfile, certfile)
+    sslserver  = SSLServer(sslport, factory, sslContext).setServiceParent(parent)
+""" % {"docroot":       self.docroot,
+       "repo":          self.repo,
+       "doacct":        self.doacct,
+       "doacl":         self.doacl,
+       "dossl":         self.dossl,
+       "keyfile":       self.keyfile,
+       "certfile":      self.certfile,
+       "onlyssl":       self.onlyssl,
+       "port":          self.port,
+       "sslport":       self.sslport,
+       "maxsize":       self.maxsize,
+       "quota":         self.quota,
+       "serverlogfile": self.serverlogfile}
+
+if __name__ == "__main__":
+
+    try:
+        caldavd().run()
+    except Exception, e:
+        sys.exit(str(e))


Property changes on: CalendarServer/trunk/bin/dircaldavd
___________________________________________________________________
Name: svn:executable
   + *

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


More information about the calendarserver-changes mailing list