[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