[CalendarServer-changes] [5817] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Jun 30 14:13:47 PDT 2010


Revision: 5817
          http://trac.macosforge.org/projects/calendarserver/changeset/5817
Author:   sagen at apple.com
Date:     2010-06-30 14:13:44 -0700 (Wed, 30 Jun 2010)
Log Message:
-----------
Adds a utility for migrating resources and locations from OpenDirectory into calendar server's internal directory service.

Modified Paths:
--------------
    CalendarServer/trunk/support/Makefile.Apple

Added Paths:
-----------
    CalendarServer/trunk/bin/calendarserver_migrate_resources
    CalendarServer/trunk/calendarserver/tools/resources.py
    CalendarServer/trunk/calendarserver/tools/test/test_resources.py
    CalendarServer/trunk/doc/calendarserver_migrate_resources.8

Added: CalendarServer/trunk/bin/calendarserver_migrate_resources
===================================================================
--- CalendarServer/trunk/bin/calendarserver_migrate_resources	                        (rev 0)
+++ CalendarServer/trunk/bin/calendarserver_migrate_resources	2010-06-30 21:13:44 UTC (rev 5817)
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+##
+# Copyright (c) 2010 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.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+import sys
+
+#PYTHONPATH
+
+if __name__ == "__main__":
+    if "PYTHONPATH" in globals():
+        sys.path.insert(0, PYTHONPATH)
+    else:
+        from os.path import dirname, abspath, join
+        from subprocess import Popen, PIPE
+
+        home = dirname(dirname(abspath(__file__)))
+        run = join(home, "run")
+
+        child = Popen((run, "-p"), stdout=PIPE)
+        path, stderr = child.communicate()
+
+        path = path.rstrip("\n")
+
+        if child.wait() == 0:
+            sys.path[0:0] = path.split(":")
+
+        sys.argv[1:1] = ["-f", join(home, "conf", "caldavd-dev.plist")]
+
+    from calendarserver.tools.resources import main
+    main()


Property changes on: CalendarServer/trunk/bin/calendarserver_migrate_resources
___________________________________________________________________
Added: svn:executable
   + *

Added: CalendarServer/trunk/calendarserver/tools/resources.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/resources.py	                        (rev 0)
+++ CalendarServer/trunk/calendarserver/tools/resources.py	2010-06-30 21:13:44 UTC (rev 5817)
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+
+##
+# Copyright (c) 2006-2010 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.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from calendarserver.tools.principals import updateRecord
+from calendarserver.tools.util import loadConfig, getDirectory, setupMemcached, setupNotifications, checkDirectory
+from getopt import getopt, GetoptError
+from grp import getgrnam
+from pwd import getpwnam
+from twext.python.log import StandardIOObserver
+from twext.python.log import clearLogLevels
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks
+from twisted.python.util import switchUID
+from twistedcaldav.config import config, ConfigurationError
+from twistedcaldav.directory.appleopendirectory import OpenDirectoryService
+from twistedcaldav.directory.directory import DirectoryService, DirectoryError
+from twistedcaldav.directory.xmlfile import XMLDirectoryService
+import opendirectory, dsattributes
+import os
+import sys
+
+__all__ = [ "migrateResources", ]
+
+def usage():
+
+    name = os.path.basename(sys.argv[0])
+    print "usage: %s [options] " % (name,)
+    print ""
+    print "  Migrates resources and locations from OD to Calendar Server"
+    print ""
+    print "options:"
+    print "  -h --help: print this help and exit"
+    print "  -f --config <path>: Specify caldavd.plist configuration path"
+    print "  -v --verbose: print debugging information"
+    print ""
+
+    sys.exit(0)
+
+def abort(msg, status=1):
+    sys.stdout.write("%s\n" % (msg,))
+    try:
+        reactor.stop()
+    except RuntimeError:
+        pass
+    sys.exit(status)
+
+def main():
+    try:
+        (optargs, args) = getopt(
+            sys.argv[1:], "hf:v", [
+                "help",
+                "config=",
+                "verbose",
+            ],
+        )
+    except GetoptError, e:
+        usage(e)
+
+    #
+    # Get configuration
+    #
+    configFileName = None
+    verbose = False
+
+    for opt, arg in optargs:
+        if opt in ("-h", "--help"):
+            usage()
+
+        elif opt in ("-v", "--verbose"):
+            verbose = True
+
+        elif opt in ("-f", "--config"):
+            configFileName = arg
+
+        else:
+            raise NotImplementedError(opt)
+
+    #
+    # Get configuration
+    #
+    try:
+        loadConfig(configFileName)
+
+        # Do this first, because modifying the config object will cause
+        # some logging activity at whatever log level the plist says
+        clearLogLevels()
+
+        config.DefaultLogLevel = "info" if verbose else "error"
+
+        #
+        # Send logging output to stdout
+        #
+        observer = StandardIOObserver()
+        observer.start()
+
+        # Create the DataRoot directory before shedding privileges
+        if config.DataRoot.startswith(config.ServerRoot + os.sep):
+            checkDirectory(
+                config.DataRoot,
+                "Data root",
+                access=os.W_OK,
+                create=(0750, config.UserName, config.GroupName),
+            )
+
+        # Shed privileges
+        if config.UserName and config.GroupName and os.getuid() == 0:
+            uid = getpwnam(config.UserName).pw_uid
+            gid = getgrnam(config.GroupName).gr_gid
+            switchUID(uid, uid, gid)
+
+        os.umask(config.umask)
+
+        try:
+            config.directory = getDirectory()
+        except DirectoryError, e:
+            abort(e)
+        setupMemcached(config)
+        setupNotifications(config)
+    except ConfigurationError, e:
+        abort(e)
+
+    # Find the opendirectory service
+    userService = config.directory.serviceForRecordType("users")
+    resourceService = config.directory.serviceForRecordType("resources")
+    if (not isinstance(userService, OpenDirectoryService) or
+        not isinstance(resourceService, XMLDirectoryService)):
+        abort("This script only migrates resources and locations from OpenDirectory to XML; this calendar server does not have such a configuration.")
+
+    #
+    # Start the reactor
+    #
+    reactor.callLater(0, migrate, userService, resourceService, verbose=verbose)
+    reactor.run()
+
+
+
+ at inlineCallbacks
+def migrate(sourceService, resourceService, verbose=False):
+    """
+    Simply a wrapper around migrateResources in order to stop the reactor
+    """
+
+    try:
+        yield migrateResources(sourceService, resourceService, verbose=verbose)
+    finally:
+        reactor.stop()
+
+
+def queryForType(sourceService, recordType, verbose=False):
+    """
+    Queries OD for all records of the specified record type
+    """
+
+    attrs = [
+        dsattributes.kDS1AttrGeneratedUID,
+        dsattributes.kDS1AttrDistinguishedName,
+        # NEED THIS? dsattributes.kDSNAttrServicesLocator,
+    ]
+
+    if verbose:
+        print "Querying for all %s records" % (recordType,)
+
+    results = opendirectory.listAllRecordsWithAttributes_list(
+        sourceService.directory,
+        recordType,
+        attrs,
+    )
+
+    if verbose:
+        print "Found %d records" % (len(results),)
+
+    return results
+
+
+ at inlineCallbacks
+def migrateResources(sourceService, destService, queryMethod=queryForType,
+    verbose=False):
+
+    for recordTypeOD, recordType in (
+        (dsattributes.kDSStdRecordTypeResources, DirectoryService.recordType_resources),
+        (dsattributes.kDSStdRecordTypePlaces, DirectoryService.recordType_locations),
+    ):
+        data = queryMethod(sourceService, recordTypeOD, verbose=verbose)
+        for recordName, val in data:
+            guid = val.get(dsattributes.kDS1AttrGeneratedUID, None)
+            fullName = val.get(dsattributes.kDS1AttrDistinguishedName, None)
+            if guid and fullName:
+                if not recordName:
+                    recordName = guid
+                record = destService.recordWithGUID(guid)
+                if record is None:
+                    if verbose:
+                        print "Migrating %s (%s)" % (fullName, recordType)
+                    yield updateRecord(True, destService, recordType,
+                        guid=guid, shortNames=[recordName], fullName=fullName,
+                        autoSchedule="true")
+
+
+if __name__ == "__main__":
+    main()


Property changes on: CalendarServer/trunk/calendarserver/tools/resources.py
___________________________________________________________________
Added: svn:executable
   + *

Added: CalendarServer/trunk/calendarserver/tools/test/test_resources.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_resources.py	                        (rev 0)
+++ CalendarServer/trunk/calendarserver/tools/test/test_resources.py	2010-06-30 21:13:44 UTC (rev 5817)
@@ -0,0 +1,157 @@
+##
+# Copyright (c) 2005-2010 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.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from calendarserver.tools.resources import migrateResources
+from twisted.internet.defer import inlineCallbacks, succeed
+from twistedcaldav.directory import augment
+from twistedcaldav.directory.directory import DirectoryService
+from twistedcaldav.test.util import TestCase
+import dsattributes
+
+
+strGUID = dsattributes.kDS1AttrGeneratedUID
+strName = dsattributes.kDS1AttrDistinguishedName
+
+
+class StubDirectoryRecord(object):
+
+    def __init__(self, recordType, guid=None, shortNames=None, fullName=None):
+        self.recordType = recordType
+        self.guid = guid
+        self.shortNames = shortNames
+        self.fullName = fullName
+
+
+class StubDirectoryService(object):
+
+    def __init__(self):
+        self.records = {}
+
+    def recordWithGUID(self, guid):
+        return None
+
+    def createRecord(self, recordType, guid=None, shortNames=None,
+        fullName=None):
+        record = StubDirectoryRecord(recordType, guid=guid,
+            shortNames=shortNames, fullName=fullName)
+        self.records[guid] = record
+        return record
+
+    def updateRecord(self, recordType, guid=None, shortNames=None,
+        fullName=None):
+        pass
+
+
+class StubAugmentRecord(object):
+
+    def __init__(self, guid=None):
+        self.guid = guid
+        self.autoSchedule = True
+
+
+class StubAugmentService(object):
+
+    records = {}
+
+    @classmethod
+    def getAugmentRecord(cls, guid):
+        if not cls.records.has_key(guid):
+            record = StubAugmentRecord(guid=guid)
+            cls.records[guid] = record
+        return succeed(cls.records[guid])
+
+    @classmethod
+    def addAugmentRecords(cls, records):
+        for record in records:
+            cls.records[record.guid] = record
+        return succeed(True)
+
+
+class MigrateResourcesTestCase(TestCase):
+
+    @inlineCallbacks
+    def test_migrateResources(self):
+
+        data = {
+                dsattributes.kDSStdRecordTypeResources :
+                [
+                    ['projector1', {
+                        strGUID : '6C99E240-E915-4012-82FA-99E0F638D7EF',
+                        strName : 'Projector 1'
+                    }],
+                    ['projector2', {
+                        strGUID : '7C99E240-E915-4012-82FA-99E0F638D7EF',
+                        strName : 'Projector 2'
+                    }],
+                ],
+                dsattributes.kDSStdRecordTypePlaces :
+                [
+                    ['office1', {
+                        strGUID : '8C99E240-E915-4012-82FA-99E0F638D7EF',
+                        strName : 'Office 1'
+                    }],
+                ],
+            }
+
+        def queryMethod(sourceService, recordType, verbose=False):
+            return data[recordType]
+
+        self.patch(augment, "AugmentService", StubAugmentService)
+        directoryService = StubDirectoryService()
+        yield migrateResources(None, directoryService, queryMethod=queryMethod)
+        for guid, recordType in (
+            ('6C99E240-E915-4012-82FA-99E0F638D7EF', DirectoryService.recordType_resources),
+            ('7C99E240-E915-4012-82FA-99E0F638D7EF', DirectoryService.recordType_resources),
+            ('8C99E240-E915-4012-82FA-99E0F638D7EF', DirectoryService.recordType_locations),
+        ):
+            self.assertTrue(guid in directoryService.records)
+            record = directoryService.records[guid]
+            self.assertEquals(record.recordType, recordType)
+
+            self.assertTrue(guid in StubAugmentService.records)
+
+
+        #
+        # Add more to OD and re-migrate
+        #
+
+        data[dsattributes.kDSStdRecordTypeResources].append(
+            ['projector3', {
+                strGUID : '9C99E240-E915-4012-82FA-99E0F638D7EF',
+                strName : 'Projector 3'
+            }]
+        )
+        data[dsattributes.kDSStdRecordTypePlaces].append(
+            ['office2', {
+                strGUID : 'AC99E240-E915-4012-82FA-99E0F638D7EF',
+                strName : 'Office 2'
+            }]
+        )
+
+        yield migrateResources(None, directoryService, queryMethod=queryMethod)
+
+        for guid, recordType in (
+            ('6C99E240-E915-4012-82FA-99E0F638D7EF', DirectoryService.recordType_resources),
+            ('7C99E240-E915-4012-82FA-99E0F638D7EF', DirectoryService.recordType_resources),
+            ('9C99E240-E915-4012-82FA-99E0F638D7EF', DirectoryService.recordType_resources),
+            ('8C99E240-E915-4012-82FA-99E0F638D7EF', DirectoryService.recordType_locations),
+            ('AC99E240-E915-4012-82FA-99E0F638D7EF', DirectoryService.recordType_locations),
+        ):
+            self.assertTrue(guid in directoryService.records)
+            record = directoryService.records[guid]
+            self.assertEquals(record.recordType, recordType)
+
+            self.assertTrue(guid in StubAugmentService.records)

Added: CalendarServer/trunk/doc/calendarserver_migrate_resources.8
===================================================================
--- CalendarServer/trunk/doc/calendarserver_migrate_resources.8	                        (rev 0)
+++ CalendarServer/trunk/doc/calendarserver_migrate_resources.8	2010-06-30 21:13:44 UTC (rev 5817)
@@ -0,0 +1,51 @@
+.\"
+.\" Copyright (c) 2006-2010 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.
+.\" You may obtain a copy of the License at
+.\"
+.\"     http://www.apache.org/licenses/LICENSE-2.0
+.\"
+.\" Unless required by applicable law or agreed to in writing, software
+.\" distributed under the License is distributed on an "AS IS" BASIS,
+.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+.\" See the License for the specific language governing permissions and
+.\" limitations under the License.
+.\"
+.\" The following requests are required for all man pages.
+.Dd June 17, 2009
+.Dt CALENDARSERVER_MIGRATE_RESOURCES 8
+.Os
+.Sh NAME
+.Nm calendarserver_migrate_resources
+.Nd Darwin Calendar Server resource and location migration utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl -config Ar file
+.Op Fl -verbose
+.Op Fl -help
+.Sh DESCRIPTION
+.Nm
+is a tool for migrating resource and location records from OpenDirectory into the calendar server's internal directory.
+.Pp
+.Nm
+should be run as a user with the same priviledges as the Calendar
+Server itself, as it needs to read and write data that belongs to the
+server.
+.Sh OPTIONS
+.Bl -tag -width flag
+.It Fl h, -help
+Display usage information
+.It Fl f, -config Ar FILE
+Use the Calendar Server configuration specified in the given file.  Defaults to /etc/caldavd/caldavd.plist.
+.It Fl v, -verbose
+Print progress information including the names of resources and locations being migrated.
+.El
+.Sh FILES
+.Bl -tag -width flag
+.It /etc/caldavd/caldavd.plist
+The Calendar Server configuration file.
+.El
+.Sh SEE ALSO
+.Xr caldavd 8

Modified: CalendarServer/trunk/support/Makefile.Apple
===================================================================
--- CalendarServer/trunk/support/Makefile.Apple	2010-06-30 21:07:30 UTC (rev 5816)
+++ CalendarServer/trunk/support/Makefile.Apple	2010-06-30 21:13:44 UTC (rev 5817)
@@ -88,6 +88,7 @@
 	$(_v) $(INSTALL_FILE) "$(Sources)/doc/carddavd.8"                         "$(DSTROOT)$(MANDIR)/man8"
 	$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_export.8"            "$(DSTROOT)$(MANDIR)/man8"
 	$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_manage_principals.8" "$(DSTROOT)$(MANDIR)/man8"
+	$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_migrate_resources.8" "$(DSTROOT)$(MANDIR)/man8"
 	$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_command_gateway.8"   "$(DSTROOT)$(MANDIR)/man8"
 	$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_purge_events.8"   "$(DSTROOT)$(MANDIR)/man8"
 	$(_v) gzip -9 -f "$(DSTROOT)$(MANDIR)/man8/"*.[0-9]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100630/9ed56f7f/attachment-0001.html>


More information about the calendarserver-changes mailing list