[CalendarServer-changes] [8868] CalendarServer/branches/users/gaya/ldapdirectorybacker
source_changes at macosforge.org
source_changes at macosforge.org
Wed Mar 14 13:49:10 PDT 2012
Revision: 8868
http://trac.macosforge.org/projects/calendarserver/changeset/8868
Author: gaya at apple.com
Date: 2012-03-14 13:49:10 -0700 (Wed, 14 Mar 2012)
Log Message:
-----------
merge in TOT
Modified Paths:
--------------
CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/principals.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/cmd.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/terminal.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/vfs.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/validcalendardata.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/migration/calendarmigrator.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/migration/test/test_migrator.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/tools/protocolanalysis.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/tools/request_monitor.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/idirectory.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectory.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectorybacker.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/test/test_ldapdirectory.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directorybackedaddressbook.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/caldav.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/imip.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/implicit.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/ischedule.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/itip.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/processing.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/scheduler.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/test/test_itip.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/stdconfig.py
Property Changed:
----------------
CalendarServer/branches/users/gaya/ldapdirectorybacker/
CalendarServer/branches/users/gaya/ldapdirectorybacker/support/build.sh
CalendarServer/branches/users/gaya/ldapdirectorybacker/txdav/caldav/datastore/index_file.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/txdav/caldav/datastore/test/test_index_file.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/txdav/carddav/datastore/index_file.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/txdav/carddav/datastore/test/test_index_file.py
Property changes on: CalendarServer/branches/users/gaya/ldapdirectorybacker
___________________________________________________________________
Modified: svn:mergeinfo
- /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/table-alias:8651-8664
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/wsanchez/transations:5515-5593
+ /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/table-alias:8651-8664
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/wsanchez/transations:5515-5593
/CalendarServer/trunk:8831-8867
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/principals.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/principals.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/principals.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -657,7 +657,11 @@
@inlineCallbacks
def action_removeProxyPrincipal(principal, proxyPrincipal, **kwargs):
try:
- (yield removeProxy(principal, proxyPrincipal, **kwargs))
+ removed = (yield removeProxy(principal, proxyPrincipal, **kwargs))
+ if removed:
+ print "Removed %s as a proxy for %s" % (
+ prettyPrincipal(proxyPrincipal),
+ prettyPrincipal(principal))
except ProxyError, e:
print "Error:", e
except ProxyWarning, e:
@@ -666,6 +670,7 @@
@inlineCallbacks
def removeProxy(principal, proxyPrincipal, **kwargs):
+ removed = False
proxyTypes = kwargs.get("proxyTypes", ("read", "write"))
for proxyType in proxyTypes:
proxyURL = proxyPrincipal.url()
@@ -685,11 +690,15 @@
if len(memberURLs) == len(membersProperty.children):
# No change
continue
+ else:
+ removed = True
membersProperty = davxml.GroupMemberSet(*memberURLs)
(yield subPrincipal.writeProperty(membersProperty, None))
+ returnValue(removed)
+
@inlineCallbacks
def action_setAutoSchedule(principal, autoSchedule):
if principal.record.recordType == "groups":
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/cmd.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/cmd.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/cmd.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
##
# Copyright (c) 2011-2012 Apple Inc. All rights reserved.
#
@@ -347,6 +346,9 @@
usage: exit
"""
+ if tokens:
+ raise UnknownArguments(tokens)
+
self.exit()
@@ -356,6 +358,9 @@
usage: python
"""
+ if tokens:
+ raise UnknownArguments(tokens)
+
if not hasattr(self, "_interpreter"):
# Bring in some helpful local variables.
from txdav.common.datastore.sql_tables import schema
@@ -397,9 +402,26 @@
def addOutput(self, bytes, async=False):
+ """
+ This is a delegate method, called by ManholeInterpreter.
+ """
if async:
self.terminal.write("... interrupted for Deferred ...\n")
self.terminal.write(bytes)
if async:
self.terminal.write("\n")
self.drawInputLine()
+
+
+ def cmd_sql(self, tokens):
+ """
+ Switch to an SQL prompt.
+
+ usage: sql
+ """
+ if tokens:
+ raise UnknownArguments(tokens)
+
+ raise NotImplementedError("")
+
+ cmd_sql.hidden = "Not implemented."
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/terminal.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/terminal.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/terminal.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
##
# Copyright (c) 2011-2012 Apple Inc. All rights reserved.
#
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/vfs.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/vfs.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/shell/vfs.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
##
# Copyright (c) 2011-2012 Apple Inc. All rights reserved.
#
@@ -21,12 +20,14 @@
from cStringIO import StringIO
-#from twisted.python import log
+from twisted.python import log
from twisted.internet.defer import succeed
from twisted.internet.defer import inlineCallbacks, returnValue
from txdav.common.icommondatastore import NotFoundError
+from twistedcaldav.ical import InvalidICalendarDataError
+
from calendarserver.tools.tables import Table
@@ -153,6 +154,7 @@
self._childClasses["users" ] = UsersFolder
self._childClasses["locations"] = LocationsFolder
self._childClasses["resources"] = ResourcesFolder
+ self._childClasses["groups" ] = GroupsFolder
class UIDsFolder(Folder):
@@ -191,7 +193,7 @@
return PrincipalHomeFolder(
self.service,
- self.path + (record.uid,),
+ self.path + (name,),
record.uid,
record=record
)
@@ -226,6 +228,13 @@
recordType = "resources"
+class GroupsFolder(RecordFolder):
+ """
+ Folder containing all group principals by name.
+ """
+ recordType = "groups"
+
+
class PrincipalHomeFolder(Folder):
"""
Folder containing everything related to a given principal.
@@ -295,7 +304,63 @@
def list(self):
return Folder.list(self)
+ def describe(self):
+ result = []
+ result.append("Principal home for UID: %s\n" % (self.uid,))
+ if self.record is not None:
+ #
+ # Basic record info
+ #
+
+ rows = []
+
+ def add(name, value):
+ if value:
+ rows.append((name, value))
+
+ add("Service" , self.record.service )
+ add("Record Type", self.record.recordType)
+
+ for shortName in self.record.shortNames:
+ add("Short Name", shortName)
+
+ add("GUID" , self.record.guid )
+ add("Full Name" , self.record.fullName )
+ add("First Name", self.record.firstName)
+ add("Last Name" , self.record.lastName )
+
+ for email in self.record.emailAddresses:
+ add("Email Address", email)
+
+ for cua in self.record.calendarUserAddresses:
+ add("Calendar User Address", cua)
+
+ add("Server ID" , self.record.serverID )
+ add("Partition ID" , self.record.partitionID )
+ add("Enabled" , self.record.enabled )
+ add("Enabled for Calendar", self.record.enabledForCalendaring )
+ add("Enabled for Contacts", self.record.enabledForAddressBooks)
+
+ if rows:
+ result.append("Directory Record:")
+ result.append(tableString(rows, header=("Name", "Value")))
+
+ #
+ # Group memberships
+ #
+ rows = []
+
+ for group in self.record.groups():
+ rows.append((group.uid, group.shortNames[0], group.fullName))
+
+ if rows:
+ result.append("Group Memberships:")
+ result.append(tableString(rows, header=("UID", "Short Name", "Full Name")))
+
+ return "\n".join(result)
+
+
class CalendarHomeFolder(Folder):
"""
Calendar home folder.
@@ -332,7 +397,7 @@
properties = (yield self.home.properties())
result = []
- result.append("Calendar home for UID: %s" % (uid,))
+ result.append("Calendar home for UID: %s\n" % (uid,))
#
# Attributes
@@ -352,14 +417,14 @@
))
if len(rows):
- result.append("\nAttributes:")
+ result.append("Attributes:")
result.append(tableString(rows, header=("Name", "Value")))
#
# Properties
#
if properties:
- result.append("\Properties:")
+ result.append("Properties:")
result.append(tableString(
((name, properties[name]) for name in sorted(properties)),
header=("Name", "Value")
@@ -379,8 +444,8 @@
@inlineCallbacks
def _childWithObject(self, object):
- name = (yield object.uid())
- returnValue(CalendarObject(self.service, self.path + (name,), object))
+ uid = (yield object.uid())
+ returnValue(CalendarObject(self.service, self.path + (uid,), object, uid))
@inlineCallbacks
def child(self, name):
@@ -408,27 +473,39 @@
"""
Calendar object.
"""
- def __init__(self, service, path, calendarObject):
+ def __init__(self, service, path, calendarObject, uid):
File.__init__(self, service, path)
self.object = calendarObject
+ self.uid = uid
@inlineCallbacks
def lookup(self):
if not hasattr(self, "component"):
component = (yield self.object.component())
- mainComponent = component.mainComponent()
- self.componentType = mainComponent.name()
- self.uid = mainComponent.propertyValue("UID")
- self.summary = mainComponent.propertyValue("SUMMARY")
- self.mainComponent = mainComponent
- self.component = component
+ try:
+ mainComponent = component.mainComponent(allow_multiple=True)
+ assert self.uid == mainComponent.propertyValue("UID")
+
+ self.componentType = mainComponent.name()
+ self.summary = mainComponent.propertyValue("SUMMARY")
+ self.mainComponent = mainComponent
+
+ except InvalidICalendarDataError, e:
+ log.err("%s: %s" % (self.path, e))
+
+ self.componentType = "?"
+ self.summary = "** Invalid data **"
+ self.mainComponent = None
+
+ self.component = component
+
@inlineCallbacks
def list(self):
(yield self.lookup())
- returnValue(((CalendarObject, self.uid, self.componentType, self.summary),))
+ returnValue(((CalendarObject, self.uid, self.componentType, self.summary.replace("\n", " ")),))
@inlineCallbacks
def text(self):
@@ -464,7 +541,6 @@
# log.msg("%r" % (attachment,))
# # FIXME: Not getting any results here
-
returnValue("Calendar object:\n%s" % tableString(rows))
class AddressBookHomeFolder(Folder):
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/validcalendardata.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/validcalendardata.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/calendarserver/tools/validcalendardata.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -24,6 +24,7 @@
from twisted.application.service import Service
from twisted.python.text import wordWrap
from twisted.python.usage import Options
+from twistedcaldav.config import config
from twistedcaldav.ical import Component
from twistedcaldav.stdconfig import DEFAULT_CONFIG_FILE
import os
@@ -151,8 +152,11 @@
result = True
message = ""
+ truncated = False
try:
component = Component.fromString(self.input.read())
+ if config.MaxInstancesForRRULE != 0:
+ truncated = component.truncateRecurrence(config.MaxInstancesForRRULE)
component.validCalendarData(doFix=False, validateRecurrences=True)
component.validCalendarForCalDAV(methodAllowed=True)
component.validOrganizerForScheduling(doFix=False)
@@ -161,6 +165,8 @@
message = str(e)
if message.startswith(errorPrefix):
message = message[len(errorPrefix):]
+ if truncated:
+ message = "Calendar data RRULE truncated\n" + message
return (result, message,)
@@ -184,7 +190,6 @@
stderr.write("Unable to open input file for reading: %s\n" % (e))
sys.exit(1)
def makeService(store):
- from twistedcaldav.config import config
return ValidService(store, options, output, input, reactor, config)
utilityMain(options['config'], makeService, reactor)
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/migration/calendarmigrator.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/migration/calendarmigrator.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/migration/calendarmigrator.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -147,7 +147,7 @@
# Create log directory
try:
- logDir = os.path.join(options.targetDir, LOG_DIR)
+ logDir = os.path.join(options.targetRoot, LOG_DIR)
os.mkdir(logDir, 0755)
except OSError:
# Already exists
@@ -436,10 +436,6 @@
newDocumentRootValue = "Documents"
newDocumentRoot = os.path.join(newDataRoot, newDocumentRootValue)
- if not diskAccessor.exists(newServerRoot):
- log("Creating calendar server root: %s" % (newServerRoot,))
- diskAccessor.mkdir(newServerRoot)
-
if sourceVersion < "10.7":
# Before 10.7 there was no ServerRoot; DocumentRoot and DataRoot were separate.
# Reconfigure so DocumentRoot is under DataRoot is under ServerRoot. DataRoot
@@ -510,6 +506,7 @@
if oldServerRootValue:
if diskAccessor.exists(oldServerRootValue): # external volume
+ log("Using external calendar server root: %s" % (newServerRoot,))
# ServerRoot needs to be /Library/Server/Calendar and Contacts
# Since DocumentRoot is now relative to DataRoot, move DocumentRoot into DataRoot
newDataRoot = newDataRootValue = os.path.join(oldServerRootValue, "Data")
@@ -522,24 +519,52 @@
else:
diskAccessor.mkdir(newDocumentRoot)
elif diskAccessor.exists(absolutePathWithRoot(sourceRoot, oldServerRootValue)):
+ log("Copying calendar server root: %s" % (newServerRoot,))
diskAccessor.ditto(
absolutePathWithRoot(sourceRoot, oldServerRootValue),
newServerRoot
)
+ newDataRoot = os.path.join(newServerRoot, "Data")
+ if not diskAccessor.exists(newDataRoot):
+ diskAccessor.mkdir(newDataRoot)
+ newDocumentRoot = os.path.join(newDataRoot, "Documents")
+ if diskAccessor.exists(os.path.join(newServerRoot, "Documents")):
+ log("Moving Documents into Data root: %s" % (newDataRoot,))
+ diskAccessor.rename(os.path.join(newServerRoot, "Documents"),
+ newDocumentRoot)
+ else:
+ diskAccessor.mkdir(newDocumentRoot)
+ else:
+ log("Creating new calendar server root: %s" % (newServerRoot,))
+ diskAccessor.mkdir(newServerRoot)
+ newDataRoot = os.path.join(newServerRoot, "Data")
+ diskAccessor.mkdir(newDataRoot)
+ newDocumentRoot = os.path.join(newDataRoot, "Documents")
+ diskAccessor.mkdir(newDocumentRoot)
+
else: # 10.8 -> 10.8
if oldServerRootValue:
if diskAccessor.exists(oldServerRootValue): # external volume
- pass
+ log("Using external calendar server root: %s" % (oldServerRootValue,))
elif diskAccessor.exists(absolutePathWithRoot(sourceRoot, oldServerRootValue)):
+ log("Copying calendar server root: %s" % (newServerRoot,))
diskAccessor.ditto(
absolutePathWithRoot(sourceRoot, oldServerRootValue),
newServerRoot
)
+ else:
+ log("Creating new calendar server root: %s" % (newServerRoot,))
+ diskAccessor.mkdir(newServerRoot)
+ newDataRoot = os.path.join(newServerRoot, "Data")
+ diskAccessor.mkdir(newDataRoot)
+ newDocumentRoot = os.path.join(newDataRoot, "Documents")
+ diskAccessor.mkdir(newDocumentRoot)
- if diskAccessor.exists(newServerRoot):
- diskAccessor.chown(newServerRoot, uid, gid, recursive=True)
+ if not diskAccessor.exists(newServerRoot):
+ diskAccessor.mkdir(newServerRoot)
+ diskAccessor.chown(newServerRoot, uid, gid, recursive=True)
newServerRootValue, newDataRootValue = relativize(newServerRootValue,
newDataRootValue)
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/migration/test/test_migrator.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/migration/test/test_migrator.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/migration/test/test_migrator.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -937,7 +937,6 @@
"Data"
),
[ # expected DiskAccessor history
- ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('ditto', '/Library/Server/Previous/Library/CalendarServer/Data', '/Volumes/new/Library/Server/Calendar and Contacts/Data'),
('ditto', '/Library/Server/Previous/Library/CalendarServer/Documents', '/Volumes/new/Library/Server/Calendar and Contacts/Data/Documents'),
('ditto', '/Library/Server/Previous/Library/AddressBookServer/Documents/addressbooks', '/Volumes/new/Library/Server/Calendar and Contacts/Data/Documents/addressbooks'),
@@ -1011,7 +1010,6 @@
"/Volumes/External/CalendarServer/Calendar and Contacts Data",
),
[ # expected DiskAccessor history
- ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('rename',
'/Volumes/External/CalendarServer/Calendar and Contacts Data',
'/Volumes/External/CalendarServer/Calendar and Contacts Data.bak'),
@@ -1019,6 +1017,7 @@
('rename', '/Volumes/External/CalendarServer/Documents', '/Volumes/External/CalendarServer/Calendar and Contacts Data/Documents'),
('chown-recursive', '/Volumes/External/CalendarServer/Calendar and Contacts Data', FakeUser.pw_uid, FakeGroup.gr_gid),
('ditto', '/Volumes/External/AddressBookServer/Documents/addressbooks', '/Volumes/External/CalendarServer/Calendar and Contacts Data/Documents/addressbooks'),
+ ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts', FakeUser.pw_uid, FakeGroup.gr_gid),
]
),
@@ -1088,7 +1087,6 @@
"Data"
),
[
- ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('ditto', '/Library/Server/Previous/NonStandard/CalendarServer/Data', '/Volumes/new/Library/Server/Calendar and Contacts/Data'),
('ditto', '/Library/Server/Previous/NonStandard/CalendarServer/Documents', '/Volumes/new/Library/Server/Calendar and Contacts/Data/Documents'),
('ditto', '/Library/Server/Previous/NonStandard/AddressBookServer/Documents/addressbooks', '/Volumes/new/Library/Server/Calendar and Contacts/Data/Documents/addressbooks'),
@@ -1161,13 +1159,13 @@
"/Volumes/External/CalendarServer/Calendar and Contacts Data",
),
[
- ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('ditto',
'/Library/Server/Previous/Library/CalendarServer/Data',
'/Volumes/External/CalendarServer/Calendar and Contacts Data'),
('rename', '/Volumes/External/CalendarServer/Documents', '/Volumes/External/CalendarServer/Calendar and Contacts Data/Documents'),
('chown-recursive', '/Volumes/External/CalendarServer/Calendar and Contacts Data', FakeUser.pw_uid, FakeGroup.gr_gid),
('ditto', '/Library/Server/Previous/Library/AddressBookServer/Documents/addressbooks', '/Volumes/External/CalendarServer/Calendar and Contacts Data/Documents/addressbooks'),
+ ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts', FakeUser.pw_uid, FakeGroup.gr_gid),
]
),
@@ -1211,6 +1209,8 @@
"/Library/Server/Previous/Library/Server/Calendar and Contacts/Documents/" : True,
"/Library/Server/Previous/Library/Server/Calendar and Contacts/Data/" : True,
"/Volumes/new/Library/Server/Calendar and Contacts/" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts/Data" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts/Documents" : True,
},
( # args
"/Library/Server/Previous", # sourceRoot
@@ -1229,6 +1229,7 @@
),
[
('ditto', '/Library/Server/Previous/Library/Server/Calendar and Contacts', '/Volumes/new/Library/Server/Calendar and Contacts'),
+ ('rename', '/Volumes/new/Library/Server/Calendar and Contacts/Documents', '/Volumes/new/Library/Server/Calendar and Contacts/Data/Documents'),
('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts', FakeUser.pw_uid, FakeGroup.gr_gid),
]
),
@@ -1288,10 +1289,10 @@
"/Volumes/External/Library/Server/Calendar and Contacts/Data",
),
[
- ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('rename',
'/Volumes/External/Library/Server/Calendar and Contacts/Documents',
'/Volumes/External/Library/Server/Calendar and Contacts/Data/Documents'),
+ ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts', FakeUser.pw_uid, FakeGroup.gr_gid),
]
),
@@ -1350,7 +1351,6 @@
"Data"
),
[
- ('mkdir', '/Volumes/new/Library/Server/Calendar and Contacts'),
('ditto', '/Library/Server/Previous/Library/Server/Calendar and Contacts', '/Volumes/new/Library/Server/Calendar and Contacts'),
('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts', FakeUser.pw_uid, FakeGroup.gr_gid),
]
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/tools/protocolanalysis.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/tools/protocolanalysis.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/tools/protocolanalysis.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -287,7 +287,7 @@
self.currentLine = None
self.linesRead = 0
- def analyzeLogFile(self, logFilePath, ctr):
+ def analyzeLogFile(self, logFilePath, lineCtr):
fpath = os.path.expanduser(logFilePath)
if fpath.endswith(".gz"):
f = GzipFile(fpath)
@@ -297,14 +297,18 @@
self.maxIndex = (self.endHour - self.startHour + 1) * 60 / self.resolutionMinutes
try:
for line in f:
- ctr += 1
- if ctr <= self.linesRead:
+ lineCtr += 1
+ if lineCtr <= self.linesRead:
continue
self.linesRead += 1
if line.startswith("Log"):
continue
- self.parseLine(line)
+ try:
+ self.parseLine(line)
+ except:
+ print "Could not parse line:\n%s" % (line,)
+ continue
# Filter method
if self.ignoreNonHTTPMethods and not self.currentLine.method.startswith("REPORT(") and self.currentLine.method not in httpMethods:
@@ -461,7 +465,7 @@
self.userInteractionAnalysis(adjustedMethod)
except Exception:
- print line
+ print "Failed to process line:\n%s" % (line,)
raise
# Average various items
@@ -505,7 +509,7 @@
for client, data in self.clientByMethodCount.iteritems():
self.clientIDByMethodCount[self.clientIDMap[client]] = data
- return ctr
+ return lineCtr
def parseLine(self, line):
@@ -1863,7 +1867,7 @@
pwd = os.getcwd()
analyzers = []
- ctr = 0
+ ctr = []
for arg in args:
arg = os.path.expanduser(arg)
if not arg.startswith("/"):
@@ -1876,8 +1880,9 @@
if diffMode or not analyzers:
analyzers.append(CalendarServerLogAnalyzer(startHour, endHour, utcoffset, resolution, filterByUser, filterByClient))
+ ctr.append(0)
print "Analyzing: %s" % (arg,)
- ctr = analyzers[-1].analyzeLogFile(arg, ctr)
+ ctr[-1] = analyzers[-1].analyzeLogFile(arg, ctr[-1])
if diffMode and len(analyzers) > 1:
Differ(analyzers).printAll(doTabDelimited)
@@ -1890,9 +1895,9 @@
if again.lower()[0] == "n":
break
print "\n\n\n"
- analyzers[0].analyzeLogFile(arg)
+ analyzers[0].analyzeLogFile(arg, ctr[0])
analyzers[0].printAll(doTabDelimited)
except Exception, e:
+ print traceback.print_exc()
sys.exit(str(e))
- print traceback.print_exc()
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/tools/request_monitor.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/tools/request_monitor.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/contrib/tools/request_monitor.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1,6 +1,6 @@
#!/usr/bin/env python
##
-# Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+# Copyright (c) 2009-2012 Apple 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.
@@ -24,18 +24,48 @@
import time
import traceback
-NETSTAT = "/usr/sbin/netstat"
-enableListenQueue = os.path.exists(NETSTAT)
-IOSTAT = "/usr/sbin/iostat"
-enableCpuIdle = os.path.exists(IOSTAT)
-VMSTAT = "/usr/bin/vm_stat"
-enableFreeMem = os.path.exists(VMSTAT)
+# Detect which OS this is being run on
+child = Popen(
+ args=[
+ "uname",
+ ],
+ stdout=PIPE, stderr=STDOUT,
+)
+output, _ignore_error = child.communicate()
+output = output.strip()
+if output == "Darwin":
+ OS = "OS X"
+elif output == "Linux":
+ OS = "Linux"
+else:
+ print "Unknown OS: %s" % (output,)
+ sys.exit(1)
+# Some system commands we need to detect
+if OS == "OS X":
+ NETSTAT = "/usr/sbin/netstat"
+ enableListenQueue = os.path.exists(NETSTAT)
+elif OS == "Linux":
+ enableListenQueue = False
+if OS == "OS X":
+ IOSTAT = "/usr/sbin/iostat"
+ enableCpuIdle = os.path.exists(IOSTAT)
+elif OS == "Linux":
+ IOSTAT = "/usr/bin/iostat"
+ enableCpuIdle = os.path.exists(IOSTAT)
+
+if OS == "OS X":
+ VMSTAT = "/usr/bin/vm_stat"
+ enableFreeMem = os.path.exists(VMSTAT)
+elif OS == "Linux":
+ VMSTAT = "/usr/bin/vmstat"
+ enableFreeMem = os.path.exists(VMSTAT)
+
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
-filename = "/var/log/caldavd/access.log"
+filenames = ["/var/log/caldavd/access.log",]
debug = False
def listenq():
@@ -75,28 +105,32 @@
-def tail(filename, n):
- child = Popen(
- args=[
- "/usr/bin/tail", "-%d" % (n,), filename,
- ],
- stdout=PIPE, stderr=STDOUT,
- )
- output, _ignore_error = child.communicate()
- return output.split("\n")
+def tail(filenames, n):
+ results = []
+ for filename in filenames:
+ child = Popen(
+ args=[
+ "/usr/bin/tail", "-%d" % (n,), filename,
+ ],
+ stdout=PIPE, stderr=STDOUT,
+ )
+ output, _ignore_error = child.communicate()
+ results.extend(output.splitlines())
+ return results
-def range(filename, start, end):
+def range(filenames, start, end):
results = []
- with open(filename) as f:
- for count, line in enumerate(f):
- if count >= start:
- results.append(line)
- if count > end:
- break
+ for filename in filenames:
+ with open(filename) as f:
+ for count, line in enumerate(f):
+ if count >= start:
+ results.append(line)
+ if count > end:
+ break
return results
def cpuPerDaemon():
- a = []
+ a = {}
child = Popen(
args=[
"ps", "auxw",
@@ -107,37 +141,68 @@
for l in output.split("\n"):
if "ProcessType=" in l:
f = l.split()
- a.append(f[2])
- return ", ".join(a)
+ for l in f:
+ if l.startswith("LogID="):
+ logID = int(l[6:])
+ break
+ else:
+ logID = None
+ if logID is not None:
+ a[logID] = f[2]
+ return ", ".join([v for _ignore_k, v in sorted(a.items(), key=lambda i:i[0])])
def cpuidle():
- child = Popen(
- args=[
- IOSTAT, "-c", "2", "-n", "0",
- ],
- stdout=PIPE, stderr=STDOUT,
- )
- output, _ignore_ = child.communicate()
- return output.split("\n")[-2].split()[2]
-
-def freemem():
- try:
+ if OS == "OS X":
child = Popen(
args=[
- VMSTAT,
+ IOSTAT, "-c", "2", "-n", "0",
],
stdout=PIPE, stderr=STDOUT,
)
output, _ignore_ = child.communicate()
- lines = output.split("\n")
-
- line = lines[0]
- pageSize = int(line[line.find("page size of")+12:].split()[0])
- line = lines[1]
- freeSize = int(line[line.find("Pages free:")+11:].split()[0][:-1])
- freed = freeSize * pageSize
- return "%d bytes (%.1f GB)" % (freed, freed / (1024.0 * 1024 * 1024),)
+ return output.splitlines[-2].split()[2]
+ elif OS == "Linux":
+ child = Popen(
+ args=[
+ IOSTAT, "-c", "1", "2"
+ ],
+ stdout=PIPE, stderr=STDOUT,
+ )
+ output, _ignore_ = child.communicate()
+ return output.splitlines()[-2].split()[5]
+
+def freemem():
+ try:
+ if OS == "OS X":
+ child = Popen(
+ args=[
+ VMSTAT,
+ ],
+ stdout=PIPE, stderr=STDOUT,
+ )
+ output, _ignore_ = child.communicate()
+ lines = output.split("\n")
+
+ line = lines[0]
+ pageSize = int(line[line.find("page size of")+12:].split()[0])
+ line = lines[1]
+ freeSize = int(line[line.find("Pages free:")+11:].split()[0][:-1])
+ freed = freeSize * pageSize
+ return "%d bytes (%.1f GB)" % (freed, freed / (1024.0 * 1024 * 1024),)
+ elif OS == "Linux":
+ child = Popen(
+ args=[
+ VMSTAT, "-s", "-S", "K"
+ ],
+ stdout=PIPE, stderr=STDOUT,
+ )
+ output, _ignore_ = child.communicate()
+ lines = output.splitlines()
+
+ line = lines[4]
+ freed = int(line.split()[0]) * 1024
+ return "%d bytes (%.1f GB)" % (freed, freed / (1024.0 * 1024 * 1024),)
except Exception, e:
if debug:
print "freemem failure", e
@@ -251,22 +316,24 @@
numTop = int(value)
if len(args):
- filename = os.path.expanduser(args[0])
+ filenames = [os.path.expanduser(arg) for arg in args]
-if not os.path.isfile(filename):
- print "Path %s does not exist" % (filename,)
- print
- usage()
- sys.exit(1)
+for filename in filenames:
+ if not os.path.isfile(filename):
+ print "Path %s does not exist" % (filename,)
+ print
+ usage()
+ sys.exit(1)
-if not os.access(filename, os.R_OK):
- print "Path %s does not exist" % (filename,)
- print
- usage()
- sys.exit(1)
+for filename in filenames:
+ if not os.access(filename, os.R_OK):
+ print "Path %s does not exist" % (filename,)
+ print
+ usage()
+ sys.exit(1)
if debug:
- print "Starting: access log file: %s" % (filename,)
+ print "Starting: access log files: %s" % (", ".join(filenames),)
print
while True:
@@ -297,7 +364,7 @@
parseErrors = 0
try:
- lines = tail(filename, numLines) if lineRange is None else range(filename, *lineRange)
+ lines = tail(filenames, numLines) if lineRange is None else range(filenames, *lineRange)
for line in lines:
if not line or line.startswith("Log"):
continue
Property changes on: CalendarServer/branches/users/gaya/ldapdirectorybacker/support/build.sh
___________________________________________________________________
Deleted: svn:mergeinfo
- /CalendarServer/branches/config-separation/support/build.sh:4379-4443
/CalendarServer/branches/egg-info-351/support/build.sh:4589-4615
/CalendarServer/branches/generic-sqlstore/support/build.sh:6167-6191
/CalendarServer/branches/new-store/support/build.sh:5594-5934
/CalendarServer/branches/new-store-no-caldavfile/support/build.sh:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2/support/build.sh:5936-5981
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/support/build.sh:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/support/build.sh:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/support/build.sh:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/support/build.sh:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/support/build.sh:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/support/build.sh:4465-4957
/CalendarServer/branches/users/cdaboo/pods/support/build.sh:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/support/build.sh:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/support/build.sh:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/support/build.sh:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/support/build.sh:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/support/build.sh:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/support/build.sh:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging/support/build.sh:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid/support/build.sh:8772-8805
/CalendarServer/branches/users/glyph/conn-limit/support/build.sh:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/support/build.sh:4971-5080
/CalendarServer/branches/users/glyph/dalify/support/build.sh:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect/support/build.sh:6824-6876
/CalendarServer/branches/users/glyph/deploybuild/support/build.sh:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/support/build.sh:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/support/build.sh:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge/support/build.sh:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes/support/build.sh:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/support/build.sh:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7/support/build.sh:6369-6445
/CalendarServer/branches/users/glyph/new-export/support/build.sh:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/support/build.sh:7340-7351
/CalendarServer/branches/users/glyph/parallel-upgrade/support/build.sh:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1/support/build.sh:8571-8583
/CalendarServer/branches/users/glyph/sendfdport/support/build.sh:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes/support/build.sh:8436-8443
/CalendarServer/branches/users/glyph/sharedpool/support/build.sh:6490-6550
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones/support/build.sh:8524-8535
/CalendarServer/branches/users/glyph/sql-store/support/build.sh:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/support/build.sh:7248-7258
/CalendarServer/branches/users/glyph/table-alias/support/build.sh:8651-8664
/CalendarServer/branches/users/glyph/use-system-twisted/support/build.sh:5084-5149
/CalendarServer/branches/users/sagen/applepush/support/build.sh:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/support/build.sh:7380-7381
/CalendarServer/branches/users/sagen/locations-resources/support/build.sh:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2/support/build.sh:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events/support/build.sh:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/support/build.sh:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/support/build.sh:4068-4075
/CalendarServer/branches/users/sagen/resources-2/support/build.sh:5084-5093
/CalendarServer/branches/users/wsanchez/transations/support/build.sh:5515-5593
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/idirectory.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/idirectory.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/idirectory.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -110,7 +110,7 @@
fullName = Attribute("The full name of this record.")
firstName = Attribute("The first name of this record.")
lastName = Attribute("The last name of this record.")
- emailAddress = Attribute("The email address of this record.")
+ emailAddresses = Attribute("The email addresses of this record.")
enabledForCalendaring = Attribute("Determines whether this record creates a principal with a calendar home.")
enabledForAddressBooks = Attribute("Determines whether this record creates a principal with an address book home.")
calendarUserAddresses = Attribute(
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectory.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectory.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectory.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -86,6 +86,9 @@
"negativeCaching": False,
"warningThresholdSeconds": 3,
"batchSize": 500, # for splitting up large queries
+ "requestTimeoutSeconds" : 10,
+ "requestResultsLimit" : 200,
+ "optimizeMultiName" : False,
"queryLocationsImplicitly": True,
"restrictEnabledRecords": False,
"restrictToGroup": "",
@@ -195,6 +198,11 @@
self.warningThresholdSeconds = params["warningThresholdSeconds"]
self.batchSize = params["batchSize"]
+ self.requestTimeoutSeconds = params["requestTimeoutSeconds"]
+ self.requestResultsLimit = params["requestResultsLimit"]
+ self.optimizeMultiName = params["optimizeMultiName"]
+ if self.batchSize > self.requestResultsLimit:
+ self.batchSize = self.requestResultsLimit
self.queryLocationsImplicitly = params["queryLocationsImplicitly"]
self.augmentService = params["augmentService"]
self.groupMembershipCache = params["groupMembershipCache"]
@@ -261,25 +269,10 @@
self.rdnSchema[recordType]["rdn"].lower()
) + self.base
- # Create LDAP connection
- self.log_info("Connecting to LDAP %s" % (repr(self.uri),))
- self.ldap = self.createLDAPConnection()
- if self.credentials.get("dn", ""):
- try:
- self.log_info("Binding to LDAP %s" %
- (repr(self.credentials.get("dn")),))
- self.ldap.simple_bind_s(self.credentials.get("dn"),
- self.credentials.get("password"))
- except ldap.SERVER_DOWN:
- msg = "Can't connect to LDAP %s: server down" % (self.uri,)
- self.log_error(msg)
- raise DirectoryConfigurationError(msg)
- except ldap.INVALID_CREDENTIALS:
- msg = "Can't bind to LDAP %s: check credentials" % (self.uri,)
- self.log_error(msg)
- raise DirectoryConfigurationError(msg)
+ self.ldap = None
+
# Separate LDAP connection used solely for authenticating clients
self.authLDAP = None
@@ -390,12 +383,30 @@
return assignments
+ def getLDAPConnection(self):
+ if self.ldap is None:
+ self.log_info("Connecting to LDAP %s" % (repr(self.uri),))
+ self.ldap = self.createLDAPConnection()
+ self.log_info("Connection established to LDAP %s" % (repr(self.uri),))
+ if self.credentials.get("dn", ""):
+ try:
+ self.log_info("Binding to LDAP %s" %
+ (repr(self.credentials.get("dn")),))
+ self.ldap.simple_bind_s(self.credentials.get("dn"),
+ self.credentials.get("password"))
+ self.log_info("Successfully authenticated with LDAP as %s" %
+ (repr(self.credentials.get("dn")),))
+ except ldap.INVALID_CREDENTIALS:
+ msg = "Can't bind to LDAP %s: check credentials" % (self.uri,)
+ self.log_error(msg)
+ raise DirectoryConfigurationError(msg)
+ return self.ldap
def createLDAPConnection(self):
"""
Create and configure LDAP connection
"""
- cxn = ldap.ldapobject.ReconnectLDAPObject(self.uri)
+ cxn = ldap.initialize(self.uri)
if self.tlsCACertFile:
cxn.set_option(ldap.OPT_X_TLS_CACERTFILE, self.tlsCACertFile)
@@ -468,44 +479,53 @@
def timedSearch(self, base, scope, filterstr="(objectClass=*)",
- attrlist=None, timeout=-1, sizelimit=0):
+ attrlist=None, timeoutSeconds=-1, resultLimit=0):
"""
- Execute an ldap.search_s( ); if it takes longer than the configured
+ Execute an LDAP query, retrying up to 3 times in case the LDAP server has
+ gone down and we need to reconnect. If it takes longer than the configured
threshold, emit a log error.
+ The number of records requested is controlled by resultLimit (0=no limit).
+ If timeoutSeconds is not -1, the query will abort after the specified number
+ of seconds and the results retrieved so far are returned.
"""
- s = ldap.async.List( self.ldap )
- s.startSearch( base, scope, filterStr=filterstr, attrList=attrlist, timeout=timeout, sizelimit=sizelimit, )
-
- startTime = time.time()
- try:
- s.processResults()
+ TRIES = 3
- except ldap.SERVER_DOWN:
- self.log_error("LDAP server unavailable")
- raise HTTPError(StatusResponse(responsecode.SERVICE_UNAVAILABLE, "LDAP server unavailable"))
- except ldap.NO_SUCH_OBJECT:
- pass
- except ldap.FILTER_ERROR, e:
- self.log_error("LDAP filter error: %s %s" % (e, filterstr))
- except ldap.SIZELIMIT_EXCEEDED, e:
- self.log_error("LDAP size limited exceeded: %s sizelimit %s (#results=%d)" % (e, sizelimit, len(s.allResults), ))
- except ldap.TIMELIMIT_EXCEEDED, e:
- self.log_error("LDAP timeout %s timeout %s (#results=%d)" % (e, timeout, len(s.allResults), ))
- except ldap.TIMEOUT, e:
- self.log_error("LDAP timeout %s (#results=%d)" % (e, len(s.allResults), ))
-
- # change format, ignoring resultsType
- result = [resultItem for resultType, resultItem in s.allResults]
+ for i in xrange(TRIES):
+ try:
+ s = ldap.async.List(self.getLDAPConnection())
+ s.startSearch(base, scope, filterstr, attrList=attrlist,
+ timeout=timeoutSeconds,
+ sizelimit=resultLimit)
+ startTime = time.time()
+ s.processResults()
+ except ldap.NO_SUCH_OBJECT:
+ return []
+ except ldap.FILTER_ERROR, e:
+ self.log_error("LDAP filter error: %s %s" % (e, filterstr))
+ return []
+ except ldap.SIZELIMIT_EXCEEDED, e:
+ self.log_debug("LDAP result limit exceeded: %d" % (resultLimit,))
+ except ldap.TIMELIMIT_EXCEEDED, e:
+ self.log_warn("LDAP timeout exceeded: %d seconds" % (timeoutSeconds,))
+ except ldap.SERVER_DOWN:
+ self.ldap = None
+ self.log_error("LDAP server unavailable (tried %d times)" % (i+1,))
+ continue
- totalTime = time.time() - startTime
- if totalTime > self.warningThresholdSeconds:
- if filterstr and len(filterstr) > 100:
- filterstr = "%s..." % (filterstr[:100],)
- self.log_error("LDAP query exceeded threshold: %.2f seconds for %s %s %s (#results=%d)" %
- (totalTime, base, filterstr, attrlist, len(result)))
- return result
+ # change format, ignoring resultsType
+ result = [resultItem for resultType, resultItem in s.allResults]
+ totalTime = time.time() - startTime
+ if totalTime > self.warningThresholdSeconds:
+ if filterstr and len(filterstr) > 100:
+ filterstr = "%s..." % (filterstr[:100],)
+ self.log_error("LDAP query exceeded threshold: %.2f seconds for %s %s %s (#results=%d)" %
+ (totalTime, base, filterstr, attrlist, len(result)))
+ return result
+ raise HTTPError(StatusResponse(responsecode.SERVICE_UNAVAILABLE, "LDAP server unavailable"))
+
+
@property
def restrictedGUIDs(self):
"""
@@ -951,15 +971,19 @@
else:
scope = ldap.SCOPE_SUBTREE
- filterstr = buildFilter(self.rdnSchema[recordType]["mapping"],
- fields, operand=operand)
+ filterstr = buildFilter(recordType,
+ self.rdnSchema[recordType]["mapping"],
+ fields, operand=operand,
+ optimizeMultiName=self.optimizeMultiName)
if filterstr is not None:
# Query the LDAP server
self.log_debug("LDAP search %s %s %s" %
(ldap.dn.dn2str(base), scope, filterstr))
- results = self.timedSearch(ldap.dn.dn2str(base), scope, filterstr=filterstr,
- attrlist=self.attrlist)
+ results = self.timedSearch(ldap.dn.dn2str(base), scope,
+ filterstr=filterstr, attrlist=self.attrlist,
+ timeoutSeconds=self.requestTimeoutSeconds,
+ resultLimit=self.requestResultsLimit)
self.log_debug("LDAP search returned %d results" % (len(results),))
numMissingGuids = 0
numMissingRecordNames = 0
@@ -1105,7 +1129,17 @@
return ' '.join(ldap.dn.dn2str(ldap.dn.str2dn(dnStr.lower())).split())
-def buildFilter(mapping, fields, operand="or"):
+def _convertValue(value, matchType):
+ if matchType == "starts-with":
+ value = "%s*" % (ldapEsc(value),)
+ elif matchType == "contains":
+ value = "*%s*" % (ldapEsc(value),)
+ # otherwise it's an exact match
+ else:
+ value = ldapEsc(value)
+ return value
+
+def buildFilter(recordType, mapping, fields, operand="or", optimizeMultiName=False):
"""
Create an LDAP filter string from a list of tuples representing directory
attributes to search
@@ -1117,31 +1151,57 @@
"""
converted = []
+ combined = {}
for field, value, caseless, matchType in fields:
ldapField = mapping.get(field, None)
if ldapField:
- if matchType == "starts-with":
- value = "%s*" % (ldapEsc(value),)
- elif matchType == "contains":
- value = "*%s*" % (ldapEsc(value),)
- # otherwise it's an exact match
- else:
- value = ldapEsc(value)
+ combined.setdefault(field, []).append((value, caseless, matchType))
+ value = _convertValue(value, matchType)
converted.append("(%s=%s)" % (ldapField, value))
if len(converted) == 0:
- filterstr = None
- elif len(converted) == 1:
+ return None
+
+ if optimizeMultiName and recordType in ("users", "groups"):
+ for field in [key for key in combined.keys() if key != "guid"]:
+ if len(combined.get(field, [])) > 1:
+ # Client is searching on more than one name -- interpret this as the user
+ # explicitly looking up a user by name (ignoring other record types), and
+ # try the various firstName/lastName permutations:
+ if recordType == "users":
+ converted = []
+ for firstName, firstCaseless, firstMatchType in combined["firstName"]:
+ for lastName, lastCaseless, lastMatchType in combined["lastName"]:
+ if firstName != lastName:
+ firstValue = _convertValue(firstName, firstMatchType)
+ lastValue = _convertValue(lastName, lastMatchType)
+ converted.append("(&(%s=%s)(%s=%s))" %
+ (mapping["firstName"], firstValue,
+ mapping["lastName"], lastValue)
+ )
+ else:
+ return None
+
+ if len(converted) == 1:
filterstr = converted[0]
else:
operand = ("|" if operand == "or" else "&")
filterstr = "(%s%s)" % (operand, "".join(converted))
+ if filterstr:
+ # To reduce the amount of records returned, filter out the ones
+ # that don't have (possibly) required attribute values (record
+ # name, guid)
+ additional = []
+ for key in ("recordName", "guid"):
+ if mapping.has_key(key):
+ additional.append("(%s=*)" % (mapping.get(key),))
+ if additional:
+ filterstr = "(&%s%s)" % ("".join(additional), filterstr)
+
return filterstr
-
-
class LdapDirectoryRecord(CachingDirectoryRecord):
"""
LDAP implementation of L{IDirectoryRecord}.
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectorybacker.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectorybacker.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectorybacker.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -256,9 +256,9 @@
# can't resist also using a timeout, 1 sec per requested record for now
timeout = maxRecords
- self.log_debug("vCardRecordsForAddressBookQuery:LDAP query base=%s and filter=%s and attributes=%s timeout=%s sizelimit=%s" % (ldap.dn.dn2str(base), filterstr, attributes, timeout, maxRecords))
+ self.log_debug("vCardRecordsForAddressBookQuery:LDAP query base=%s and filter=%s and attributes=%s timeout=%s resultLimit=%s" % (ldap.dn.dn2str(base), filterstr, attributes, timeout, maxRecords))
- ldapSearchResult = (yield self.timedSearch(ldap.dn.dn2str(base), ldap.SCOPE_SUBTREE, filterstr=filterstr, attrlist=attributes, timeout=timeout, sizelimit=maxRecords))
+ ldapSearchResult = (yield self.timedSearch(ldap.dn.dn2str(base), ldap.SCOPE_SUBTREE, filterstr=filterstr, attrlist=attributes, timeoutSeconds=timeout, resultLimit=maxRecords))
self.log_debug("vCardRecordsForAddressBookQuery: ldapSearchResult=%s" % (ldapSearchResult,))
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/test/test_ldapdirectory.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/test/test_ldapdirectory.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/test/test_ldapdirectory.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -37,10 +37,12 @@
def test_buildFilter(self):
mapping = {
+ "recordName" : "uid",
"fullName" : "cn",
"emailAddresses" : "mail",
"firstName" : "givenName",
"lastName" : "sn",
+ "guid" : "generateduid",
}
entries = [
@@ -52,8 +54,9 @@
("lastName", "mor", True, u"starts-with")
],
"operand" : "or",
- "recordType" : None,
- "expected" : "(|(cn=mor*)(mail=mor*)(givenName=mor*)(sn=mor*))"
+ "recordType" : "users",
+ "expected" : "(&(uid=*)(generateduid=*)(|(cn=mor*)(mail=mor*)(givenName=mor*)(sn=mor*)))",
+ "optimize" : False,
},
{
"fields" : [
@@ -63,16 +66,18 @@
("lastName", "mor\\", True, u"starts-with")
],
"operand" : "or",
- "recordType" : None,
- "expected" : "(|(cn=mor\\28*)(mail=*mor\\29*)(givenName=mor\\2a)(sn=mor\\5c*))"
+ "recordType" : "users",
+ "expected" : "(&(uid=*)(generateduid=*)(|(cn=mor\\28*)(mail=*mor\\29*)(givenName=mor\\2a)(sn=mor\\5c*)))",
+ "optimize" : False,
},
{
"fields" : [
("fullName", "mor", True, u"starts-with"),
],
"operand" : "or",
- "recordType" : None,
- "expected" : "(cn=mor*)"
+ "recordType" : "users",
+ "expected" : "(&(uid=*)(generateduid=*)(cn=mor*))",
+ "optimize" : False,
},
{
"fields" : [
@@ -81,8 +86,9 @@
("invalid", "mor", True, u"starts-with"),
],
"operand" : "and",
- "recordType" : None,
- "expected" : "(&(cn=*mor*)(mail=mor))"
+ "recordType" : "users",
+ "expected" : "(&(uid=*)(generateduid=*)(&(cn=*mor*)(mail=mor)))",
+ "optimize" : False,
},
{
"fields" : [
@@ -90,32 +96,135 @@
("invalid", "mor", True, u"starts-with"),
],
"operand" : "and",
- "recordType" : None,
- "expected" : None
+ "recordType" : "users",
+ "expected" : None,
+ "optimize" : False,
},
{
"fields" : [ ],
"operand" : "and",
- "recordType" : None,
- "expected" : None
+ "recordType" : "users",
+ "expected" : None,
+ "optimize" : False,
},
+ {
+ "fields" : [
+ ("fullName", "mor", True, u"starts-with"),
+ ("fullName", "sag", True, u"starts-with"),
+ ("emailAddresses", "mor", True, u"starts-with"),
+ ("emailAddresses", "sag", True, u"starts-with"),
+ ("firstName", "mor", True, u"starts-with"),
+ ("firstName", "sag", True, u"starts-with"),
+ ("lastName", "mor", True, u"starts-with"),
+ ("lastName", "sag", True, u"starts-with"),
+ ],
+ "operand" : "or",
+ "recordType" : "users",
+ "expected" : "(&(uid=*)(generateduid=*)(|(&(givenName=mor*)(sn=sag*))(&(givenName=sag*)(sn=mor*))))",
+ "optimize" : True,
+ },
+ {
+ "fields" : [
+ ("fullName", "mor", True, u"starts-with"),
+ ("fullName", "sag", True, u"starts-with"),
+ ("emailAddresses", "mor", True, u"starts-with"),
+ ("emailAddresses", "sag", True, u"starts-with"),
+ ("firstName", "mor", True, u"starts-with"),
+ ("firstName", "sag", True, u"starts-with"),
+ ("lastName", "mor", True, u"starts-with"),
+ ("lastName", "sag", True, u"starts-with"),
+ ],
+ "operand" : "or",
+ "recordType" : "groups",
+ "expected" : None,
+ "optimize" : True,
+ },
+ {
+ "fields" : [
+ ("fullName", "mor", True, u"starts-with"),
+ ("fullName", "sag", True, u"starts-with"),
+ ("emailAddresses", "mor", True, u"starts-with"),
+ ("emailAddresses", "sag", True, u"starts-with"),
+ ("firstName", "mor", True, u"starts-with"),
+ ("firstName", "sag", True, u"starts-with"),
+ ("lastName", "mor", True, u"starts-with"),
+ ("lastName", "sag", True, u"starts-with"),
+ ],
+ "operand" : "or",
+ "recordType" : "groups",
+ "expected" : None,
+ "optimize" : "(&(uid=*)(generateduid=*)(|(cn=mor*)(cn=sag*)(mail=mor*)(mail=sag*)(givenName=mor*)(givenName=sag*)(sn=mor*)(sn=sag*)))",
+ },
+ {
+ "fields" : [
+ ("guid", "xyzzy", True, u"equals"),
+ ("guid", "plugh", True, u"equals"),
+ ],
+ "operand" : "or",
+ "recordType" : "groups",
+ "expected" : "(&(uid=*)(generateduid=*)(|(generateduid=xyzzy)(generateduid=plugh)))",
+ "optimize" : True,
+ },
+ {
+ "fields" : [
+ ("fullName", "mor", True, u"contains"),
+ ("fullName", "sag", True, u"contains"),
+ ],
+ "operand" : "or",
+ "recordType" : "locations",
+ "expected" : "(&(uid=*)(generateduid=*)(|(cn=*mor*)(cn=*sag*)))",
+ "optimize" : True,
+ },
+ {
+ "fields" : [
+ ("fullName", "mor", True, u"contains"),
+ ("fullName", "sag", True, u"contains"),
+ ],
+ "operand" : "or",
+ "recordType" : "resources",
+ "expected" : "(&(uid=*)(generateduid=*)(|(cn=*mor*)(cn=*sag*)))",
+ "optimize" : True,
+ },
]
for entry in entries:
self.assertEquals(
- buildFilter(mapping, entry["fields"],
- operand=entry["operand"]),
+ buildFilter(entry["recordType"], mapping, entry["fields"],
+ operand=entry["operand"], optimizeMultiName=entry["optimize"]),
entry["expected"]
)
+ class StubList(object):
+ def __init__(self, wrapper):
+ self.ldap = wrapper
+ def startSearch(self, base, scope, filterstr, attrList=None,
+ timeout=-1, sizelimit=0):
+ self.base = base
+ self.scope = scope
+ self.filterstr = filterstr
+ self.attrList = attrList
+ self.timeout = timeout
+ self.sizelimit = sizelimit
+
+ def processResults(self):
+ self.allResults = self.ldap.search_s(self.base, self.scope,
+ self.filterstr, attrlist=self.attrList)
+
+ class StubAsync(object):
+ def List(self, wrapper):
+ return StubList(wrapper)
+
+
class LdapDirectoryTestWrapper(object):
"""
A test stub which replaces search_s( ) with a version that will return
whatever you have previously called addTestResults( ) with.
"""
+
def __init__(self, actual):
self.actual = actual
+ self.async = StubAsync()
# Test data returned from search_s.
# Note that some DNs have various extra whitespace added and mixed
@@ -242,10 +351,10 @@
for dn, attrs in self.records:
dn = normalizeDNstr(dn)
if dn == base:
- results.append((dn, attrs))
+ results.append(("ignored", (dn, attrs)))
elif dnContainedIn(ldap.dn.str2dn(dn), ldap.dn.str2dn(base)):
if filterstr in ("(objectClass=*)", "(!(objectClass=organizationalUnit))"):
- results.append((dn, attrs))
+ results.append(("ignored", (dn, attrs)))
else:
trans = maketrans("&(|)", " |")
fragments = filterstr.encode("utf-8").translate(trans).split("|")
@@ -255,7 +364,7 @@
fragment = fragment.strip()
key, value = fragment.split("=")
if value in attrs.get(key, []):
- results.append((dn, attrs))
+ results.append(("ignored", (dn, attrs)))
return results
@@ -369,6 +478,7 @@
self.service = LdapDirectoryService(params)
self.service.ldap = LdapDirectoryTestWrapper(self.service.ldap)
+ self.patch(ldap, "async", StubAsync())
def test_ldapWrapper(self):
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directorybackedaddressbook.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directorybackedaddressbook.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directorybackedaddressbook.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2008-2012 Apple 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.
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/caldav.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/caldav.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/caldav.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2011 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple 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.
@@ -45,7 +45,9 @@
from twistedcaldav.scheduling.processing import ImplicitProcessor, ImplicitProcessorException
"""
-Class that handles delivery of scheduling messages via CalDAV.
+Handles the sending of scheduling messages to the server itself. This will cause
+actual processing of the delivery of the message to the recipient's inbox, via the
+L{ImplicitProcessor} class.
"""
__all__ = [
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/imip.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/imip.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/imip.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple 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.
@@ -31,7 +31,7 @@
from twistedcaldav.scheduling.itip import iTIPRequestStatus
"""
-Class that handles delivery of scheduling messages via iMIP.
+Handles the sending of scheduling messages via iMIP (mail gateway).
"""
__all__ = [
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/implicit.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/implicit.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -88,6 +88,9 @@
self.calendar = (yield resource.iCalendarForUser(request))
yield self.checkImplicitState()
+ # Once we have collected sufficient information from the calendar data, check validity of organizer and attendees
+ self.checkValidOrganizer()
+
# Attendees are not allowed to overwrite one type with another
if (
not self.internal_request and
@@ -187,6 +190,22 @@
returnValue((self.action != "none", False,))
+ def checkValidOrganizer(self):
+ """
+ Make sure the ORGANIZER is allowed to do certain scheduling operations.
+ """
+
+ # Check to see whether the organizer principal is enabled for scheduling. If not, do not allow them
+ # to create new scheduling resources.
+ if self.action == "create":
+ if self.organizerPrincipal and not self.organizerPrincipal.enabledAsOrganizer():
+ log.err("ORGANIZER not allowed to be an Organizer: %s" % (self.organizer,))
+ raise HTTPError(ErrorResponse(
+ responsecode.FORBIDDEN,
+ (caldav_namespace, "organizer-allowed"),
+ "Organizer cannot schedule",
+ ))
+
@inlineCallbacks
def checkSchedulingObjectResource(self, resource):
@@ -835,17 +854,17 @@
itipmsg = iTipGenerator.generateCancel(self.oldcalendar, (attendee,), rids)
# Send scheduling message
+ if itipmsg:
+ # This is a local CALDAV scheduling operation.
+ scheduler = self.makeScheduler()
+
+ # Do the PUT processing
+ log.info("Implicit CANCEL - organizer: '%s' to attendee: '%s', UID: '%s', RIDs: '%s'" % (self.organizer, attendee, self.uid, rids))
+ response = (yield scheduler.doSchedulingViaPUT(self.originator, (attendee,), itipmsg, self.internal_request))
+ self.handleSchedulingResponse(response, True)
+
+ count += 1
- # This is a local CALDAV scheduling operation.
- scheduler = self.makeScheduler()
-
- # Do the PUT processing
- log.info("Implicit CANCEL - organizer: '%s' to attendee: '%s', UID: '%s', RIDs: '%s'" % (self.organizer, attendee, self.uid, rids))
- response = (yield scheduler.doSchedulingViaPUT(self.originator, (attendee,), itipmsg, self.internal_request))
- self.handleSchedulingResponse(response, True)
-
- count += 1
-
returnValue(count)
@inlineCallbacks
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/ischedule.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/ischedule.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/ischedule.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple 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.
@@ -48,7 +48,8 @@
import OpenSSL
"""
-Server to server utility functions and client requests.
+Handles the sending of iSchedule scheduling messages. Used for both cross-domain scheduling,
+as well as internal partitioning or podding.
"""
__all__ = [
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/itip.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/itip.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/itip.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -15,20 +15,17 @@
##
"""
-iTIP (RFC5546) processing.
+iTIP (RFC5546) scheduling message processing and generation.
+
+
+This is currently used for handling auto-replies to schedule requests arriving
+in an inbox. It is called in a delayed fashion via reactor.callLater.
+
+We assume that all the components/calendars we deal with have been determined
+as being 'valid for CalDAV/iTIP', i.e. they contain UIDs, single component
+types, etc.
"""
-#
-# This is currently used for handling auto-replies to schedule requests arriving
-# in an inbox. It is called in a delayed fashion via reactor.callLater.
-#
-# We assume that all the components/calendars we deal with have been determined
-# as being 'valid for CalDAV/iTIP', i.e. they contain UIDs, single component
-# types, etc.
-#
-# The logic for component matching needs a lot more work as it currently does not
-# know how to deal with overridden instances.
-#
from twext.python.log import Logger
@@ -616,6 +613,7 @@
instances = (None,)
tzids = set()
+ added = False
for instance_rid in instances:
# Create a new component matching the type of the original
@@ -624,11 +622,16 @@
# Use the master component when the instance is None
if not instance_rid:
instance = original.masterComponent()
+ assert instance is not None, "Need a master component"
else:
instance = original.overriddenComponent(instance_rid)
if instance is None:
instance = original.deriveInstance(instance_rid)
- assert instance is not None, "Need a master component"
+
+ # If the instance to be cancelled did not exist in the original, then
+ # do nothing
+ if instance is None:
+ continue
# Add some required properties extracted from the original
comp.addProperty(Property("DTSTAMP", instance.propertyValue("DTSTAMP")))
@@ -665,19 +668,23 @@
tzids.update(comp.timezoneIDs())
itip.addComponent(comp)
-
- # Now include any referenced tzids
- for comp in original.subcomponents():
- if comp.name() == "VTIMEZONE":
- tzid = comp.propertyValue("TZID")
- if tzid in tzids:
- itip.addComponent(comp)
+ added = True
+
+ if added:
+ # Now include any referenced tzids
+ for comp in original.subcomponents():
+ if comp.name() == "VTIMEZONE":
+ tzid = comp.propertyValue("TZID")
+ if tzid in tzids:
+ itip.addComponent(comp)
+
+ # Strip out unwanted bits
+ iTipGenerator.prepareSchedulingMessage(itip)
+
+ return itip
+ else:
+ return None
- # Strip out unwanted bits
- iTipGenerator.prepareSchedulingMessage(itip)
-
- return itip
-
@staticmethod
def generateAttendeeRequest(original, attendees, filter_rids):
"""
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/processing.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/processing.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -40,6 +40,16 @@
from pycalendar.datetime import PyCalendarDateTime
from pycalendar.timezone import PyCalendarTimezone
+"""
+CalDAV implicit processing.
+
+This module handles the processing of scheduling messages being delivered to a calendar user's inbox.
+It determines who is scheduling (organizer or attendee) and applies the scheduling message changes
+to the recipient's calendar data as well as depositing the scheduling message in the inbox. For users
+who have an auto-accept option on, it will also handle the automatic response. Also, refreshes of other
+attendees (when one attendee replies) are triggered from here.
+"""
+
__all__ = [
"ImplicitProcessor",
"ImplicitProcessorException",
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/scheduler.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/scheduler.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/scheduler.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -55,6 +55,62 @@
"""
CalDAV/Server-to-Server scheduling behavior.
+
+This module handles the delivery of scheduling messages to organizer and attendees. The basic idea is to first
+confirm the integrity of the incoming scheduling message, check authorization. Appropriate L{DeliveryService}s
+are then used to deliver the message to attendees or organizer. Delivery responses are processed and returned.
+This takes into account partitioning and podding of users by detecting the appropriate host for a calendar
+user and then dispatching the delivery accordingly.
+
+The L{Scheduler} class defines the basic behavior for processing deliveries. Sub-classes are defined for the
+different ways a deliver can be triggered.
+
+L{CalDAVScheduler} - handles deliveries for scheduling messages originating from inside the CalDAV server
+i.e. user PUTs or POSTs.
+
+L{IScheduleScheduler} - handles deliveries for scheduling messages being POSTed to the iSchedule inbox.
+
+L{IMIPScheduler} - handles deliveries for POSTs on the iMIP inbox (coming from the mail gateway).
+
+L{DirectScheduler} - used when doing some internal processing (e.g., inbox item processing during an
+upgrade.
+
+Here is a typical flow of activity for a iTIP between users on the server:
+
+iTIP PUT request
+\
+ \_L{ImplicitScheduler} - does CalDAV-schedule logic and sends iTIP message
+ \
+ \_L{CalDAVScheduler} - receives iTIP message
+ \
+ \_L{ScheduleViaCalDAV} - handles delivery of iTIP message
+ \
+ \_L{ImplicitProcessor} - dispatches iTIP message (also auto-accept)
+ \
+ \_L{iTipProcessing} - processes iTIP message
+
+Here is a typical flow of activity for a iTIP between an organizer on the server and an iMIP attendee:
+
+iTIP PUT request
+\
+ \_L{ImplicitScheduler}
+ \
+ \_L{CalDAVScheduler}
+ \
+ \_L{ScheduleViaIMip}
+
+Here is a typical flow of activity for a iTIP between an organizer not on the server and attendee on the server:
+
+iTIP POST on /ischedule
+\
+ \_L{IScheduleScheduler}
+ \
+ \_L{ScheduleViaCalDAV}
+ \
+ \_L{ImplicitProcessor}
+ \
+ \_L{iTipProcessing}
+
"""
__all__ = [
@@ -671,7 +727,11 @@
if organizerPrincipal:
outboxURL = organizerPrincipal.scheduleOutboxURL()
if outboxURL:
- if not organizerPrincipal.enabledAsOrganizer():
+
+ # Only do this check for a freebusy request. A check for an invite needs
+ # to be handled later when we know whether a new invite is being added
+ # (which we reject) vs an update to an existing one (which we allow).
+ if self.checkForFreeBusy() and not organizerPrincipal.enabledAsOrganizer():
log.err("ORGANIZER not allowed to be an Organizer: %s" % (self.calendar,))
raise HTTPError(ErrorResponse(
responsecode.FORBIDDEN,
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/test/test_itip.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/test/test_itip.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/scheduling/test/test_itip.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -1894,12 +1894,33 @@
("mailto:user2 at example.com",),
(None, ),
),
+
+ # Recurring component - cancel non-existent instance
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-4
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=10
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+""",
+ "",
+ ("mailto:user2 at example.com",),
+ (PyCalendarDateTime(2008, 12, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), ),
+ ),
+
)
for original, filtered, attendees, instances in data:
component = Component.fromString(original)
itipped = iTipGenerator.generateCancel(component, attendees, instances)
- itipped = str(itipped).replace("\r", "")
+ itipped = str(itipped).replace("\r", "") if itipped else ""
itipped = "".join([line for line in itipped.splitlines(True) if not line.startswith("DTSTAMP:")])
self.assertEqual(filtered, itipped)
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/stdconfig.py 2012-03-14 19:44:23 UTC (rev 8867)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/stdconfig.py 2012-03-14 20:49:10 UTC (rev 8868)
@@ -65,6 +65,9 @@
"negativeCaching": False,
"warningThresholdSeconds": 3,
"batchSize": 500, # for splitting up large queries
+ "requestTimeoutSeconds" : 10,
+ "requestResultsLimit" : 200,
+ "optimizeMultiName" : False,
"queryLocationsImplicitly": True,
"restrictEnabledRecords": False,
"restrictToGroup": "",
Property changes on: CalendarServer/branches/users/gaya/ldapdirectorybacker/txdav/caldav/datastore/index_file.py
___________________________________________________________________
Deleted: svn:mergeinfo
- /CalendarServer/branches/config-separation/txdav/caldav/datastore/index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/caldav/datastore/index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/caldav/datastore/index_file.py:6167-6191
/CalendarServer/branches/new-store/txdav/caldav/datastore/index_file.py:5594-5934
/CalendarServer/branches/new-store-no-caldavfile/txdav/caldav/datastore/index_file.py:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/caldav/datastore/index_file.py:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/caldav/datastore/index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/caldav/datastore/index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/index_file.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/caldav/datastore/index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/txdav/caldav/datastore/index_file.py:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/caldav/datastore/index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/caldav/datastore/index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/caldav/datastore/index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/caldav/datastore/index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/caldav/datastore/index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/caldav/datastore/index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/caldav/datastore/index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/caldav/datastore/index_file.py:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging/txdav/caldav/datastore/index_file.py:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid/txdav/caldav/datastore/index_file.py:8772-8805
/CalendarServer/branches/users/glyph/conn-limit/txdav/caldav/datastore/index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/caldav/datastore/index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/caldav/datastore/index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/caldav/datastore/index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/caldav/datastore/index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/caldav/datastore/index_file.py:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge/txdav/caldav/datastore/index_file.py:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/caldav/datastore/index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/caldav/datastore/index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/caldav/datastore/index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle/txdav/caldav/datastore/index_file.py:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/caldav/datastore/index_file.py:7340-7351
/CalendarServer/branches/users/glyph/parallel-upgrade/txdav/caldav/datastore/index_file.py:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1/txdav/caldav/datastore/index_file.py:8571-8583
/CalendarServer/branches/users/glyph/sendfdport/txdav/caldav/datastore/index_file.py:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes/txdav/caldav/datastore/index_file.py:8436-8443
/CalendarServer/branches/users/glyph/sharedpool/txdav/caldav/datastore/index_file.py:6490-6550
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones/txdav/caldav/datastore/index_file.py:8524-8535
/CalendarServer/branches/users/glyph/sql-store/txdav/caldav/datastore/index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/caldav/datastore/index_file.py:7248-7258
/CalendarServer/branches/users/glyph/table-alias/txdav/caldav/datastore/index_file.py:8651-8664
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/caldav/datastore/index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/caldav/datastore/index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/caldav/datastore/index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources/txdav/caldav/datastore/index_file.py:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/caldav/datastore/index_file.py:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events/txdav/caldav/datastore/index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/caldav/datastore/index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/caldav/datastore/index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/caldav/datastore/index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/caldav/datastore/index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/index.py:6322-6394
Property changes on: CalendarServer/branches/users/gaya/ldapdirectorybacker/txdav/caldav/datastore/test/test_index_file.py
___________________________________________________________________
Deleted: svn:mergeinfo
- /CalendarServer/branches/config-separation/txdav/caldav/datastore/test/test_index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/caldav/datastore/test/test_index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/caldav/datastore/test/test_index_file.py:6167-6191
/CalendarServer/branches/new-store/txdav/caldav/datastore/test/test_index_file.py:5594-5934
/CalendarServer/branches/new-store-no-caldavfile/txdav/caldav/datastore/test/test_index_file.py:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/caldav/datastore/test/test_index_file.py:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/caldav/datastore/test/test_index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/caldav/datastore/test/test_index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/test_index_file.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/caldav/datastore/test/test_index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/caldav/datastore/test/test_index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/caldav/datastore/test/test_index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/caldav/datastore/test/test_index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/test/test_index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/caldav/datastore/test/test_index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/caldav/datastore/test/test_index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/caldav/datastore/test/test_index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/caldav/datastore/test/test_index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/caldav/datastore/test/test_index_file.py:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging/txdav/caldav/datastore/test/test_index_file.py:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid/txdav/caldav/datastore/test/test_index_file.py:8772-8805
/CalendarServer/branches/users/glyph/conn-limit/txdav/caldav/datastore/test/test_index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/caldav/datastore/test/test_index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/caldav/datastore/test/test_index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/caldav/datastore/test/test_index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/caldav/datastore/test/test_index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/caldav/datastore/test/test_index_file.py:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge/txdav/caldav/datastore/test/test_index_file.py:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/caldav/datastore/test/test_index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/caldav/datastore/test/test_index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/test/test_index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/caldav/datastore/test/test_index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle/txdav/caldav/datastore/test/test_index_file.py:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/caldav/datastore/test/test_index_file.py:7340-7351
/CalendarServer/branches/users/glyph/parallel-upgrade/txdav/caldav/datastore/test/test_index_file.py:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1/txdav/caldav/datastore/test/test_index_file.py:8571-8583
/CalendarServer/branches/users/glyph/sendfdport/txdav/caldav/datastore/test/test_index_file.py:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes/txdav/caldav/datastore/test/test_index_file.py:8436-8443
/CalendarServer/branches/users/glyph/sharedpool/txdav/caldav/datastore/test/test_index_file.py:6490-6550
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones/txdav/caldav/datastore/test/test_index_file.py:8524-8535
/CalendarServer/branches/users/glyph/sql-store/txdav/caldav/datastore/test/test_index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/caldav/datastore/test/test_index_file.py:7248-7258
/CalendarServer/branches/users/glyph/table-alias/txdav/caldav/datastore/test/test_index_file.py:8651-8664
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/caldav/datastore/test/test_index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/caldav/datastore/test/test_index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/caldav/datastore/test/test_index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources/txdav/caldav/datastore/test/test_index_file.py:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/caldav/datastore/test/test_index_file.py:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events/txdav/caldav/datastore/test/test_index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/caldav/datastore/test/test_index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/caldav/datastore/test/test_index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/caldav/datastore/test/test_index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/caldav/datastore/test/test_index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/test/test_index.py:6322-6394
Property changes on: CalendarServer/branches/users/gaya/ldapdirectorybacker/txdav/carddav/datastore/index_file.py
___________________________________________________________________
Deleted: svn:mergeinfo
- /CalendarServer/branches/config-separation/txdav/carddav/datastore/index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/carddav/datastore/index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/carddav/datastore/index_file.py:6167-6191
/CalendarServer/branches/new-store/txdav/carddav/datastore/index_file.py:5594-5934
/CalendarServer/branches/new-store-no-caldavfile/txdav/carddav/datastore/index_file.py:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/carddav/datastore/index_file.py:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/carddav/datastore/index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/carddav/datastore/index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/carddav/datastore/index_file.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/carddav/datastore/index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/txdav/carddav/datastore/index_file.py:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/carddav/datastore/index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/carddav/datastore/index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/carddav/datastore/index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/carddav/datastore/index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/carddav/datastore/index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/carddav/datastore/index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/carddav/datastore/index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/carddav/datastore/index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/carddav/datastore/index_file.py:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging/txdav/carddav/datastore/index_file.py:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid/txdav/carddav/datastore/index_file.py:8772-8805
/CalendarServer/branches/users/glyph/conn-limit/txdav/carddav/datastore/index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/carddav/datastore/index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/carddav/datastore/index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/carddav/datastore/index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/carddav/datastore/index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/carddav/datastore/index_file.py:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge/txdav/carddav/datastore/index_file.py:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/carddav/datastore/index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/carddav/datastore/index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/carddav/datastore/index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle/txdav/carddav/datastore/index_file.py:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/carddav/datastore/index_file.py:7340-7351
/CalendarServer/branches/users/glyph/parallel-upgrade/txdav/carddav/datastore/index_file.py:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1/txdav/carddav/datastore/index_file.py:8571-8583
/CalendarServer/branches/users/glyph/sendfdport/txdav/carddav/datastore/index_file.py:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes/txdav/carddav/datastore/index_file.py:8436-8443
/CalendarServer/branches/users/glyph/sharedpool/txdav/carddav/datastore/index_file.py:6490-6550
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones/txdav/carddav/datastore/index_file.py:8524-8535
/CalendarServer/branches/users/glyph/sql-store/txdav/carddav/datastore/index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/carddav/datastore/index_file.py:7248-7258
/CalendarServer/branches/users/glyph/table-alias/txdav/carddav/datastore/index_file.py:8651-8664
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/carddav/datastore/index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/carddav/datastore/index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/carddav/datastore/index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources/txdav/carddav/datastore/index_file.py:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/carddav/datastore/index_file.py:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events/txdav/carddav/datastore/index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/carddav/datastore/index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/carddav/datastore/index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/carddav/datastore/index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/carddav/datastore/index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/vcardindex.py:6322-6394
Property changes on: CalendarServer/branches/users/gaya/ldapdirectorybacker/txdav/carddav/datastore/test/test_index_file.py
___________________________________________________________________
Deleted: svn:mergeinfo
- /CalendarServer/branches/config-separation/txdav/carddav/datastore/test/test_index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/carddav/datastore/test/test_index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/carddav/datastore/test/test_index_file.py:6167-6191
/CalendarServer/branches/new-store/txdav/carddav/datastore/test/test_index_file.py:5594-5934
/CalendarServer/branches/new-store-no-caldavfile/txdav/carddav/datastore/test/test_index_file.py:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/carddav/datastore/test/test_index_file.py:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/carddav/datastore/test/test_index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/carddav/datastore/test/test_index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/carddav/datastore/test/test_index_file.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/carddav/datastore/test/test_index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/carddav/datastore/test/test_index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/carddav/datastore/test/test_index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/carddav/datastore/test/test_index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/carddav/datastore/test/test_index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/carddav/datastore/test/test_index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/carddav/datastore/test/test_index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/carddav/datastore/test/test_index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/carddav/datastore/test/test_index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/carddav/datastore/test/test_index_file.py:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging/txdav/carddav/datastore/test/test_index_file.py:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid/txdav/carddav/datastore/test/test_index_file.py:8772-8805
/CalendarServer/branches/users/glyph/conn-limit/txdav/carddav/datastore/test/test_index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/carddav/datastore/test/test_index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/carddav/datastore/test/test_index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/carddav/datastore/test/test_index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/carddav/datastore/test/test_index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/carddav/datastore/test/test_index_file.py:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge/txdav/carddav/datastore/test/test_index_file.py:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/carddav/datastore/test/test_index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/carddav/datastore/test/test_index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/test/test_index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/carddav/datastore/test/test_index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle/txdav/carddav/datastore/test/test_index_file.py:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/carddav/datastore/test/test_index_file.py:7340-7351
/CalendarServer/branches/users/glyph/parallel-upgrade/txdav/carddav/datastore/test/test_index_file.py:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1/txdav/carddav/datastore/test/test_index_file.py:8571-8583
/CalendarServer/branches/users/glyph/sendfdport/txdav/carddav/datastore/test/test_index_file.py:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes/txdav/carddav/datastore/test/test_index_file.py:8436-8443
/CalendarServer/branches/users/glyph/sharedpool/txdav/carddav/datastore/test/test_index_file.py:6490-6550
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones/txdav/carddav/datastore/test/test_index_file.py:8524-8535
/CalendarServer/branches/users/glyph/sql-store/txdav/carddav/datastore/test/test_index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/carddav/datastore/test/test_index_file.py:7248-7258
/CalendarServer/branches/users/glyph/table-alias/txdav/carddav/datastore/test/test_index_file.py:8651-8664
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/carddav/datastore/test/test_index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/carddav/datastore/test/test_index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/carddav/datastore/test/test_index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources/txdav/carddav/datastore/test/test_index_file.py:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/carddav/datastore/test/test_index_file.py:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events/txdav/carddav/datastore/test/test_index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/carddav/datastore/test/test_index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/carddav/datastore/test/test_index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/carddav/datastore/test/test_index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/carddav/datastore/test/test_index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/test/test_vcardindex.py:6322-6394
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120314/1e176170/attachment-0001.html>
More information about the calendarserver-changes
mailing list