[CalendarServer-changes] [1593] CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py

source_changes at macosforge.org source_changes at macosforge.org
Wed Jun 6 19:10:52 PDT 2007


Revision: 1593
          http://trac.macosforge.org/projects/calendarserver/changeset/1593
Author:   wsanchez at apple.com
Date:     2007-06-06 19:10:52 -0700 (Wed, 06 Jun 2007)

Log Message:
-----------
If record lookup results in a cache miss, try to look up the missing
record rather than failing the lookup.

This solves the problem where new users are added in OD but aren't
seen on the server until the record cache expires.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py

Modified: CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py	2007-06-06 22:17:51 UTC (rev 1592)
+++ CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py	2007-06-07 02:10:52 UTC (rev 1593)
@@ -213,7 +213,8 @@
 
         else:
             raise OpenDirectoryInitError(
-                "Open Directory (node=%s) no /Computers records with an enabled and valid calendar service were found matching virtual hostname: %s"
+                "Open Directory (node=%s) no /Computers records with an enabled and valid "
+                "calendar service were found matching virtual hostname: %s"
                 % (self.realmName, vhostname,)
             )
 
@@ -343,132 +344,171 @@
         type.  Keys are short names and values are the cooresponding
         OpenDirectoryRecord for the given record type.
         """
-        def reloadCache():
-            log.msg("Reloading %s record cache" % (recordType,))
+        try:
+            storage = self._records[recordType]
+        except KeyError:
+            self.reloadCache(recordType)
+        else:
+            if storage["status"] == "stale":
+                storage["status"] = "loading"
 
-            attrs = [
-                dsattributes.kDS1AttrGeneratedUID,
-                dsattributes.kDS1AttrDistinguishedName,
-                dsattributes.kDSNAttrEMailAddress,
-                dsattributes.kDSNAttrServicesLocator,
-            ]
+                def onError(f):
+                    storage["status"] = "stale" # Keep trying
+                    log.err("Unable to load records of type %s from OpenDirectory due to unexpected error: %s"
+                            % (recordType, f))
 
-            query = None
-            if recordType == DirectoryService.recordType_users:
-                listRecordType = dsattributes.kDSStdRecordTypeUsers
+                d = deferToThread(self.reloadCache, recordType)
+                d.addErrback(onError)
 
-            elif recordType == DirectoryService.recordType_groups:
-                listRecordType = dsattributes.kDSStdRecordTypeGroups
-                attrs.append(dsattributes.kDSNAttrGroupMembers)
+        return self._records[recordType]["records"]
 
-            elif recordType == DirectoryService.recordType_locations:
-                listRecordType = dsattributes.kDSStdRecordTypeResources
-                query = dsquery.match(dsattributes.kDSNAttrResourceType, "1", dsattributes.eDSExact)
+    def listRecords(self, recordType):
+        return self.recordsForType(recordType).itervalues()
+
+    def recordWithShortName(self, recordType, shortName):
+        try:
+            return self.recordsForType(recordType)[shortName]
+        except KeyError:
+            # Cache miss; try looking the record up, in case it is new
+            # FIXME: This is a blocking call (hopefully it's a fast one)
+            self.reloadCache(recordType, shortName)
+            return self.recordsForType(recordType)[shortName]
+
+    def reloadCache(self, recordType, shortName=None):
+        log.msg("Reloading %s record cache" % (recordType,))
+
+        attrs = [
+            dsattributes.kDS1AttrGeneratedUID,
+            dsattributes.kDS1AttrDistinguishedName,
+            dsattributes.kDSNAttrEMailAddress,
+            dsattributes.kDSNAttrServicesLocator,
+        ]
+
+        query = None
+        if recordType == DirectoryService.recordType_users:
+            listRecordType = dsattributes.kDSStdRecordTypeUsers
+
+        elif recordType == DirectoryService.recordType_groups:
+            listRecordType = dsattributes.kDSStdRecordTypeGroups
+            attrs.append(dsattributes.kDSNAttrGroupMembers)
+
+        elif recordType == DirectoryService.recordType_locations:
+            listRecordType = dsattributes.kDSStdRecordTypeResources
+            query = dsquery.match(dsattributes.kDSNAttrResourceType, "1", dsattributes.eDSExact)
+        
+        elif recordType == DirectoryService.recordType_resources:
+            listRecordType = dsattributes.kDSStdRecordTypeResources
+            query = dsquery.expression(dsquery.expression.OR, (
+                dsquery.match(dsattributes.kDSNAttrResourceType, "0", dsattributes.eDSExact),
+                dsquery.match(dsattributes.kDSNAttrResourceType, "2", dsattributes.eDSExact),
+                dsquery.match(dsattributes.kDSNAttrResourceType, "3", dsattributes.eDSExact),
+                dsquery.match(dsattributes.kDSNAttrResourceType, "4", dsattributes.eDSExact),
+                dsquery.match(dsattributes.kDSNAttrResourceType, "5", dsattributes.eDSExact),
+            ))
+        
+        else:
+            raise UnknownRecordTypeError("Unknown Open Directory record type: %s"
+                                         % (recordType,))
+
+        if self.requireComputerRecord:
+            cprecord = dsquery.match(dsattributes.kDSNAttrServicesLocator, self.servicetag, dsattributes.eDSStartsWith)
+            if query:
+                query = dsquery.expression(dsquery.expression.AND, (cprecord, query))
+            else:
+                query = cprecord
             
-            elif recordType == DirectoryService.recordType_resources:
-                listRecordType = dsattributes.kDSStdRecordTypeResources
-                query = dsquery.expression(dsquery.expression.OR, (
-                    dsquery.match(dsattributes.kDSNAttrResourceType, "0", dsattributes.eDSExact),
-                    dsquery.match(dsattributes.kDSNAttrResourceType, "2", dsattributes.eDSExact),
-                    dsquery.match(dsattributes.kDSNAttrResourceType, "3", dsattributes.eDSExact),
-                    dsquery.match(dsattributes.kDSNAttrResourceType, "4", dsattributes.eDSExact),
-                    dsquery.match(dsattributes.kDSNAttrResourceType, "5", dsattributes.eDSExact),
-                ))
-            
-            else:
-                raise UnknownRecordTypeError("Unknown Open Directory record type: %s"
-                                             % (recordType,))
+        if shortName is not None:
+            query = dsquery.expression(dsquery.expression.AND,
+                (dsquery.match(dsattributes.kDSNAttrResourceType, shortName, dsattributes.eDSExact), query)
+            )
 
-            if self.requireComputerRecord:
-                cprecord = dsquery.match(dsattributes.kDSNAttrServicesLocator, self.servicetag, dsattributes.eDSStartsWith)
-                if query:
-                    query = dsquery.expression(dsquery.expression.AND, (cprecord, query))
-                else:
-                    query = cprecord
-                
-            records = {}
+        records = {}
 
-            try:
-                if query:
-                    if isinstance(query, dsquery.match):
-                        results = opendirectory.queryRecordsWithAttribute(
-                            self.directory,
-                            query.attribute,
-                            query.value,
-                            query.matchType,
-                            False,
-                            listRecordType,
-                            attrs,
-                        )
-                    else:
-                        results = opendirectory.queryRecordsWithAttributes(
-                            self.directory,
-                            query.generate(),
-                            False,
-                            listRecordType,
-                            attrs,
-                        )
+        try:
+            if query:
+                if isinstance(query, dsquery.match):
+                    results = opendirectory.queryRecordsWithAttribute(
+                        self.directory,
+                        query.attribute,
+                        query.value,
+                        query.matchType,
+                        False,
+                        listRecordType,
+                        attrs,
+                    )
                 else:
-                    results = opendirectory.listAllRecordsWithAttributes(
+                    results = opendirectory.queryRecordsWithAttributes(
                         self.directory,
+                        query.generate(),
+                        False,
                         listRecordType,
                         attrs,
                     )
-            except opendirectory.ODError, ex:
-                log.msg("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
-                raise
+            else:
+                results = opendirectory.listAllRecordsWithAttributes(
+                    self.directory,
+                    listRecordType,
+                    attrs,
+                )
+        except opendirectory.ODError, ex:
+            log.msg("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
+            raise
 
-            for (key, value) in results.iteritems():
-                if self.requireComputerRecord:
-                    # Make sure this record has service enabled.
-                    enabled = True
+        for (key, value) in results.iteritems():
+            if self.requireComputerRecord:
+                # Make sure this record has service enabled.
+                enabled = True
 
-                    services = value.get(dsattributes.kDSNAttrServicesLocator)
-                    if isinstance(services, str):
-                        services = [services]
+                services = value.get(dsattributes.kDSNAttrServicesLocator)
+                if isinstance(services, str):
+                    services = [services]
 
-                    for service in services:
-                        if service.startswith(self.servicetag):
-                            if service.endswith(":disabled"):
-                                enabled = False
-                            break
+                for service in services:
+                    if service.startswith(self.servicetag):
+                        if service.endswith(":disabled"):
+                            enabled = False
+                        break
 
-                    if not enabled:
-                        log.err("Record is not enabled")
-                        continue
-
-                # Now get useful record info.
-                shortName = key
-                guid = value.get(dsattributes.kDS1AttrGeneratedUID)
-                if not guid:
+                if not enabled:
+                    log.err("Record is not enabled")
                     continue
-                realName = value.get(dsattributes.kDS1AttrDistinguishedName)
 
-                # Get calendar user addresses from directory record.
-                cuaddrset = self._getCalendarUserAddresses(recordType, key, value)
+            # Now get useful record info.
+            recordShortName = key
+            guid = value.get(dsattributes.kDS1AttrGeneratedUID)
+            if not guid:
+                continue
+            realName = value.get(dsattributes.kDS1AttrDistinguishedName)
 
-                # Special case for groups.
-                if recordType == DirectoryService.recordType_groups:
-                    memberGUIDs = value.get(dsattributes.kDSNAttrGroupMembers)
-                    if memberGUIDs is None:
-                        memberGUIDs = ()
-                    elif type(memberGUIDs) is str:
-                        memberGUIDs = (memberGUIDs,)
-                else:
+            # Get calendar user addresses from directory record.
+            cuaddrset = self._getCalendarUserAddresses(recordType, key, value)
+
+            # Special case for groups.
+            if recordType == DirectoryService.recordType_groups:
+                memberGUIDs = value.get(dsattributes.kDSNAttrGroupMembers)
+                if memberGUIDs is None:
                     memberGUIDs = ()
+                elif type(memberGUIDs) is str:
+                    memberGUIDs = (memberGUIDs,)
+            else:
+                memberGUIDs = ()
 
-                records[shortName] = OpenDirectoryRecord(
-                    service               = self,
-                    recordType            = recordType,
-                    guid                  = guid,
-                    shortName             = shortName,
-                    fullName              = realName,
-                    calendarUserAddresses = cuaddrset,
-                    memberGUIDs           = memberGUIDs,
-                )
+            records[recordShortName] = OpenDirectoryRecord(
+                service               = self,
+                recordType            = recordType,
+                guid                  = guid,
+                shortName             = recordShortName,
+                fullName              = realName,
+                calendarUserAddresses = cuaddrset,
+                memberGUIDs           = memberGUIDs,
+            )
 
-                #log.debug("Populated record: %s" % (records[shortName],))
+            #log.debug("Populated record: %s" % (records[recordShortName],))
 
+        if shortName is None:
+            #
+            # Replace the entire cache
+            #
             storage = {
                 "status": "new",
                 "records": records,
@@ -486,31 +526,16 @@
             self._delayedCalls.add(callLater(recordListCacheTimeout, rot))
 
             self._records[recordType] = storage
-
-        try:
-            storage = self._records[recordType]
-        except KeyError:
-            reloadCache()
         else:
-            if storage["status"] == "stale":
-                storage["status"] = "loading"
+            #
+            # Update one record, if found
+            #
+            if records:
+                assert len(records) == 1, "shortName = %r, records = %r" % (shortName, len(records))
+                self._records[recordType]["records"][shortName] = records[shortName]
+            else:
+                self._records[recordType]["records"][shortName] = None
 
-                def onError(f):
-                    storage["status"] = "stale" # Keep trying
-                    log.err("Unable to load records of type %s from OpenDirectory due to unexpected error: %s"
-                            % (recordType, f))
-
-                d = deferToThread(reloadCache)
-                d.addErrback(onError)
-
-        return self._records[recordType]["records"]
-
-    def listRecords(self, recordType):
-        return self.recordsForType(recordType).itervalues()
-
-    def recordWithShortName(self, recordType, shortName):
-        return self.recordsForType(recordType).get(shortName, None)
-
 class OpenDirectoryRecord(DirectoryRecord):
     """
     Open Directory implementation of L{IDirectoryRecord}.

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


More information about the calendarserver-changes mailing list