[CalendarServer-changes] [647] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Fri Dec 1 17:06:19 PST 2006
Revision: 647
http://trac.macosforge.org/projects/calendarserver/changeset/647
Author: dreid at apple.com
Date: 2006-12-01 17:06:17 -0800 (Fri, 01 Dec 2006)
Log Message:
-----------
Merge caladmin-tool-2, this creates a flexible administration tool and framework for the commandline with various output mechanisms
Modified Paths:
--------------
CalendarServer/trunk/conf/caldavd-test.plist
CalendarServer/trunk/conf/caldavd.plist
Added Paths:
-----------
CalendarServer/trunk/bin/caladmin
CalendarServer/trunk/bin/caldavd
CalendarServer/trunk/caladmin/
CalendarServer/trunk/caladmin/__init__.py
CalendarServer/trunk/caladmin/formatters.py
CalendarServer/trunk/caladmin/logs.py
CalendarServer/trunk/caladmin/options.py
CalendarServer/trunk/caladmin/principals.py
CalendarServer/trunk/caladmin/purge.py
CalendarServer/trunk/caladmin/script.py
CalendarServer/trunk/caladmin/stats.py
CalendarServer/trunk/caladmin/util.py
CalendarServer/trunk/twistedcaldav/caldavd.py
Removed Paths:
-------------
CalendarServer/trunk/bin/caldavd
CalendarServer/trunk/caladmin/__init__.py
CalendarServer/trunk/caladmin/formatters.py
CalendarServer/trunk/caladmin/logs.py
CalendarServer/trunk/caladmin/options.py
CalendarServer/trunk/caladmin/principals.py
CalendarServer/trunk/caladmin/purge.py
CalendarServer/trunk/caladmin/script.py
CalendarServer/trunk/caladmin/stats.py
CalendarServer/trunk/caladmin/util.py
Copied: CalendarServer/trunk/bin/caladmin (from rev 646, CalendarServer/branches/caladmin-tool-2/bin/caladmin)
===================================================================
--- CalendarServer/trunk/bin/caladmin (rev 0)
+++ CalendarServer/trunk/bin/caladmin 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+##
+# Copyright (c) 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 sys, os
+
+sys.path.insert(0, os.path.join(os.environ['HOME'],
+ 'projects', 'CalendarServer',
+ 'Twisted'))
+
+if __name__ == '__main__':
+ from caladmin.script import run
+ run()
Deleted: CalendarServer/trunk/bin/caldavd
===================================================================
--- CalendarServer/trunk/bin/caldavd 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/bin/caldavd 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,416 +0,0 @@
-#!/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.manhole = 0
-
- self.directoryservice = {
- "type": "OpenDirectoryService",
- "params": { "node": "/Search" },
- }
-
- self.dropbox = True
- self.dropboxName = "dropbox"
- self.dropboxACLs = True
- self.notifications = False
- self.notificationName = "notifications"
-
- 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 "Directory Service: %s" % (self.directoryservice["type"],)
- print "Directory Service Parameters: %r" % (self.directoryservice["params"],)
- print "Drop Box Enabled: %s" % (self.dropbox,)
- print "Drop Box Name: %s" % (self.dropboxName,)
- print "Drop Box ACLs are Inherited %s" % (self.dropboxACLs,)
- print "Notifications Enabled: %s" % (self.notifications,)
- print "Notification Collection Name: %s" % (self.notificationName,)
- 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):
- print "Reading configuration file %s." % (self.plistfile,)
-
- 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",
- "ManholePort": "manhole",
- "DirectoryService": "directoryservice",
- "DropBoxEnabled": "dropbox",
- "DropBoxName": "dropboxName",
- "DropBoxInheritedACLs": "dropboxACLs",
- "NotificationsEnabled": "notifications",
- "NotificationCollectionName": "notificationName",
- "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)
- else:
- print "Unknown option: %s" % (k,)
-
- 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 """
-from twistedcaldav.repository import startServer
-
-application, site = startServer(
- %(docroot)r,
- %(repo)r,
- %(doacct)s,
- %(doacl)s,
- %(dossl)s,
- %(keyfile)r,
- %(certfile)r,
- %(onlyssl)s,
- %(port)d,
- %(sslport)d,
- %(maxsize)d,
- %(quota)d,
- %(serverlogfile)r,
- %(directoryservice)r,
- %(dropbox)r,
- %(dropboxName)r,
- %(dropboxACLs)r,
- %(notifications)r,
- %(notificationName)r,
- %(manhole)d,
-)
-""" % {
- "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,
- "directoryservice": self.directoryservice,
- "dropbox": self.dropbox,
- "dropboxName": self.dropboxName,
- "dropboxACLs": self.dropboxACLs,
- "notifications": self.notifications,
- "notificationName": self.notificationName,
- "manhole": self.manhole,
-}
-
-if __name__ == "__main__":
- try:
- caldavd().run()
- except Exception, e:
- sys.exit(str(e))
Copied: CalendarServer/trunk/bin/caldavd (from rev 646, CalendarServer/branches/caladmin-tool-2/bin/caldavd)
===================================================================
--- CalendarServer/trunk/bin/caldavd (rev 0)
+++ CalendarServer/trunk/bin/caldavd 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,30 @@
+#!/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
+##
+
+
+if __name__ == "__main__":
+ from twistedcaldav.caldavd import caldavd
+
+ import sys
+
+ try:
+ caldavd().run()
+ except Exception, e:
+ sys.exit(str(e))
Copied: CalendarServer/trunk/caladmin (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin)
Deleted: CalendarServer/trunk/caladmin/__init__.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/__init__.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/__init__.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,17 +0,0 @@
-##
-# Copyright (c) 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
-##
Copied: CalendarServer/trunk/caladmin/__init__.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/__init__.py)
===================================================================
--- CalendarServer/trunk/caladmin/__init__.py (rev 0)
+++ CalendarServer/trunk/caladmin/__init__.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,17 @@
+##
+# Copyright (c) 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
+##
Deleted: CalendarServer/trunk/caladmin/formatters.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/formatters.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/formatters.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,238 +0,0 @@
-##
-# Copyright (c) 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 sys
-
-FORMATTERS = {}
-
-def registerFormatter(formatter):
- FORMATTERS[formatter.name] = formatter
-
-def listFormatters():
- return FORMATTERS.keys()
-
-def getFormatter(short):
- return FORMATTERS[short]
-
-
-class BaseFormatter(object):
- config = None
-
- def __init__(self, dest=None, options=None):
- self.dest = dest
-
- if not self.dest:
- self.dest = sys.stdout
-
- self.options = options
-
- if not options:
- self.options = {}
-
- self.reportTypes = []
-
- for attr in self.__dict__:
- if attr.startswith('report_'):
- self.reportTypes.append(attr.split('_', 1)[1])
-
- def write(self, data):
- self.dest.write(data)
- self.dest.flush()
-
- def close(self):
- self.dest.close()
-
- def printReport(self, report):
- reportPrinter = getattr(self, 'report_%s' % (report['type'],), None)
-
- if reportPrinter:
- reportPrinter(report)
-
- else:
- self.report_default(report)
-
- def report_default(self, report):
- import pprint
-
- preport = pprint.pformat(report)
-
- self.write(''.join([preport, '\n']))
- self.close()
-
-
-class PPrintFormatter(BaseFormatter):
- name = "pprint"
-
-registerFormatter(PPrintFormatter)
-
-
-class PlainFormatter(BaseFormatter):
- name = "plain"
-
- def writeLine(self, fields, spacing=None):
-
- if not spacing:
- spacing = self.options.get('spacing', 16)
-
- for f in fields:
- self.write(str(f))
- self.write(' '*(int(spacing) - len(str(f))))
-
- self.write('\n')
-
- def writeTable(self, report, fields, headings):
- if self.options.has_key('fields'):
- fields = self.options.get('fields', '').split(',')
-
- self.writeLine((headings[f] for f in fields))
-
- for record in report['records']:
- self.writeLine((record[f] for f in fields))
-
- def writeReport(self, report, name, fields, headings):
- if self.options.has_key('fields'):
- fields = self.options.get('fields', '').split(',')
-
- if name:
- self.write('%s:\n' % (name,))
-
- for f in fields:
- self.write(' %s: %s\n' % (headings[f], report['data'][f]))
-
- def report_principals(self, report):
- fields = ('principalName', 'calendarCount', 'eventCount', 'todoCount',
- 'quotaRoot', 'quotaUsed', 'quotaAvail')
-
- headings = {
- 'principalName': 'Name',
- 'calendarCount': '# Calendars',
- 'eventCount': '# Events',
- 'todoCount': '# Todos',
- 'quotaRoot': 'Quota',
- 'quotaUsed': 'Used',
- 'quotaAvail': 'Available',
- 'disabled': 'Disaabled',
- 'quotaFree': 'Free %',
- 'calendarHome': 'Home',
- }
-
- self.writeTable(report, fields, headings)
-
- report_user = report_group = report_resource = report_principals
-
- def report_stats(self, report):
- fields = ('accountCount', 'groupCount', 'calendarCount', 'eventCount',
- 'todoCount', 'diskUsage')
-
- headings = {
- 'accountCount': '# Accounts',
- 'groupCount': '# Groups',
- 'calendarCount': '# Calendars',
- 'eventCount': '# Events',
- 'todoCount': '# Todos',
- 'diskUsage': 'Disk Usage',
- }
-
- self.writeReport(report, 'Statistics', fields, headings)
-
- def report_logs(self, report):
- self.write('Log Statistics:\n')
-
- self.write(' Bytes Out: %s\n' % (report['data']['bytesOut'],))
- self.write(' # Requests:\n')
-
- for req, count in report['data']['requestCounts'].iteritems():
- self.write(' %s: %s\n' % (req, count))
-
- self.write(' User Agents:\n')
-
- for ua, count in report['data']['userAgents'].iteritems():
- self.write(' %s: %s\n' % (ua, count))
-
-registerFormatter(PlainFormatter)
-
-
-import csv
-
-class CsvFormatter(BaseFormatter):
- name = "csv"
-
- def writeList(self, fieldnames, l):
- dw = csv.DictWriter(self.dest,
- **self.options)
-
- dw.writerow(dict(zip(fieldnames,
- fieldnames)))
-
- dw.writerows(l)
-
- def report_principals(self, report):
- if 'fieldnames' not in self.options:
- self.options['fieldnames'] = [
- 'principalName',
- 'calendarHome',
- 'calendarCount',
- 'eventCount',
- 'todoCount',
- 'disabled',
- 'diskUsage',
- 'quotaRoot',
- 'quotaUsed',
- 'quotaAvail',
- 'quotaFree']
-
- self.writeDict(self.options['fieldnames'],
- report['records'])
-
- report_user = report_group = report_resource = report_principals
-
- def report_stats(self, report):
- if 'fieldnames' not in self.options:
- self.options['fieldnames'] = report['data'].keys()
- self.options['fieldnames'].sort()
-
- self.writeList(self.options['fieldnames'],
- [report['data']])
-
- report_logs = report_stats
-
-registerFormatter(CsvFormatter)
-
-import plistlib
-
-class PlistFormatter(BaseFormatter):
- name = "plist"
-
- def report_principals(self, report):
- plist = plistlib.Dict()
-
- plist[report['type']] = list(report['records'])
-
- plistlib.writePlist(plist, self.dest)
-
- report_user = report_group = report_resource = report_principals
-
- def report_stats(self, report):
- plist = plistlib.Dict()
- plist[report['type']] = report['data']
-
- plistlib.writePlist(plist, self.dest)
-
- report_logs = report_stats
-
-registerFormatter(PlistFormatter)
Copied: CalendarServer/trunk/caladmin/formatters.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/formatters.py)
===================================================================
--- CalendarServer/trunk/caladmin/formatters.py (rev 0)
+++ CalendarServer/trunk/caladmin/formatters.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,238 @@
+##
+# Copyright (c) 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 sys
+
+FORMATTERS = {}
+
+def registerFormatter(formatter):
+ FORMATTERS[formatter.name] = formatter
+
+def listFormatters():
+ return FORMATTERS.keys()
+
+def getFormatter(short):
+ return FORMATTERS[short]
+
+
+class BaseFormatter(object):
+ config = None
+
+ def __init__(self, dest=None, options=None):
+ self.dest = dest
+
+ if not self.dest:
+ self.dest = sys.stdout
+
+ self.options = options
+
+ if not options:
+ self.options = {}
+
+ self.reportTypes = []
+
+ for attr in self.__dict__:
+ if attr.startswith('report_'):
+ self.reportTypes.append(attr.split('_', 1)[1])
+
+ def write(self, data):
+ self.dest.write(data)
+ self.dest.flush()
+
+ def close(self):
+ self.dest.close()
+
+ def printReport(self, report):
+ reportPrinter = getattr(self, 'report_%s' % (report['type'],), None)
+
+ if reportPrinter:
+ reportPrinter(report)
+
+ else:
+ self.report_default(report)
+
+ def report_default(self, report):
+ import pprint
+
+ preport = pprint.pformat(report)
+
+ self.write(''.join([preport, '\n']))
+ self.close()
+
+
+class PPrintFormatter(BaseFormatter):
+ name = "pprint"
+
+registerFormatter(PPrintFormatter)
+
+
+class PlainFormatter(BaseFormatter):
+ name = "plain"
+
+ def writeLine(self, fields, spacing=None):
+
+ if not spacing:
+ spacing = self.options.get('spacing', 16)
+
+ for f in fields:
+ self.write(str(f))
+ self.write(' '*(int(spacing) - len(str(f))))
+
+ self.write('\n')
+
+ def writeTable(self, report, fields, headings):
+ if self.options.has_key('fields'):
+ fields = self.options.get('fields', '').split(',')
+
+ self.writeLine((headings[f] for f in fields))
+
+ for record in report['records']:
+ self.writeLine((record[f] for f in fields))
+
+ def writeReport(self, report, name, fields, headings):
+ if self.options.has_key('fields'):
+ fields = self.options.get('fields', '').split(',')
+
+ if name:
+ self.write('%s:\n' % (name,))
+
+ for f in fields:
+ self.write(' %s: %s\n' % (headings[f], report['data'][f]))
+
+ def report_principals(self, report):
+ fields = ('principalName', 'calendarCount', 'eventCount', 'todoCount',
+ 'quotaRoot', 'quotaUsed', 'quotaAvail')
+
+ headings = {
+ 'principalName': 'Name',
+ 'calendarCount': '# Calendars',
+ 'eventCount': '# Events',
+ 'todoCount': '# Todos',
+ 'quotaRoot': 'Quota',
+ 'quotaUsed': 'Used',
+ 'quotaAvail': 'Available',
+ 'disabled': 'Disaabled',
+ 'quotaFree': 'Free %',
+ 'calendarHome': 'Home',
+ }
+
+ self.writeTable(report, fields, headings)
+
+ report_user = report_group = report_resource = report_principals
+
+ def report_stats(self, report):
+ fields = ('accountCount', 'groupCount', 'calendarCount', 'eventCount',
+ 'todoCount', 'diskUsage')
+
+ headings = {
+ 'accountCount': '# Accounts',
+ 'groupCount': '# Groups',
+ 'calendarCount': '# Calendars',
+ 'eventCount': '# Events',
+ 'todoCount': '# Todos',
+ 'diskUsage': 'Disk Usage',
+ }
+
+ self.writeReport(report, 'Statistics', fields, headings)
+
+ def report_logs(self, report):
+ self.write('Log Statistics:\n')
+
+ self.write(' Bytes Out: %s\n' % (report['data']['bytesOut'],))
+ self.write(' # Requests:\n')
+
+ for req, count in report['data']['requestCounts'].iteritems():
+ self.write(' %s: %s\n' % (req, count))
+
+ self.write(' User Agents:\n')
+
+ for ua, count in report['data']['userAgents'].iteritems():
+ self.write(' %s: %s\n' % (ua, count))
+
+registerFormatter(PlainFormatter)
+
+
+import csv
+
+class CsvFormatter(BaseFormatter):
+ name = "csv"
+
+ def writeList(self, fieldnames, l):
+ dw = csv.DictWriter(self.dest,
+ **self.options)
+
+ dw.writerow(dict(zip(fieldnames,
+ fieldnames)))
+
+ dw.writerows(l)
+
+ def report_principals(self, report):
+ if 'fieldnames' not in self.options:
+ self.options['fieldnames'] = [
+ 'principalName',
+ 'calendarHome',
+ 'calendarCount',
+ 'eventCount',
+ 'todoCount',
+ 'disabled',
+ 'diskUsage',
+ 'quotaRoot',
+ 'quotaUsed',
+ 'quotaAvail',
+ 'quotaFree']
+
+ self.writeDict(self.options['fieldnames'],
+ report['records'])
+
+ report_user = report_group = report_resource = report_principals
+
+ def report_stats(self, report):
+ if 'fieldnames' not in self.options:
+ self.options['fieldnames'] = report['data'].keys()
+ self.options['fieldnames'].sort()
+
+ self.writeList(self.options['fieldnames'],
+ [report['data']])
+
+ report_logs = report_stats
+
+registerFormatter(CsvFormatter)
+
+import plistlib
+
+class PlistFormatter(BaseFormatter):
+ name = "plist"
+
+ def report_principals(self, report):
+ plist = plistlib.Dict()
+
+ plist[report['type']] = list(report['records'])
+
+ plistlib.writePlist(plist, self.dest)
+
+ report_user = report_group = report_resource = report_principals
+
+ def report_stats(self, report):
+ plist = plistlib.Dict()
+ plist[report['type']] = report['data']
+
+ plistlib.writePlist(plist, self.dest)
+
+ report_logs = report_stats
+
+registerFormatter(PlistFormatter)
Deleted: CalendarServer/trunk/caladmin/logs.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/logs.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/logs.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,164 +0,0 @@
-##
-# Copyright (c) 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
-##
-"""
- Log Stats:
- # Invitations sent per day/week/month
- # bytes out (bytes in not provided in the current log format.)/
- # requests
- user agents
-
-"""
-
-import plistlib
-
-from caladmin import util
-
-statsTemplate = plistlib.Dict(
- bytesOut=0,
- requestCounts=plistlib.Dict(
- ),
- invitations=plistlib.Dict(
- day=0,
- week=0,
- month=0,
- ),
- userAgents=plistlib.Dict(),
- )
-
-class Stats(object):
- def __init__(self, fp):
- self.fp = fp
-
- if self.fp.exists():
- self._data = plistlib.readPlist(self.fp.path)
- else:
- self._data = statsTemplate
- self.save()
-
- def getBytes(self):
- return self._data.bytesOut
-
- def addBytes(self, bytes):
- self._data.bytesOut += bytes
-
- def addRequest(self, request):
- if request in self._data.requestCounts:
- self._data.requestCounts[request] += 1
- else:
- self._data.requestCounts[request] = 1
-
- def getRequests(self):
- return self._data.requestCounts
-
- def addUserAgent(self, useragent):
- if useragent in self._data.userAgents:
- self._data.userAgents[useragent] += 1
- else:
- self._data.userAgents[useragent] = 1
-
- def getUserAgents(self):
- return self._data.userAgents
-
- def save(self):
- plistlib.writePlist(self._data, self.fp.path)
-
-NORMAL = 1
-INDATE = 2
-INSTRING = 3
-
-def parseCLFLine(line):
- state = NORMAL
- elements = []
-
- rest = []
-
- for c in line:
- if c == ' ':
- if state == NORMAL:
- elements.append(''.join(rest))
- rest = []
-
- elif state == INSTRING or state == INDATE:
- rest.append(c)
-
- elif c == '[':
- if state != INSTRING:
- state = INDATE
-
- elif c == ']':
- if state == INDATE:
- state = NORMAL
-
- elif c == '"':
- if state == INSTRING:
- state = NORMAL
- else:
- state = INSTRING
- elif c == '\n':
- if state == NORMAL:
- elements.append(''.join(rest))
- rest = []
-
- else:
- rest.append(c)
-
- return elements
-
-
-class LogAction(object):
- def __init__(self, config):
- self.config = config
-
- self.noOutput = self.config['nooutput']
- self.readOnly = self.config['readonly']
-
- self.logfile = self.config['logfile']
- self.stats = Stats(self.config['statsfile'])
-
- def run(self):
-
- if not self.readOnly:
- for line in self.logfile.open():
- if (line.startswith('Log opened') or
- line.startswith('Log closed')):
- continue
- else:
- pline = parseCLFLine(line)
-
- self.stats.addBytes(int(pline[6]))
- self.stats.addRequest(pline[4].split(' ')[0])
-
- if len(pline) > 7:
- self.stats.addUserAgent(pline[8])
-
- self.stats.save()
-
- if not self.noOutput:
- report = {
- 'type': 'logs',
- 'data': {
- 'bytesOut': util.prepareByteValue(self.config,
- self.stats.getBytes()),
- 'requestCounts': self.stats.getRequests(),
- 'userAgents': self.stats.getUserAgents(),
- }
- }
-
- return report
-
- return None
Copied: CalendarServer/trunk/caladmin/logs.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/logs.py)
===================================================================
--- CalendarServer/trunk/caladmin/logs.py (rev 0)
+++ CalendarServer/trunk/caladmin/logs.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,164 @@
+##
+# Copyright (c) 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
+##
+"""
+ Log Stats:
+ # Invitations sent per day/week/month
+ # bytes out (bytes in not provided in the current log format.)/
+ # requests
+ user agents
+
+"""
+
+import plistlib
+
+from caladmin import util
+
+statsTemplate = plistlib.Dict(
+ bytesOut=0,
+ requestCounts=plistlib.Dict(
+ ),
+ invitations=plistlib.Dict(
+ day=0,
+ week=0,
+ month=0,
+ ),
+ userAgents=plistlib.Dict(),
+ )
+
+class Stats(object):
+ def __init__(self, fp):
+ self.fp = fp
+
+ if self.fp.exists():
+ self._data = plistlib.readPlist(self.fp.path)
+ else:
+ self._data = statsTemplate
+ self.save()
+
+ def getBytes(self):
+ return self._data.bytesOut
+
+ def addBytes(self, bytes):
+ self._data.bytesOut += bytes
+
+ def addRequest(self, request):
+ if request in self._data.requestCounts:
+ self._data.requestCounts[request] += 1
+ else:
+ self._data.requestCounts[request] = 1
+
+ def getRequests(self):
+ return self._data.requestCounts
+
+ def addUserAgent(self, useragent):
+ if useragent in self._data.userAgents:
+ self._data.userAgents[useragent] += 1
+ else:
+ self._data.userAgents[useragent] = 1
+
+ def getUserAgents(self):
+ return self._data.userAgents
+
+ def save(self):
+ plistlib.writePlist(self._data, self.fp.path)
+
+NORMAL = 1
+INDATE = 2
+INSTRING = 3
+
+def parseCLFLine(line):
+ state = NORMAL
+ elements = []
+
+ rest = []
+
+ for c in line:
+ if c == ' ':
+ if state == NORMAL:
+ elements.append(''.join(rest))
+ rest = []
+
+ elif state == INSTRING or state == INDATE:
+ rest.append(c)
+
+ elif c == '[':
+ if state != INSTRING:
+ state = INDATE
+
+ elif c == ']':
+ if state == INDATE:
+ state = NORMAL
+
+ elif c == '"':
+ if state == INSTRING:
+ state = NORMAL
+ else:
+ state = INSTRING
+ elif c == '\n':
+ if state == NORMAL:
+ elements.append(''.join(rest))
+ rest = []
+
+ else:
+ rest.append(c)
+
+ return elements
+
+
+class LogAction(object):
+ def __init__(self, config):
+ self.config = config
+
+ self.noOutput = self.config['nooutput']
+ self.readOnly = self.config['readonly']
+
+ self.logfile = self.config['logfile']
+ self.stats = Stats(self.config['statsfile'])
+
+ def run(self):
+
+ if not self.readOnly:
+ for line in self.logfile.open():
+ if (line.startswith('Log opened') or
+ line.startswith('Log closed')):
+ continue
+ else:
+ pline = parseCLFLine(line)
+
+ self.stats.addBytes(int(pline[6]))
+ self.stats.addRequest(pline[4].split(' ')[0])
+
+ if len(pline) > 7:
+ self.stats.addUserAgent(pline[8])
+
+ self.stats.save()
+
+ if not self.noOutput:
+ report = {
+ 'type': 'logs',
+ 'data': {
+ 'bytesOut': util.prepareByteValue(self.config,
+ self.stats.getBytes()),
+ 'requestCounts': self.stats.getRequests(),
+ 'userAgents': self.stats.getUserAgents(),
+ }
+ }
+
+ return report
+
+ return None
Deleted: CalendarServer/trunk/caladmin/options.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/options.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/options.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,187 +0,0 @@
-##
-# Copyright (c) 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
-##
-
-""" "pluggable" subcommands for the caladmin script
-"""
-
-from twisted.python import usage
-
-COMMANDS = {}
-
-def registerCommand(command):
- COMMANDS[command.name] = command
-
-def listCommands():
- return COMMANDS.keys()
-
-def genSubCommandsDef():
- sc = listCommands()
- sc.sort()
-
- for name in sc:
- command = COMMANDS[name]
- yield [command.name, command.shortcut, command, command.help]
-
-
-from twisted.python import reflect
-
-class SubCommand(usage.Options):
- name = None
- shortcut = None
- help = "FIXME"
- action = None
-
- params = ()
-
- def parseArgs(self, *rest):
- self.params += rest
-
- def postOptions(self):
-
- report = reflect.namedAny(self.action)(self).run()
- if report:
- self.parent.formatter.config = self
- self.parent.formatter.printReport(report)
-
-
-PARAM_HUMAN = ['human', 'h', 'Display byte values in a human readable form.']
-PARAM_MEGA = ['megabytes', 'm', 'Display byte values in megabytes']
-PARAM_KILO = ['kilobytes', 'k', 'Display byte values in kilobytes']
-PARAM_GIGA = ['gigabytes', 'g', 'Display byte values in gigabytes']
-
-
-class PurgeOptions(SubCommand):
- name = 'purge'
- help = ('Keep your store from becoming unnecessarily large by purging '
- 'old events.')
- action = 'caladmin.purge.PurgeAction'
-
- optParameters = [
- ['days', 'n', 30, 'Age threshold for purging events.'],
- ]
-
-registerCommand(PurgeOptions)
-
-
-class StatsOptions(SubCommand):
- name = 'stats'
- help = ('Overall usage statistics.')
- action = 'caladmin.stats.StatsAction'
-
- optFlags = [
- PARAM_HUMAN,
- PARAM_KILO,
- PARAM_MEGA,
- PARAM_GIGA,
- ]
-
-registerCommand(StatsOptions)
-
-
-from twisted.python import filepath
-from twistedcaldav.caldavd import DEFAULTS
-
-class LogOptions(SubCommand):
- name = 'logs'
- help = ('Gather and report useful information from the logfiles.')
- action = 'caladmin.logs.LogAction'
-
- optFlags = [
- ['nooutput', 'n', 'Do not output anything to stdout'],
- ['readonly', 'r', 'Just read the current stats in the statistics file'],
- PARAM_HUMAN,
- PARAM_KILO,
- PARAM_MEGA,
- PARAM_GIGA,
- ]
-
- def __init__(self):
- SubCommand.__init__(self)
-
- self['logfile'] = None
- self['statsfile'] = None
-
- def opt_logfile(self, path):
- """Path to input logfile
- """
-
- self['logfile'] = path
-
- def opt_statsfile(self, path):
- """Path to destination statistics plist
- """
- self['statsfile'] = path
-
- def postOptions(self):
- if not self['logfile']:
- self['logfile'] = filepath.FilePath(
- self.parent.config['ServerLogFile'])
- else:
- self['logfile'] = filepath.FilePath(self['logfile'])
-
- if not self['statsfile']:
- self['statsfile'] = filepath.FilePath(
- self.parent.config['ServerStatsFile'])
- else:
- self['statsfile'] = filepath.FilePath(self['statsfile'])
-
- SubCommand.postOptions(self)
-
-registerCommand(LogOptions)
-
-
-class PrincipalOptions(SubCommand):
- name = None
- help = ("Gather statistics and act on %s")
- action = 'caladmin.principals.PrincipalAction'
-
- optFlags = [
- ['list', '1', 'List principal names'],
- ['disabled', 'd', 'List disabled principals'],
- PARAM_HUMAN,
- PARAM_KILO,
- PARAM_MEGA,
- PARAM_GIGA,
- ]
-
- def postOptions(self):
- report = reflect.namedAny(self.action)(self, self.name).run()
- self.parent.formatter.printReport(report)
-
-
-class UserOptions(PrincipalOptions):
- name = "user"
- help = PrincipalOptions.help % (name,)
-
-registerCommand(UserOptions)
-
-
-class GroupOptions(PrincipalOptions):
- name = "group"
- help = PrincipalOptions.help % (name,)
-
-registerCommand(GroupOptions)
-
-
-class ResourceOptions(PrincipalOptions):
- name = "resource"
- help = PrincipalOptions.help % (name,)
-
-registerCommand(ResourceOptions)
-
-
Copied: CalendarServer/trunk/caladmin/options.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/options.py)
===================================================================
--- CalendarServer/trunk/caladmin/options.py (rev 0)
+++ CalendarServer/trunk/caladmin/options.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,187 @@
+##
+# Copyright (c) 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
+##
+
+""" "pluggable" subcommands for the caladmin script
+"""
+
+from twisted.python import usage
+
+COMMANDS = {}
+
+def registerCommand(command):
+ COMMANDS[command.name] = command
+
+def listCommands():
+ return COMMANDS.keys()
+
+def genSubCommandsDef():
+ sc = listCommands()
+ sc.sort()
+
+ for name in sc:
+ command = COMMANDS[name]
+ yield [command.name, command.shortcut, command, command.help]
+
+
+from twisted.python import reflect
+
+class SubCommand(usage.Options):
+ name = None
+ shortcut = None
+ help = "FIXME"
+ action = None
+
+ params = ()
+
+ def parseArgs(self, *rest):
+ self.params += rest
+
+ def postOptions(self):
+
+ report = reflect.namedAny(self.action)(self).run()
+ if report:
+ self.parent.formatter.config = self
+ self.parent.formatter.printReport(report)
+
+
+PARAM_HUMAN = ['human', 'h', 'Display byte values in a human readable form.']
+PARAM_MEGA = ['megabytes', 'm', 'Display byte values in megabytes']
+PARAM_KILO = ['kilobytes', 'k', 'Display byte values in kilobytes']
+PARAM_GIGA = ['gigabytes', 'g', 'Display byte values in gigabytes']
+
+
+class PurgeOptions(SubCommand):
+ name = 'purge'
+ help = ('Keep your store from becoming unnecessarily large by purging '
+ 'old events.')
+ action = 'caladmin.purge.PurgeAction'
+
+ optParameters = [
+ ['days', 'n', 30, 'Age threshold for purging events.'],
+ ]
+
+registerCommand(PurgeOptions)
+
+
+class StatsOptions(SubCommand):
+ name = 'stats'
+ help = ('Overall usage statistics.')
+ action = 'caladmin.stats.StatsAction'
+
+ optFlags = [
+ PARAM_HUMAN,
+ PARAM_KILO,
+ PARAM_MEGA,
+ PARAM_GIGA,
+ ]
+
+registerCommand(StatsOptions)
+
+
+from twisted.python import filepath
+from twistedcaldav.caldavd import DEFAULTS
+
+class LogOptions(SubCommand):
+ name = 'logs'
+ help = ('Gather and report useful information from the logfiles.')
+ action = 'caladmin.logs.LogAction'
+
+ optFlags = [
+ ['nooutput', 'n', 'Do not output anything to stdout'],
+ ['readonly', 'r', 'Just read the current stats in the statistics file'],
+ PARAM_HUMAN,
+ PARAM_KILO,
+ PARAM_MEGA,
+ PARAM_GIGA,
+ ]
+
+ def __init__(self):
+ SubCommand.__init__(self)
+
+ self['logfile'] = None
+ self['statsfile'] = None
+
+ def opt_logfile(self, path):
+ """Path to input logfile
+ """
+
+ self['logfile'] = path
+
+ def opt_statsfile(self, path):
+ """Path to destination statistics plist
+ """
+ self['statsfile'] = path
+
+ def postOptions(self):
+ if not self['logfile']:
+ self['logfile'] = filepath.FilePath(
+ self.parent.config['ServerLogFile'])
+ else:
+ self['logfile'] = filepath.FilePath(self['logfile'])
+
+ if not self['statsfile']:
+ self['statsfile'] = filepath.FilePath(
+ self.parent.config['ServerStatsFile'])
+ else:
+ self['statsfile'] = filepath.FilePath(self['statsfile'])
+
+ SubCommand.postOptions(self)
+
+registerCommand(LogOptions)
+
+
+class PrincipalOptions(SubCommand):
+ name = None
+ help = ("Gather statistics and act on %s")
+ action = 'caladmin.principals.PrincipalAction'
+
+ optFlags = [
+ ['list', '1', 'List principal names'],
+ ['disabled', 'd', 'List disabled principals'],
+ PARAM_HUMAN,
+ PARAM_KILO,
+ PARAM_MEGA,
+ PARAM_GIGA,
+ ]
+
+ def postOptions(self):
+ report = reflect.namedAny(self.action)(self, self.name).run()
+ self.parent.formatter.printReport(report)
+
+
+class UserOptions(PrincipalOptions):
+ name = "user"
+ help = PrincipalOptions.help % (name,)
+
+registerCommand(UserOptions)
+
+
+class GroupOptions(PrincipalOptions):
+ name = "group"
+ help = PrincipalOptions.help % (name,)
+
+registerCommand(GroupOptions)
+
+
+class ResourceOptions(PrincipalOptions):
+ name = "resource"
+ help = PrincipalOptions.help % (name,)
+
+registerCommand(ResourceOptions)
+
+
Deleted: CalendarServer/trunk/caladmin/principals.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/principals.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/principals.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,89 +0,0 @@
-##
-# Copyright (c) 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
-##
-"""
- Account Stats:
- # of calendars
- # of events
- # storage used (including things that don't count against quota?)
- Last login?
-"""
-
-from caladmin import util
-
-class PrincipalAction(object):
- def __init__(self, config, type):
- self.config = config
- self.type = type
-
- self.formatter = self.config.parent.formatter
- self.root = self.config.parent.root
- self.calendarCollection = self.config.parent.calendarCollection
- self.principalCollection = self.config.parent.principalCollection
-
- def run(self):
- report = {'type': self.type,
- 'records': []}
-
- if not self.config.params:
- principals = util.getPrincipalList(self.principalCollection,
- self.type,
- disabled=self.config['disabled'])
-
- else:
- principals = []
- for p in self.config.params:
- p = self.principalCollection.child(self.type).child(p)
-
- if p.exists():
- if self.config['disabled']:
- if util.isPrincipalDisabled(p):
- principals.append(p)
-
- else:
- principals.append(p)
-
- def _getRecords():
- for p in principals:
- precord = {}
-
- pcal = self.calendarCollection.child(
- self.type
- ).child(p.basename())
-
- precord['principalName'] = p.basename()
-
- precord['calendarHome'] = pcal.path
-
- precord.update(
- util.getQuotaStatsForPrincipal(
- self.config,
- pcal,
- self.config.parent.config['UserQuotaBytes']))
-
- precord.update(
- util.getCalendarDataCounts(pcal))
-
- precord['diskUsage'] = util.getDiskUsage(self.config, pcal)
-
- precord['disabled'] = util.isPrincipalDisabled(p)
-
- yield precord
-
- report['records'] = _getRecords()
-
- return report
Copied: CalendarServer/trunk/caladmin/principals.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/principals.py)
===================================================================
--- CalendarServer/trunk/caladmin/principals.py (rev 0)
+++ CalendarServer/trunk/caladmin/principals.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,89 @@
+##
+# Copyright (c) 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
+##
+"""
+ Account Stats:
+ # of calendars
+ # of events
+ # storage used (including things that don't count against quota?)
+ Last login?
+"""
+
+from caladmin import util
+
+class PrincipalAction(object):
+ def __init__(self, config, type):
+ self.config = config
+ self.type = type
+
+ self.formatter = self.config.parent.formatter
+ self.root = self.config.parent.root
+ self.calendarCollection = self.config.parent.calendarCollection
+ self.principalCollection = self.config.parent.principalCollection
+
+ def run(self):
+ report = {'type': self.type,
+ 'records': []}
+
+ if not self.config.params:
+ principals = util.getPrincipalList(self.principalCollection,
+ self.type,
+ disabled=self.config['disabled'])
+
+ else:
+ principals = []
+ for p in self.config.params:
+ p = self.principalCollection.child(self.type).child(p)
+
+ if p.exists():
+ if self.config['disabled']:
+ if util.isPrincipalDisabled(p):
+ principals.append(p)
+
+ else:
+ principals.append(p)
+
+ def _getRecords():
+ for p in principals:
+ precord = {}
+
+ pcal = self.calendarCollection.child(
+ self.type
+ ).child(p.basename())
+
+ precord['principalName'] = p.basename()
+
+ precord['calendarHome'] = pcal.path
+
+ precord.update(
+ util.getQuotaStatsForPrincipal(
+ self.config,
+ pcal,
+ self.config.parent.config['UserQuotaBytes']))
+
+ precord.update(
+ util.getCalendarDataCounts(pcal))
+
+ precord['diskUsage'] = util.getDiskUsage(self.config, pcal)
+
+ precord['disabled'] = util.isPrincipalDisabled(p)
+
+ yield precord
+
+ report['records'] = _getRecords()
+
+ return report
Deleted: CalendarServer/trunk/caladmin/purge.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/purge.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/purge.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,99 +0,0 @@
-##
-# Copyright (c) 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 datetime, dateutil.tz
-
-def purgeEvents(collection, purgeDate):
- """
- Recursively purge all events older than purgeDate.
-
- for VTODO:
- * if completed
- * purge if it's dueDate is older than purgeDate.
-
- for V*:
- * purge if endDate is older than purgeDate
- """
-
- from twistedcaldav import ical
-
- files = []
- directories = []
-
- for child in collection.children():
- if child.basename() == '.db.sqlite':
- continue
-
- if child.isdir():
- directories.append(child)
-
- elif child.isfile():
- files.append(child)
-
- for directory in directories:
- purgeEvents(directory, purgeDate)
-
- for f in files:
- try:
- component = ical.Component.fromStream(f.open())
- except ValueError:
- # Not a calendar file?
- continue
-
- endDate = component.mainComponent().getEndDateUTC()
-
- if component.resourceType() == 'VTODO':
- if component.mainComponent().hasProperty('COMPLETED'):
- endDate = component.mainComponent().getDueDateUTC()
- else:
- endDate = None
-
- if isinstance(endDate, datetime.datetime):
- endDate = endDate.date()
-
- if endDate:
- if purgeDate > endDate:
- print "Purging %s, %s, %s" % (component.resourceType(),
- component.resourceUID(),
- endDate.isoformat())
- f.remove()
-
-
-class PurgeAction(object):
- def __init__(self, config):
- self.config = config
- self.calendarCollection = config.parent.calendarCollection
-
- def run(self):
- if self.config.params:
- collections = [self.calendarCollection.child(p)
- for p in self.config.params]
-
- else:
- collections = []
-
- for type in self.calendarCollection.children():
- collections.extend(type.children())
-
- purgeDate = datetime.date.today()
- purgeDate = purgeDate - datetime.timedelta(int(self.config['days']))
-
- for collection in collections:
- purgeEvents(collection, purgeDate)
Copied: CalendarServer/trunk/caladmin/purge.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/purge.py)
===================================================================
--- CalendarServer/trunk/caladmin/purge.py (rev 0)
+++ CalendarServer/trunk/caladmin/purge.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,99 @@
+##
+# Copyright (c) 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 datetime, dateutil.tz
+
+def purgeEvents(collection, purgeDate):
+ """
+ Recursively purge all events older than purgeDate.
+
+ for VTODO:
+ * if completed
+ * purge if it's dueDate is older than purgeDate.
+
+ for V*:
+ * purge if endDate is older than purgeDate
+ """
+
+ from twistedcaldav import ical
+
+ files = []
+ directories = []
+
+ for child in collection.children():
+ if child.basename() == '.db.sqlite':
+ continue
+
+ if child.isdir():
+ directories.append(child)
+
+ elif child.isfile():
+ files.append(child)
+
+ for directory in directories:
+ purgeEvents(directory, purgeDate)
+
+ for f in files:
+ try:
+ component = ical.Component.fromStream(f.open())
+ except ValueError:
+ # Not a calendar file?
+ continue
+
+ endDate = component.mainComponent().getEndDateUTC()
+
+ if component.resourceType() == 'VTODO':
+ if component.mainComponent().hasProperty('COMPLETED'):
+ endDate = component.mainComponent().getDueDateUTC()
+ else:
+ endDate = None
+
+ if isinstance(endDate, datetime.datetime):
+ endDate = endDate.date()
+
+ if endDate:
+ if purgeDate > endDate:
+ print "Purging %s, %s, %s" % (component.resourceType(),
+ component.resourceUID(),
+ endDate.isoformat())
+ f.remove()
+
+
+class PurgeAction(object):
+ def __init__(self, config):
+ self.config = config
+ self.calendarCollection = config.parent.calendarCollection
+
+ def run(self):
+ if self.config.params:
+ collections = [self.calendarCollection.child(p)
+ for p in self.config.params]
+
+ else:
+ collections = []
+
+ for type in self.calendarCollection.children():
+ collections.extend(type.children())
+
+ purgeDate = datetime.date.today()
+ purgeDate = purgeDate - datetime.timedelta(int(self.config['days']))
+
+ for collection in collections:
+ purgeEvents(collection, purgeDate)
Deleted: CalendarServer/trunk/caladmin/script.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/script.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/script.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,142 +0,0 @@
-##
-# Copyright (c) 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
-##
-
-"""
-Examples:
-
- caladmin users
-
- caladmin purge
-
- caladmin backup
-
- caladmin restore
-"""
-
-import sys, os
-
-from twisted.python import usage
-from twisted.python import filepath
-
-from plistlib import readPlist
-
-from caladmin import options
-from caladmin import formatters
-
-from twistedcaldav.caldavd import DEFAULTS, caldavd
-
-class AdminOptions(usage.Options):
- recursing = 0
- params = ()
-
- optParameters = [
- ['config', 'c', caldavd().plistfile, "Path to the caldavd.plist"],
- ['format', 'f', 'plain', ("Select an appropriate output formatter: "
- "%s" % (formatters.listFormatters(),))]
- ]
-
- def __init__(self):
- usage.Options.__init__(self)
-
- self.config = None
- self.format_options = {}
-
- def opt_option(self, option):
- if '=' in option:
- k,v = option.split('=', 1)
-
- self.format_options[k] = v
- else:
- self.format_options[option] = True
-
- opt_o = opt_option
-
- def parseArgs(self, *rest):
- self.params += rest
-
- def parseOptions(self, opts=None):
- if not opts:
- opts = ['--help']
-
- if opts == ['--help']:
- self.subCommands = options.genSubCommandsDef()
-
- usage.Options.parseOptions(self, opts)
-
- def postOptions(self):
- if self.recursing:
- return
-
- if self['config']:
- self['config'] = os.path.abspath(self['config'])
- try:
- self.config = readPlist(self['config'])
- except IOError, err:
- sys.stderr.write(("Could not open configuration file: %s (%s)\n"
- ) % (err.filename,
- err.strerror))
- sys.stderr.flush()
-
- self.config = DEFAULTS
-
- self.root = filepath.FilePath(self.config['DocumentRoot'])
- self.calendarCollection = self.root.child('calendars')
- self.principalCollection = self.root.child('principals')
-
- lf = formatters.listFormatters()
- lf.sort()
-
- if self['format'] in lf:
- self.formatter = formatters.getFormatter(self['format'])
- self.formatter = self.formatter(options=self.format_options)
- else:
- raise usage.UsageError("Please specify a valid formatter: %s" % (
- ', '.join(lf)))
-
- sc = options.listCommands()
- sc.sort()
-
- self.subCommands = options.genSubCommandsDef()
-
- self.recursing = 1
-
- self.parseOptions(self.params)
-
- if self.subCommand not in sc:
- raise usage.UsageError("Please select one of: %s" % (
- ', '.join(sc)))
-
-
-def run():
- config = AdminOptions()
-
- try:
- config.parseOptions(sys.argv[1:])
-
- except usage.UsageError, ue:
- print config
- if len(sys.argv) > 1:
- cmd = sys.argv[1]
- else:
- cmd = sys.argv[0]
-
- print "%s: %s" % (cmd, ue)
-
-
- except KeyboardInterrupt:
- sys.exit(1)
Copied: CalendarServer/trunk/caladmin/script.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/script.py)
===================================================================
--- CalendarServer/trunk/caladmin/script.py (rev 0)
+++ CalendarServer/trunk/caladmin/script.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,142 @@
+##
+# Copyright (c) 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
+##
+
+"""
+Examples:
+
+ caladmin users
+
+ caladmin purge
+
+ caladmin backup
+
+ caladmin restore
+"""
+
+import sys, os
+
+from twisted.python import usage
+from twisted.python import filepath
+
+from plistlib import readPlist
+
+from caladmin import options
+from caladmin import formatters
+
+from twistedcaldav.caldavd import DEFAULTS, caldavd
+
+class AdminOptions(usage.Options):
+ recursing = 0
+ params = ()
+
+ optParameters = [
+ ['config', 'c', caldavd().plistfile, "Path to the caldavd.plist"],
+ ['format', 'f', 'plain', ("Select an appropriate output formatter: "
+ "%s" % (formatters.listFormatters(),))]
+ ]
+
+ def __init__(self):
+ usage.Options.__init__(self)
+
+ self.config = None
+ self.format_options = {}
+
+ def opt_option(self, option):
+ if '=' in option:
+ k,v = option.split('=', 1)
+
+ self.format_options[k] = v
+ else:
+ self.format_options[option] = True
+
+ opt_o = opt_option
+
+ def parseArgs(self, *rest):
+ self.params += rest
+
+ def parseOptions(self, opts=None):
+ if not opts:
+ opts = ['--help']
+
+ if opts == ['--help']:
+ self.subCommands = options.genSubCommandsDef()
+
+ usage.Options.parseOptions(self, opts)
+
+ def postOptions(self):
+ if self.recursing:
+ return
+
+ if self['config']:
+ self['config'] = os.path.abspath(self['config'])
+ try:
+ self.config = readPlist(self['config'])
+ except IOError, err:
+ sys.stderr.write(("Could not open configuration file: %s (%s)\n"
+ ) % (err.filename,
+ err.strerror))
+ sys.stderr.flush()
+
+ self.config = DEFAULTS
+
+ self.root = filepath.FilePath(self.config['DocumentRoot'])
+ self.calendarCollection = self.root.child('calendars')
+ self.principalCollection = self.root.child('principals')
+
+ lf = formatters.listFormatters()
+ lf.sort()
+
+ if self['format'] in lf:
+ self.formatter = formatters.getFormatter(self['format'])
+ self.formatter = self.formatter(options=self.format_options)
+ else:
+ raise usage.UsageError("Please specify a valid formatter: %s" % (
+ ', '.join(lf)))
+
+ sc = options.listCommands()
+ sc.sort()
+
+ self.subCommands = options.genSubCommandsDef()
+
+ self.recursing = 1
+
+ self.parseOptions(self.params)
+
+ if self.subCommand not in sc:
+ raise usage.UsageError("Please select one of: %s" % (
+ ', '.join(sc)))
+
+
+def run():
+ config = AdminOptions()
+
+ try:
+ config.parseOptions(sys.argv[1:])
+
+ except usage.UsageError, ue:
+ print config
+ if len(sys.argv) > 1:
+ cmd = sys.argv[1]
+ else:
+ cmd = sys.argv[0]
+
+ print "%s: %s" % (cmd, ue)
+
+
+ except KeyboardInterrupt:
+ sys.exit(1)
Deleted: CalendarServer/trunk/caladmin/stats.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/stats.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/stats.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,93 +0,0 @@
-##
-# Copyright (c) 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
-##
-
-"""
-Statisitcs Types:
-
- Overall Stats:
- # of accounts
- # of calendars
- # of events
-
-"""
-import os
-import xattr
-import commands
-
-from twisted.web import microdom
-
-from twistedcaldav import ical
-
-from caladmin import util
-
-class StatsAction(object):
- def __init__(self, config):
- self.config = config
- self.formatter = self.config.parent.formatter
- self.root = self.config.parent.root
- self.calendarCollection = self.config.parent.calendarCollection
- self.principalCollection = self.config.parent.principalCollection
-
- self.calCount = 0
- self.eventCount = 0
- self.todoCount = 0
-
- self.gatherers = [
- self.getAccountCount,
- self.getGroupCount,
- self.getResourceCount,
- self.getDiskUsage]
-
- def getDiskUsage(self):
- return ("diskUsage",
- util.getDiskUsage(self.config, self.root))
-
- def getAccountCount(self):
- return ("accountCount",
- len(util.getPrincipalList(
- self.principalCollection,
- 'user')))
-
- def getGroupCount(self):
- return ("groupCount",
- len(util.getPrincipalList(
- self.principalCollection,
- 'group')))
-
- def getResourceCount(self):
- return ("resourceCount",
- len(util.getPrincipalList(
- self.principalCollection,
- 'resource')))
-
- def run(self):
- assert self.root.exists()
- stats = []
-
- report = {'type': 'stats',
- 'data': {}}
-
- report['data'].update(
- util.getCalendarDataCounts(
- self.calendarCollection))
-
- for gatherer in self.gatherers:
- stat, value = gatherer()
- report['data'][stat] = value
-
- return report
Copied: CalendarServer/trunk/caladmin/stats.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/stats.py)
===================================================================
--- CalendarServer/trunk/caladmin/stats.py (rev 0)
+++ CalendarServer/trunk/caladmin/stats.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,93 @@
+##
+# Copyright (c) 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
+##
+
+"""
+Statisitcs Types:
+
+ Overall Stats:
+ # of accounts
+ # of calendars
+ # of events
+
+"""
+import os
+import xattr
+import commands
+
+from twisted.web import microdom
+
+from twistedcaldav import ical
+
+from caladmin import util
+
+class StatsAction(object):
+ def __init__(self, config):
+ self.config = config
+ self.formatter = self.config.parent.formatter
+ self.root = self.config.parent.root
+ self.calendarCollection = self.config.parent.calendarCollection
+ self.principalCollection = self.config.parent.principalCollection
+
+ self.calCount = 0
+ self.eventCount = 0
+ self.todoCount = 0
+
+ self.gatherers = [
+ self.getAccountCount,
+ self.getGroupCount,
+ self.getResourceCount,
+ self.getDiskUsage]
+
+ def getDiskUsage(self):
+ return ("diskUsage",
+ util.getDiskUsage(self.config, self.root))
+
+ def getAccountCount(self):
+ return ("accountCount",
+ len(util.getPrincipalList(
+ self.principalCollection,
+ 'user')))
+
+ def getGroupCount(self):
+ return ("groupCount",
+ len(util.getPrincipalList(
+ self.principalCollection,
+ 'group')))
+
+ def getResourceCount(self):
+ return ("resourceCount",
+ len(util.getPrincipalList(
+ self.principalCollection,
+ 'resource')))
+
+ def run(self):
+ assert self.root.exists()
+ stats = []
+
+ report = {'type': 'stats',
+ 'data': {}}
+
+ report['data'].update(
+ util.getCalendarDataCounts(
+ self.calendarCollection))
+
+ for gatherer in self.gatherers:
+ stat, value = gatherer()
+ report['data'][stat] = value
+
+ return report
Deleted: CalendarServer/trunk/caladmin/util.py
===================================================================
--- CalendarServer/branches/caladmin-tool-2/caladmin/util.py 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/caladmin/util.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -1,195 +0,0 @@
-##
-# Copyright (c) 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 xattr
-
-import commands
-
-from twisted.web import microdom
-
-from twistedcaldav import ical
-
-def prepareByteValue(config, value):
- if config.get('human', None):
- KB = value/1024.0
- if KB < 1:
- return '%d' % (value,)
-
- MB = KB/1024.0
- if MB < 1:
- return '%5.2fKB' % (KB,)
-
- GB = MB/1024.0
- if GB < 1:
- return '%5.2fMB' % (MB,)
-
- return '%5.2fGB' % (GB,)
-
- elif config.get('gigabytes', None):
- G = value/1024.0/1024.0/1024.0
-
- return '%5.2fGB' % (G,)
-
- elif config.get('megabytes', None):
- M = value/1024.0/1024.0
-
- return '%5.2fMB' % (M,)
-
- elif config.get('kilobytes', None):
- K = value/1024.0
- return '%5.2fKB' % (K,)
-
- return value
-
-
-def getPrincipalList(principalCollection, type, disabled=False):
- typeRoot = principalCollection.child(type)
- assert typeRoot.exists(), "Does not exist: %s" % typeRoot.path
-
- pl = []
-
- for child in typeRoot.listdir():
- if child not in ['.db.sqlite']:
- p = typeRoot.child(child)
-
- if disabled:
- if isPrincipalDisabled(p):
- pl.append(p)
- else:
- pl.append(p)
-
- return pl
-
-
-def getDiskUsage(config, fp):
- status, output = commands.getstatusoutput(
- ' '.join(['/usr/bin/du', '-s', fp.path]))
-
- if status != 0:
- return 0
-
- return prepareByteValue(config, int(output.split()[0]))
-
-
-def getResourceType(fp):
- rt = 'WebDAV:{DAV:}resourcetype'
- x = xattr.xattr(fp.path)
- if not x.has_key(rt):
- return None
-
- collection = False
-
- type = None
-
- dom = microdom.parseString(x[rt])
- rt = microdom.getElementsByTagName(dom, 'resourcetype')
-
- for child in rt[0].childNodes:
- if child.tagName == 'collection':
- collection = True
- else:
- type = child.tagName
-
- return (collection, type)
-
-
-def getCalendarDataCounts(calendarCollection):
- calCount = 0
- eventCount = 0
- todoCount = 0
-
- for child in calendarCollection.walk():
- if child.isdir():
- if getResourceType(child) == (True, 'calendar'):
- calCount += 1
-
- elif child.isfile():
- try:
- component = ical.Component.fromStream(child.open())
- except ValueError:
- # not a calendar file
- continue
-
- if component.resourceType() == 'VEVENT':
- eventCount += 1
-
- elif component.resourceType() == 'VTODO':
- todoCount += 1
-
- return {'calendarCount': calCount,
- 'eventCount': eventCount,
- 'todoCount': todoCount}
-
-
-def isPrincipalDisabled(principal):
- return False
-
-
-from twisted.web2.dav.resource import TwistedQuotaRootProperty, TwistedQuotaUsedProperty
-
-quotaRoot = "WebDAV:" + TwistedQuotaRootProperty.sname().replace("/", "%2F")
-quotaUsed = "WebDAV:" + TwistedQuotaUsedProperty.sname().replace("/", "%2F")
-
-def getQuotaRoot(fp):
- x = xattr.xattr(fp.path)
- if not x.has_key(quotaRoot):
- return None
-
- dom = microdom.parseString(x[quotaRoot])
-
- qr = microdom.getElementsByTagName(dom, 'quota-root')[0]
-
- return int(qr.firstChild().value)
-
-
-def getQuotaUsed(fp):
- x = xattr.xattr(fp.path)
- if not x.has_key(quotaUsed):
- return None
-
- dom = microdom.parseString(x[quotaUsed])
-
- qu = microdom.getElementsByTagName(dom, 'quota-used')[0]
-
- return int(qu.firstChild().value)
-
-
-def getQuotaStatsForPrincipal(config, principal, defaultQuota=None, depth=2):
- quotaRoot = principal
-
- principalQuota = getQuotaRoot(quotaRoot)
-
- while not principalQuota and depth > 0:
- depth -= 1
- quotaRoot = quotaRoot.parent()
- principalQuota = getQuotaRoot(quotaRoot)
-
- if not principalQuota:
- principalQuota = defaultQuota
-
- principalUsed = getQuotaUsed(principal)
- if not principalUsed:
- principalUsed = 0
-
- principalAvail = principalQuota - principalUsed
- principalFree = (float(principalAvail)/principalQuota)*100
-
- return {'quotaRoot': prepareByteValue(config, principalQuota),
- 'quotaUsed': prepareByteValue(config, principalUsed),
- 'quotaAvail': prepareByteValue(config, principalAvail),
- 'quotaFree': principalFree}
Copied: CalendarServer/trunk/caladmin/util.py (from rev 646, CalendarServer/branches/caladmin-tool-2/caladmin/util.py)
===================================================================
--- CalendarServer/trunk/caladmin/util.py (rev 0)
+++ CalendarServer/trunk/caladmin/util.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,195 @@
+##
+# Copyright (c) 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 xattr
+
+import commands
+
+from twisted.web import microdom
+
+from twistedcaldav import ical
+
+def prepareByteValue(config, value):
+ if config.get('human', None):
+ KB = value/1024.0
+ if KB < 1:
+ return '%d' % (value,)
+
+ MB = KB/1024.0
+ if MB < 1:
+ return '%5.2fKB' % (KB,)
+
+ GB = MB/1024.0
+ if GB < 1:
+ return '%5.2fMB' % (MB,)
+
+ return '%5.2fGB' % (GB,)
+
+ elif config.get('gigabytes', None):
+ G = value/1024.0/1024.0/1024.0
+
+ return '%5.2fGB' % (G,)
+
+ elif config.get('megabytes', None):
+ M = value/1024.0/1024.0
+
+ return '%5.2fMB' % (M,)
+
+ elif config.get('kilobytes', None):
+ K = value/1024.0
+ return '%5.2fKB' % (K,)
+
+ return value
+
+
+def getPrincipalList(principalCollection, type, disabled=False):
+ typeRoot = principalCollection.child(type)
+ assert typeRoot.exists(), "Does not exist: %s" % typeRoot.path
+
+ pl = []
+
+ for child in typeRoot.listdir():
+ if child not in ['.db.sqlite']:
+ p = typeRoot.child(child)
+
+ if disabled:
+ if isPrincipalDisabled(p):
+ pl.append(p)
+ else:
+ pl.append(p)
+
+ return pl
+
+
+def getDiskUsage(config, fp):
+ status, output = commands.getstatusoutput(
+ ' '.join(['/usr/bin/du', '-s', fp.path]))
+
+ if status != 0:
+ return 0
+
+ return prepareByteValue(config, int(output.split()[0]))
+
+
+def getResourceType(fp):
+ rt = 'WebDAV:{DAV:}resourcetype'
+ x = xattr.xattr(fp.path)
+ if not x.has_key(rt):
+ return None
+
+ collection = False
+
+ type = None
+
+ dom = microdom.parseString(x[rt])
+ rt = microdom.getElementsByTagName(dom, 'resourcetype')
+
+ for child in rt[0].childNodes:
+ if child.tagName == 'collection':
+ collection = True
+ else:
+ type = child.tagName
+
+ return (collection, type)
+
+
+def getCalendarDataCounts(calendarCollection):
+ calCount = 0
+ eventCount = 0
+ todoCount = 0
+
+ for child in calendarCollection.walk():
+ if child.isdir():
+ if getResourceType(child) == (True, 'calendar'):
+ calCount += 1
+
+ elif child.isfile():
+ try:
+ component = ical.Component.fromStream(child.open())
+ except ValueError:
+ # not a calendar file
+ continue
+
+ if component.resourceType() == 'VEVENT':
+ eventCount += 1
+
+ elif component.resourceType() == 'VTODO':
+ todoCount += 1
+
+ return {'calendarCount': calCount,
+ 'eventCount': eventCount,
+ 'todoCount': todoCount}
+
+
+def isPrincipalDisabled(principal):
+ return False
+
+
+from twisted.web2.dav.resource import TwistedQuotaRootProperty, TwistedQuotaUsedProperty
+
+quotaRoot = "WebDAV:" + TwistedQuotaRootProperty.sname().replace("/", "%2F")
+quotaUsed = "WebDAV:" + TwistedQuotaUsedProperty.sname().replace("/", "%2F")
+
+def getQuotaRoot(fp):
+ x = xattr.xattr(fp.path)
+ if not x.has_key(quotaRoot):
+ return None
+
+ dom = microdom.parseString(x[quotaRoot])
+
+ qr = microdom.getElementsByTagName(dom, 'quota-root')[0]
+
+ return int(qr.firstChild().value)
+
+
+def getQuotaUsed(fp):
+ x = xattr.xattr(fp.path)
+ if not x.has_key(quotaUsed):
+ return None
+
+ dom = microdom.parseString(x[quotaUsed])
+
+ qu = microdom.getElementsByTagName(dom, 'quota-used')[0]
+
+ return int(qu.firstChild().value)
+
+
+def getQuotaStatsForPrincipal(config, principal, defaultQuota=None, depth=2):
+ quotaRoot = principal
+
+ principalQuota = getQuotaRoot(quotaRoot)
+
+ while not principalQuota and depth > 0:
+ depth -= 1
+ quotaRoot = quotaRoot.parent()
+ principalQuota = getQuotaRoot(quotaRoot)
+
+ if not principalQuota:
+ principalQuota = defaultQuota
+
+ principalUsed = getQuotaUsed(principal)
+ if not principalUsed:
+ principalUsed = 0
+
+ principalAvail = principalQuota - principalUsed
+ principalFree = (float(principalAvail)/principalQuota)*100
+
+ return {'quotaRoot': prepareByteValue(config, principalQuota),
+ 'quotaUsed': prepareByteValue(config, principalUsed),
+ 'quotaAvail': prepareByteValue(config, principalAvail),
+ 'quotaFree': principalFree}
Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/conf/caldavd-test.plist 2006-12-02 01:06:17 UTC (rev 647)
@@ -53,6 +53,9 @@
<key>ErrorLogFile</key>
<string>error.log</string>
+ <key>ServerStatsFile</key>
+ <string>stats.plist</key>
+
<key>PIDFile</key>
<string>caldavd.pid</string>
Modified: CalendarServer/trunk/conf/caldavd.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd.plist 2006-12-01 22:28:39 UTC (rev 646)
+++ CalendarServer/trunk/conf/caldavd.plist 2006-12-02 01:06:17 UTC (rev 647)
@@ -50,6 +50,9 @@
<key>ServerLogFile</key>
<string>/var/log/caldavd/server.log</string>
+ <key>ServerStatsFile</key>
+ <string>/Library/CalendarServer/Documents/stats.plist</string>
+
<key>ErrorLogFile</key>
<string>/var/log/caldavd/error.log</string>
Copied: CalendarServer/trunk/twistedcaldav/caldavd.py (from rev 646, CalendarServer/branches/caladmin-tool-2/twistedcaldav/caldavd.py)
===================================================================
--- CalendarServer/trunk/twistedcaldav/caldavd.py (rev 0)
+++ CalendarServer/trunk/twistedcaldav/caldavd.py 2006-12-02 01:06:17 UTC (rev 647)
@@ -0,0 +1,363 @@
+#!/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.
+"""
+
+DEFAULTS = {
+ 'CreateAccounts': False,
+ 'DirectoryService': {'params': {'node': '/Search'},
+ 'type': 'OpenDirectoryService'},
+ 'DocumentRoot': '/Library/CalendarServer/Documents',
+ 'DropBoxEnabled': True,
+ 'DropBoxInheritedACLs': True,
+ 'DropBoxName': 'dropbox',
+ 'ErrorLogFile': '/var/log/caldavd/error.log',
+ 'ManholePort': 0,
+ 'MaximumAttachmentSizeBytes': 1048576,
+ 'NotificationCollectionName': 'notifications',
+ 'NotificationsEnabled': False,
+ 'PIDFile': '/var/run/caldavd.pid',
+ 'Port': 8008,
+ 'Repository': '/etc/caldavd/repository.xml',
+ 'ResetAccountACLs': False,
+ 'RunStandalone': True,
+ 'SSLCertificate': '/etc/certificates/Default.crt',
+ 'SSLEnable': False,
+ 'SSLOnly': False,
+ 'SSLPort': 8443,
+ 'SSLPrivateKey': '/etc/certificates/Default.key',
+ 'ServerLogFile': '/var/log/caldavd/server.log',
+ 'ServerStatsFile': '/Library/CalendarServer/Documents/stats.plist',
+ 'UserQuotaBytes': 104857600,
+ 'Verbose': False,
+ 'twistdLocation': '/usr/share/caldavd/bin/twistd'}
+
+
+class caldavd(object):
+ """
+ Runs the caldav server.
+ """
+
+ def __init__(self):
+ # Option defaults
+ self.plistfile = "/etc/caldavd/caldavd.plist"
+
+ self.config = DEFAULTS.copy()
+
+ 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.config['RunStandalone'],)
+ print "Document Root: %s" % (self.config['DocumentRoot'],)
+ print "Repository Configuration: %s" % (self.config['Repository'],)
+ print "Generate Accounts in Repository: %s" % (self.config['CreateAccounts'],)
+ print "Reset ACLs on Generated Accounts: %s" % (self.config['ResetAccountACLs'],)
+ print "Non-ssl Port: %s" % (self.config['Port'],)
+ print "Use SSL: %s" % (self.config['SSLEnable'],)
+ print "SSL Port: %s" % (self.config['SSLPort'],)
+ print "Only Use SSL: %s" % (self.config['SSLOnly'],)
+ print "SSL Private Key File: %s" % (self.config['SSLPrivateKey'],)
+ print "SSL Certificate File: %s" % (self.config['SSLCertificate'],)
+ print "Directory Service: %s" % (self.config['DirectoryService']["type"],)
+ print "Directory Service Parameters: %r" % (self.config['DirectoryService']["params"],)
+ print "Drop Box Enabled: %s" % (self.config['DropBoxEnabled'],)
+ print "Drop Box Name: %s" % (self.config['DropBoxName'],)
+ print "Drop Box ACLs are Inherited %s" % (self.config['DropBoxInheritedACLs'],)
+ print "Notifications Enabled: %s" % (self.config['NotificationsEnabled'],)
+ print "Notification Collection Name: %s" % (self.config['NotificationCollectionName'],)
+ print "Server Log File: %s" % (self.config['ServerLogFile'],)
+ print "Error Log File: %s" % (self.config['ErrorLogFile'],)
+ print "PID File: %s" % (self.config['PIDFile'],)
+ print "twistd Location: %s" % (self.config['twistdLocation'],)
+ print "Maximum Calendar Resource Size: %d bytes" % (self.config['MaximumAttachmentSizeBytes'],)
+ print "Global per-user quota limit: %d bytes" % (self.config['UserQuotaBytes'],)
+
+ 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.config['twistdLocation'])
+ if not self.config['RunStandalone']:
+ args.append("-n")
+ args.append("--logfile=%s" % (self.config['ErrorLogFile'],))
+ args.append("--pidfile=%s" % (self.config['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.config['PIDFile']):
+ try:
+ pid = int(open(self.config['PIDFile']).read())
+ except ValueError:
+ sys.exit("Pidfile %s contains non-numeric value" % self.config['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.config['Verbose'] = True
+ elif option == "-f":
+ # We should have handled this already
+ pass
+ elif option == "-X":
+ self.config['RunStandalone'] = False
+ elif option == "-T":
+ self.config['twistdLocation'] = 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):
+ print "Reading configuration file %s." % (self.plistfile,)
+
+ root = readPlist(self.plistfile)
+
+ for k,v in root.items():
+ if k in self.config:
+ self.config[k] = v
+ else:
+ print "Unknown option: %s" % (k,)
+
+ def validate(self):
+
+ result = True
+
+ if not os.path.exists(self.config['DocumentRoot']):
+ print "Document Root does not exist: %s" % (self.config['DocumentRoot'],)
+ result = False
+
+ if not os.path.exists(self.config['Repository']):
+ print "Repository File does not exist: %s" % (self.config['Repository'],)
+ result = False
+
+ if self.config['SSLEnable'] and not os.path.exists(self.config['SSLPrivateKey']):
+ print "SSL Private Key File does not exist: %s" % (self.config['SSLPrivateKey'],)
+ result = False
+
+ if self.config['SSLEnable'] and not os.path.exists(self.config['SSLCertificate']):
+ print "SSL Certificate File does not exist: %s" % (self.config['SSLCertificate'],)
+ result = False
+
+ if not self.config['SSLEnable'] and self.config['SSLOnly']:
+ self.config['SSLEnable'] = True
+
+ if not self.config['RunStandalone']:
+ self.config['ErrorLogFile'] = "-"
+
+ if not os.path.exists(self.config['twistdLocation']):
+ print "twistd does not exist: %s" % (self.config['twistdLocation'],)
+ 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 """
+from twistedcaldav.repository import startServer
+
+application, site = startServer(
+ %(DocumentRoot)r,
+ %(Repository)r,
+ %(CreateAccounts)s,
+ %(ResetAccountACLs)s,
+ %(SSLEnable)s,
+ %(SSLPrivateKey)r,
+ %(SSLCertificate)r,
+ %(SSLOnly)s,
+ %(Port)d,
+ %(SSLPort)d,
+ %(MaximumAttachmentSizeBytes)d,
+ %(UserQuotaBytes)d,
+ %(ServerLogFile)r,
+ %(DirectoryService)r,
+ %(DropBoxEnabled)r,
+ %(DropBoxName)r,
+ %(DropBoxInheritedACLs)r,
+ %(NotificationsEnabled)r,
+ %(NotificationCollectionName)r,
+ %(ManholePort)d,
+)
+""" % self.config
+
+
+if __name__ == "__main__":
+ try:
+ caldavd().run()
+ except Exception, e:
+ sys.exit(str(e))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061201/98553d3c/attachment.html
More information about the calendarserver-changes
mailing list