[CalendarServer-changes] [7304] CalendarServer/trunk/contrib/migration
source_changes at macosforge.org
source_changes at macosforge.org
Fri Apr 8 12:29:46 PDT 2011
Revision: 7304
http://trac.macosforge.org/projects/calendarserver/changeset/7304
Author: sagen at apple.com
Date: 2011-04-08 12:29:46 -0700 (Fri, 08 Apr 2011)
Log Message:
-----------
Migration extra script now copies from sourceRoot, handles Lion -> Lion upgrades, and is much more unit-tested.
Modified Paths:
--------------
CalendarServer/trunk/contrib/migration/calendarmigrator.py
CalendarServer/trunk/contrib/migration/test/test_migrator.py
Modified: CalendarServer/trunk/contrib/migration/calendarmigrator.py
===================================================================
--- CalendarServer/trunk/contrib/migration/calendarmigrator.py 2011-04-08 19:21:22 UTC (rev 7303)
+++ CalendarServer/trunk/contrib/migration/calendarmigrator.py 2011-04-08 19:29:46 UTC (rev 7304)
@@ -29,7 +29,7 @@
import subprocess
import sys
-from plistlib import readPlist, writePlist
+from plistlib import readPlist, readPlistFromString, writePlist
CALDAV_LAUNCHD_KEY = "org.calendarserver.calendarserver"
CARDDAV_LAUNCHD_KEY = "org.addressbookserver.addressbookserver"
@@ -45,6 +45,7 @@
RESOURCE_MIGRATION_TRIGGER = "trigger_resource_migration"
SERVER_ADMIN = "/usr/sbin/serveradmin"
LAUNCHCTL = "/bin/launchctl"
+DITTO = "/usr/bin/ditto"
verbatimKeys = """
@@ -213,13 +214,50 @@
if enableCalDAV:
unloadService(options, CALDAV_LAUNCHD_KEY)
- newServerRootValue = migrateData(options)
- migrateConfiguration(options, newServerRootValue, enableCalDAV,
- enableCardDAV)
+ # Pull values out of previous plists
+ (
+ oldServerRootValue,
+ oldCalDocumentRootValue,
+ oldCalDataRootValue,
+ oldABDocumentRootValue,
+ uid,
+ gid
+ ) = examinePreviousSystem(
+ options.sourceRoot,
+ options.targetRoot
+ )
+ # Copy data as needed
+ (
+ newServerRoot,
+ newServerRootValue,
+ newDocumentRootValue,
+ newDataRootValue
+ ) = relocateData(
+ options.sourceRoot,
+ options.targetRoot,
+ oldServerRootValue,
+ oldCalDocumentRootValue,
+ oldCalDataRootValue,
+ oldABDocumentRootValue,
+ uid,
+ gid
+ )
+
+ # Combine old and new plists
+ migrateConfiguration(
+ options,
+ newServerRootValue,
+ newDocumentRootValue,
+ newDataRootValue,
+ enableCalDAV,
+ enableCardDAV
+ )
+
configureNotifications()
- triggerResourceMigration(newServerRootValue)
+ triggerResourceMigration(newServerRoot)
+
setRunState(options, enableCalDAV, enableCardDAV)
else:
@@ -309,7 +347,8 @@
open(triggerPath, "w").close()
-def migrateConfiguration(options, newServerRootValue, enableCalDAV, enableCardDAV):
+def migrateConfiguration(options, newServerRootValue,
+ newDocumentRootValue, newDataRootValue, enableCalDAV, enableCardDAV):
"""
Copy files/directories/symlinks from previous system's /etc/caldavd
and /etc/carddavd
@@ -324,7 +363,6 @@
log("New configuration directory does not exist: %s" % (newConfigDir,))
return
-
for configDir in (CALDAVD_CONFIG_DIR, CARDDAVD_CONFIG_DIR):
oldConfigDir = os.path.join(options.sourceRoot, configDir)
@@ -386,8 +424,8 @@
mergePlist(oldCalDAVDPlist, oldCardDAVDPlist, newCalDAVDPlist)
newCalDAVDPlist["ServerRoot"] = newServerRootValue
- newCalDAVDPlist["DocumentRoot"] = "Documents"
- newCalDAVDPlist["DataRoot"] = "Data"
+ newCalDAVDPlist["DocumentRoot"] = newDocumentRootValue
+ newCalDAVDPlist["DataRoot"] = newDataRootValue
newCalDAVDPlist["EnableCalDAV"] = enableCalDAV
newCalDAVDPlist["EnableCardDAV"] = enableCardDAV
@@ -515,250 +553,211 @@
def log(msg):
try:
+ timestamp = datetime.datetime.now().strftime("%b %d %H:%M:%S")
+ msg = "calendarmigrator: %s %s" % (timestamp, msg)
+ print msg # so it appears in Setup.log
with open(LOG, 'a') as output:
- timestamp = datetime.datetime.now().strftime("%b %d %H:%M:%S")
- msg = "calendarmigrator: %s %s" % (timestamp, msg)
output.write("%s\n" % (msg,)) # so it appears in our log
- print msg # so it appears in Setup.log
except IOError:
# Could not write to log
pass
-def migrateData(options):
+def examinePreviousSystem(sourceRoot, targetRoot, diskAccessor=None):
"""
Examines the old caldavd.plist and carddavd.plist to see where data
- lives in the previous system. If there is old data, calls relocateData( )
+ lives in the previous system.
"""
- oldCalDocuments = None
- oldCalData = None
- oldABDocuments = None
- calendarDataInDefaultLocation = True
- addressbookDataInDefaultLocation = True
- uid = -1
- gid = -1
- newServerRoot = None # actual path
- newServerRootValue = NEW_SERVER_ROOT # value to put in plist
+ if diskAccessor is None:
+ diskAccessor = DiskAccessor()
- oldCalConfigDir = os.path.join(options.sourceRoot, CALDAVD_CONFIG_DIR)
+ oldServerRootValue = None
+ oldCalDocumentRootValue = None
+ oldCalDataRootValue = None
+ oldABDocumentRootValue = None
+
+ # Get uid and gid from new caldavd.plist
+ newCalConfigDir = os.path.join(targetRoot, CALDAVD_CONFIG_DIR)
+ newCalPlistPath = os.path.join(newCalConfigDir, CALDAVD_PLIST)
+ if diskAccessor.exists(newCalPlistPath):
+ contents = diskAccessor.readFile(newCalPlistPath)
+ newCalPlist = readPlistFromString(contents)
+ uid, gid = getServerIDs(newCalPlist)
+ log("ServerIDs from %s: %d, %d" % (newCalPlistPath, uid, gid))
+ else:
+ uid = gid = -1
+ log("Can't find new calendar plist at %s" % (newCalPlistPath,))
+
+ # Try and read old caldavd.plist
+ oldCalConfigDir = os.path.join(sourceRoot, CALDAVD_CONFIG_DIR)
oldCalPlistPath = os.path.join(oldCalConfigDir, CALDAVD_PLIST)
- if os.path.exists(oldCalPlistPath):
- oldCalPlist = readPlist(oldCalPlistPath)
- uid, gid = getServerIDs(oldCalPlist)
- log("ServerIDs: %d, %d" % (uid, gid))
+ if diskAccessor.exists(oldCalPlistPath):
+ contents = diskAccessor.readFile(oldCalPlistPath)
+ oldCalPlist = readPlistFromString(contents)
+ log("Found previous caldavd plist at %s" % (oldCalPlistPath,))
+
+ oldServerRootValue = oldCalPlist.get("ServerRoot", None)
+ oldCalDocumentRootValue = oldCalPlist.get("DocumentRoot", None)
+ oldCalDataRootValue = oldCalPlist.get("DataRoot", None)
+
else:
log("Can't find previous calendar plist at %s" % (oldCalPlistPath,))
oldCalPlist = None
- newCalConfigDir = os.path.join(options.targetRoot, CALDAVD_CONFIG_DIR)
- newCalPlistPath = os.path.join(newCalConfigDir, CALDAVD_PLIST)
- if os.path.exists(newCalPlistPath):
- newCalPlist = readPlist(newCalPlistPath)
- uid, gid = getServerIDs(newCalPlist)
- log("ServerIDs: %d, %d" % (uid, gid))
+ # Try and read old carddavd.plist
+ oldABConfigDir = os.path.join(sourceRoot, CARDDAVD_CONFIG_DIR)
+ oldABPlistPath = os.path.join(oldABConfigDir, CARDDAVD_PLIST)
+ if diskAccessor.exists(oldABPlistPath):
+ contents = diskAccessor.readFile(oldABPlistPath)
+ oldABPlist = readPlistFromString(contents)
+ log("Found previous carddavd plist at %s" % (oldABPlistPath,))
- oldABConfigDir = os.path.join(options.sourceRoot, CARDDAVD_CONFIG_DIR)
- oldABPlistPath = os.path.join(oldABConfigDir, CARDDAVD_PLIST)
- if os.path.exists(oldABPlistPath):
- oldABPlist = readPlist(oldABPlistPath)
+ oldABDocumentRootValue = oldABPlist.get("DocumentRoot", None)
else:
- log("Can't find previous addressbook plist at %s" % (oldABPlistPath,))
+ log("Can't find previous carddavd plist at %s" % (oldABPlistPath,))
oldABPlist = None
- if oldCalPlist is not None:
- # See if there is actually any calendar data
+ return (
+ oldServerRootValue,
+ oldCalDocumentRootValue,
+ oldCalDataRootValue,
+ oldABDocumentRootValue,
+ uid,
+ gid
+ )
- oldDocumentRoot = oldCalPlist["DocumentRoot"]
- if oldDocumentRoot.rstrip("/") != "/Library/CalendarServer/Documents":
- log("Calendar data in non-standard location: %s" % (oldDocumentRoot,))
- calendarDataInDefaultLocation = False
- else:
- log("Calendar data in standard location: %s" % (oldDocumentRoot,))
- oldDataRoot = oldCalPlist["DataRoot"]
+def relocateData(sourceRoot, targetRoot, oldServerRootValue,
+ oldCalDocumentRootValue, oldCalDataRootValue, oldABDocumentRootValue,
+ uid, gid, diskAccessor=None):
+ """
+ Copy data from sourceRoot to targetRoot, except when data is on another
+ volume in which case we just refer to it there.
+ """
- oldCalendarsPath = os.path.join(oldDocumentRoot, "calendars")
- if os.path.exists(oldCalendarsPath):
- # There is calendar data
- oldCalDocuments = oldDocumentRoot
- oldCalData = oldDataRoot
- log("Calendar data to migrate from %s and %s" %
- (oldCalDocuments, oldCalData))
+ if diskAccessor is None:
+ diskAccessor = DiskAccessor()
- if calendarDataInDefaultLocation:
- newServerRoot = absolutePathWithRoot(options.targetRoot,
- NEW_SERVER_ROOT)
- newServerRootValue = NEW_SERVER_ROOT
- else:
- newServerRoot = absolutePathWithRoot(options.targetRoot,
- oldDocumentRoot)
- newServerRootValue = oldDocumentRoot
- else:
- log("No calendar data to migrate")
+ log("RelocateData: sourceRoot=%s, targetRoot=%s, oldServerRootValue=%s, oldCalDocumentRootValue=%s, oldCalDataRootValue=%s, oldABDocumentRootValue=%s, uid=%d, gid=%d" % (sourceRoot, targetRoot, oldServerRootValue, oldCalDocumentRootValue, oldCalDataRootValue, oldABDocumentRootValue, uid, gid))
- if oldABPlist is not None:
- # See if there is actually any addressbook data
- oldDocumentRoot = oldABPlist["DocumentRoot"]
- if oldDocumentRoot.rstrip("/") != "/Library/AddressBookServer/Documents":
- log("AddressBook data in non-standard location: %s" % (oldDocumentRoot,))
- addressbookDataInDefaultLocation = False
+ if oldServerRootValue:
+ newServerRootValue = oldServerRootValue
+ # Source is Lion; see if ServerRoot refers to an external volume
+ # or a directory in sourceRoot
+ if diskAccessor.exists(oldServerRootValue):
+ # refers to an external volume
+ newServerRoot = newServerRootValue
+ elif diskAccessor.exists(os.path.join(sourceRoot, oldServerRootValue)):
+ # refers to a directory on sourceRoot
+ newServerRoot = absolutePathWithRoot(targetRoot, newServerRootValue)
else:
- log("AddressBook data in standard location: %s" % (oldDocumentRoot,))
+ # It doesn't exist, so use default
+ newServerRootValue = NEW_SERVER_ROOT
+ newServerRoot = absolutePathWithRoot(targetRoot, newServerRootValue)
- oldAddressbooksPath = os.path.join(oldDocumentRoot, "addressbooks")
- if os.path.exists(oldAddressbooksPath):
- # There is addressbook data
- oldABDocuments = oldDocumentRoot
- log("AddressBook data to migrate from %s" % (oldABDocuments,))
+ # If there was an old ServerRoot value, process DocumentRoot and
+ # DataRoot because those could be relative to ServerRoot
+ oldCalDocumentRootValueProcessed = os.path.join(oldServerRootValue,
+ oldCalDocumentRootValue)
+ oldCalDataRootValueProcessed = os.path.join(oldServerRootValue,
+ oldCalDataRootValue)
+ else:
+ newServerRootValue = NEW_SERVER_ROOT
+ newServerRoot = absolutePathWithRoot(targetRoot, newServerRootValue)
+ oldCalDocumentRootValueProcessed = oldCalDocumentRootValue
+ oldCalDataRootValueProcessed = oldCalDataRootValue
- if newServerRoot is None:
- # don't override server root computed from calendar
- if addressbookDataInDefaultLocation:
- newServerRoot = absolutePathWithRoot(options.targetRoot,
- NEW_SERVER_ROOT)
- newServerRootValue = NEW_SERVER_ROOT
- else:
- newServerRoot = absolutePathWithRoot(options.targetRoot,
- oldDocumentRoot)
- newServerRootValue = oldDocumentRoot
- else:
- log("No addressbook data to migrate")
+ # Set default values for these, possibly overridden below:
+ newDocumentRootValue = "Documents"
+ newDocumentRoot = absolutePathWithRoot(
+ targetRoot,
+ os.path.join(newServerRootValue, newDocumentRootValue)
+ )
+ newDataRootValue = "Data"
+ newDataRoot = absolutePathWithRoot(
+ targetRoot,
+ os.path.join(newServerRootValue, newDataRootValue)
+ )
- if (oldCalDocuments or oldABDocuments) and newServerRoot:
- relocateData(oldCalDocuments, oldCalData, oldABDocuments, uid, gid,
- calendarDataInDefaultLocation, addressbookDataInDefaultLocation,
- newServerRoot)
+ # Old Calendar DocumentRoot
+ if oldCalDocumentRootValueProcessed:
+ if diskAccessor.exists(oldCalDocumentRootValueProcessed):
+ # Must be on an external volume if we see it existing at the point
+ # so don't copy it
+ newDocumentRoot = newDocumentRootValue = oldCalDocumentRootValueProcessed
+ elif diskAccessor.exists(absolutePathWithRoot(sourceRoot, oldCalDocumentRootValueProcessed)):
+ diskAccessor.ditto(
+ absolutePathWithRoot(sourceRoot, oldCalDocumentRootValueProcessed),
+ newDocumentRoot
+ )
+ diskAccessor.chown(newDocumentRoot, uid, gid, recursive=True)
- return newServerRootValue
+ # Old Calendar DataRoot
+ if oldCalDataRootValueProcessed:
+ if diskAccessor.exists(oldCalDataRootValueProcessed):
+ # Must be on an external volume if we see it existing at the point
+ # so don't copy it
+ newDataRootValue = oldCalDataRootValueProcessed
+ elif diskAccessor.exists(
+ absolutePathWithRoot(sourceRoot, oldCalDataRootValueProcessed)
+ ):
+ diskAccessor.ditto(
+ absolutePathWithRoot(sourceRoot, oldCalDataRootValueProcessed),
+ newDataRoot
+ )
+ diskAccessor.chown(newDataRoot, uid, gid, recursive=True)
-def relocateData(oldCalDocuments, oldCalData, oldABDocuments, uid, gid,
- calendarDataInDefaultLocation, addressbookDataInDefaultLocation,
- newServerRoot):
- """
- Relocates existing calendar data to the new default location iff the data
- was previously in the old default location; otherwise the old calendar
- DocumentRoot becomes the new ServerRoot directory, the contents of the
- old DocumentRoot are moved into ServerRoot/Documents and the contents of
- old DataRoot are copied/moved into ServerRoot/Data. If there is addressbook
- data, a symlink is created as ServerRoot/Documents/addressbooks pointing
- to the old addressbook directory so that the import-to-PostgreSQL will
- find it.
- """
+ # Old AddressBook DocumentRoot
+ if oldABDocumentRootValue:
+ newAddressBooks = os.path.join(newDocumentRoot, "addressbooks")
+ if diskAccessor.exists(oldABDocumentRootValue):
+ # Must be on an external volume if we see it existing at the point
+ diskAccessor.ditto(
+ os.path.join(oldABDocumentRootValue, "addressbooks"),
+ newAddressBooks
+ )
+ elif diskAccessor.exists(
+ absolutePathWithRoot(sourceRoot, oldABDocumentRootValue)
+ ):
+ diskAccessor.ditto(
+ absolutePathWithRoot(
+ sourceRoot,
+ os.path.join(oldABDocumentRootValue, "addressbooks")
+ ),
+ os.path.join(newDocumentRoot, "addressbooks")
+ )
+ if diskAccessor.exists(newAddressBooks):
+ diskAccessor.chown(newAddressBooks, uid, gid, recursive=True)
- log("RelocateData: cal documents=%s, cal data=%s, ab documents=%s, new server root=%s"
- % (oldCalDocuments, oldCalData, oldABDocuments, newServerRoot))
- if oldCalDocuments and os.path.exists(oldCalDocuments):
+ # Change ownership of newServerRoot
+ if newServerRoot and diskAccessor.exists(newServerRoot):
+ diskAccessor.chown(newServerRoot, uid, gid, recursive=False)
- if calendarDataInDefaultLocation:
- # We're in the default location, relocate to new location
- newCalDocuments = os.path.join(newServerRoot, "Documents")
- if not os.path.exists(newCalDocuments):
- os.mkdir(newCalDocuments)
- newCalData = os.path.join(newServerRoot, "Data")
- if not os.path.exists(newCalData):
- os.mkdir(newCalData)
- if os.path.exists(oldCalDocuments):
- # Move evertying from oldCalDocuments
- for item in list(os.listdir(oldCalDocuments)):
- source = os.path.join(oldCalDocuments, item)
- dest = os.path.join(newCalDocuments, item)
- log("Relocating %s to %s" % (source, dest))
- os.rename(source, dest)
- else:
- log("Warning: %s does not exist; nothing to migrate" % (oldCalDocuments,))
- else:
- # The admin has moved calendar data to a non-standard location so
- # we're going to leave it there, but move things down a level so
- # that the old DocumentRoot becomes new ServerRoot
+ newServerRootValue, newDocumentRootValue = relativize(newServerRootValue,
+ newDocumentRootValue)
+ newServerRootValue, newDataRootValue = relativize(newServerRootValue,
+ newDataRootValue)
- # Create "Documents" directory with same ownership as oldCalDocuments
- newCalDocuments = os.path.join(newServerRoot, "Documents")
- log("New documents directory: %s" % (newCalDocuments,))
- newCalData = os.path.join(newServerRoot, "Data")
- log("New data directory: %s" % (newCalData,))
- os.mkdir(newCalDocuments)
- os.mkdir(newCalData)
- for item in list(os.listdir(newServerRoot)):
- if item not in ("Documents", "Data"):
- source = os.path.join(newServerRoot, item)
- dest = os.path.join(newCalDocuments, item)
- log("Relocating %s to %s" % (source, dest))
- os.rename(source, dest)
+ return (
+ newServerRoot,
+ newServerRootValue,
+ newDocumentRootValue,
+ newDataRootValue
+ )
- # Relocate calendar DataRoot, copying all files
- if os.path.exists(oldCalData):
- if not os.path.exists(newCalData):
- os.mkdir(newCalData)
- for item in list(os.listdir(oldCalData)):
- source = os.path.join(oldCalData, item)
- if not os.path.isfile(source):
- continue
- dest = os.path.join(newCalData, item)
- log("Relocating %s to %s" % (source, dest))
- try:
- os.rename(source, dest)
- except OSError:
- # Can't rename because it's cross-volume; must copy/delete
- shutil.copy2(source, dest)
- os.remove(source)
- # Symlink to AB document root so server will find it an import to
- # PostgreSQL
- if oldABDocuments and os.path.exists(oldABDocuments):
- oldAddressBooks = os.path.join(oldABDocuments, "addressbooks")
- newAddressBooks = os.path.join(newCalDocuments, "addressbooks")
- log("Symlinking AddressBook data: %s to %s" % (newAddressBooks, oldAddressBooks))
- os.symlink(oldAddressBooks, newAddressBooks)
+def relativize(parent, child):
+ """
+ If child is really a child of parent, make child relative to parent.
+ """
+ if child.startswith(parent):
+ parent = parent.rstrip("/")
+ child = child[len(parent):].strip("/")
+ return parent.rstrip("/"), child.rstrip("/")
- elif oldABDocuments and os.path.exists(oldABDocuments):
- # No calendar data, only addressbook data
-
- if addressbookDataInDefaultLocation:
- # We're in the default location, relocate to new location
- newABDocuments = os.path.join(newServerRoot, "Documents")
- if os.path.exists(newABDocuments):
- # Move evertying from oldABDocuments
- for item in list(os.listdir(oldABDocuments)):
- source = os.path.join(oldABDocuments, item)
- dest = os.path.join(newABDocuments, item)
- log("Relocating %s to %s" % (source, dest))
- os.rename(source, dest)
- else:
- log("Error: %s does not exist" % (newABDocuments,))
- else:
- # The admin has moved addressbook data to a non-standard location so
- # we're going to leave it there, but move things down a level so
- # that the old DocumentRoot becomes new ServerRoot
-
- # Create "Documents" directory with same ownership as oldABDocuments
- newABDocuments = os.path.join(newServerRoot, "Documents")
- newABData = os.path.join(newServerRoot, "Data")
- log("New documents directory: %s" % (newABDocuments,))
- os.mkdir(newABDocuments)
- os.mkdir(newABData)
- for item in list(os.listdir(newServerRoot)):
- if item not in ("Documents", "Data"):
- source = os.path.join(newServerRoot, item)
- dest = os.path.join(newABDocuments, item)
- log("Relocating %s to %s" % (source, dest))
- os.rename(source, dest)
-
- if newServerRoot and os.path.exists(newServerRoot):
- """
- Change onwnership of entire ServerRoot
- """
- os.chown(newServerRoot, uid, gid)
- for root, dirs, files in os.walk(newServerRoot, followlinks=True):
- for name in dirs:
- os.chown(os.path.join(root, name), uid, gid)
- for name in files:
- os.chown(os.path.join(root, name), uid, gid)
-
-
-
def getServerIDs(plist):
"""
Given a caldavd.plist, return the userid and groupid for the UserName and
@@ -772,6 +771,7 @@
gid = grp.getgrnam(plist["GroupName"]).gr_gid
return uid, gid
+
def absolutePathWithRoot(root, path):
"""
Combine root and path as long as path does not start with /Volumes/
@@ -782,5 +782,59 @@
path = path.strip("/")
return os.path.join(root, path)
+
+class DiskAccessor(object):
+ """
+ A wrapper around various disk access methods so that unit tests can easily
+ replace these with a stub that doesn't actually require disk access.
+ """
+
+ def exists(self, path):
+ return os.path.exists(path)
+
+ def readFile(self, path):
+ input = file(path)
+ contents = input.read()
+ input.close()
+ return contents
+
+ def mkdir(self, path):
+ return os.mkdir(path)
+
+ def rename(self, before, after):
+ try:
+ return os.rename(before, after)
+ except OSError:
+ # Can't rename because it's cross-volume; must copy/delete
+ shutil.copy2(before, after)
+ return os.remove(before)
+
+ def isfile(self, path):
+ return os.path.isfile(path)
+
+ def symlink(self, orig, link):
+ return os.symlink(orig, link)
+
+ def chown(self, path, uid, gid, recursive=False):
+ os.chown(path, uid, gid)
+ if recursive:
+ for root, dirs, files in os.walk(path, followlinks=True):
+ for name in dirs:
+ os.chown(os.path.join(root, name), uid, gid)
+ for name in files:
+ os.chown(os.path.join(root, name), uid, gid)
+
+
+ def walk(self, path, followlinks=True):
+ return os.walk(path, followlinks=followlinks)
+
+ def listdir(self, path):
+ return list(os.listdir(path))
+
+ def ditto(self, src, dest):
+ log("Copying with ditto: %s to %s" % (src, dest))
+ return subprocess.call([DITTO, src, dest])
+
+
if __name__ == '__main__':
main()
Modified: CalendarServer/trunk/contrib/migration/test/test_migrator.py
===================================================================
--- CalendarServer/trunk/contrib/migration/test/test_migrator.py 2011-04-08 19:21:22 UTC (rev 7303)
+++ CalendarServer/trunk/contrib/migration/test/test_migrator.py 2011-04-08 19:29:46 UTC (rev 7304)
@@ -15,13 +15,21 @@
##
import twistedcaldav.test.util
-from contrib.migration.calendarmigrator import mergePlist
+from contrib.migration.calendarmigrator import (
+ mergePlist, examinePreviousSystem, relocateData, relativize
+)
+import contrib.migration.calendarmigrator
class MigrationTests(twistedcaldav.test.util.TestCase):
"""
Calendar Server Migration Tests
"""
+ def setUp(self):
+ # Disable logging during tests
+ self.patch(contrib.migration.calendarmigrator, "log", lambda _: None)
+
+
def test_mergeSSL(self):
# SSL on for both services
@@ -237,6 +245,33 @@
mergePlist(oldCalDAV, oldCardDAV, newCombined)
self.assertEquals(newCombined, expected)
+ # Only CalDAV (Lion -> Lion)
+ oldCalDAV = {
+ "BindHTTPPorts": [],
+ "BindSSLPorts": [],
+ "HTTPPort": 8008,
+ "RedirectHTTPToHTTPS": False,
+ "SSLAuthorityChain": "/etc/certificates/test.chain.pem",
+ "SSLCertificate": "/etc/certificates/test.cert.pem",
+ "SSLPort": 8443,
+ "SSLPrivateKey": "/etc/certificates/test.key.pem",
+ }
+ oldCardDAV = {
+ }
+ expected = {
+ "BindHTTPPorts": [8008, 8800],
+ "BindSSLPorts": [8443, 8843],
+ "EnableSSL" : True,
+ "HTTPPort": 8008,
+ "RedirectHTTPToHTTPS": True,
+ "SSLAuthorityChain": "/etc/certificates/test.chain.pem",
+ "SSLCertificate": "/etc/certificates/test.cert.pem",
+ "SSLPort": 8443,
+ "SSLPrivateKey": "/etc/certificates/test.key.pem",
+ }
+ newCombined = { }
+ mergePlist(oldCalDAV, oldCardDAV, newCombined)
+ self.assertEquals(newCombined, expected)
# All settings missing!
@@ -256,3 +291,1061 @@
newCombined = { }
mergePlist(oldCalDAV, oldCardDAV, newCombined)
self.assertEquals(newCombined, expected)
+
+
+ def test_examinePreviousSystem(self):
+ """
+ Set up a virtual system in various configurations, then ensure the
+ examinePreviousSystem( ) method detects/returns the expected values.
+
+ 'info' is an array of tuples, each tuple containing:
+ - Description of configuration
+ - Layout of disk as a dictionary of paths plus file contents
+ - Expected return values
+ """
+
+ info = [
+
+ (
+ "Snow -> Lion Migration, all in default locations",
+ ("/Volumes/old", "/"),
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/CalendarServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/CalendarServer/Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/private/etc/carddavd/carddavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/AddressBookServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/AddressBookServer/Data</string>
+ </dict>
+ </plist>
+ """,
+ "/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/old/Library/CalendarServer/Documents/calendars/" : True,
+ "/Volumes/old/Library/CalendarServer/Data/" : True,
+ "/Volumes/old/Library/AddressBookServer/Documents/addressbooks/" : True,
+ "/Volumes/old/Library/AddressBookServer/Data/" : True,
+ },
+ (
+ None, # Old ServerRoot value
+ "/Library/CalendarServer/Documents", # Old Cal DocRoot value
+ "/Library/CalendarServer/Data", # Old Cal DataRoot value
+ "/Library/AddressBookServer/Documents", # Old AB DocRoot value
+ 93, 93, # user id, group id
+ )
+ ),
+
+ (
+ "Snow -> Lion Migration, all in default locations, non-/ target",
+ ("/Volumes/old", "/Volumes/new"),
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/CalendarServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/CalendarServer/Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/private/etc/carddavd/carddavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/AddressBookServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/AddressBookServer/Data</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/old/Library/CalendarServer/Documents/calendars/" : True,
+ "/Volumes/old/Library/CalendarServer/Data/" : True,
+ "/Volumes/old/Library/AddressBookServer/Documents/addressbooks/" : True,
+ "/Volumes/old/Library/AddressBookServer/Data/" : True,
+ },
+ (
+ None, # Old ServerRoot value
+ "/Library/CalendarServer/Documents", # Old Cal DocRoot value
+ "/Library/CalendarServer/Data", # Old Cal DataRoot value
+ "/Library/AddressBookServer/Documents", # Old AB DocRoot value
+ 93, 93, # user id, group id
+ )
+ ),
+
+ (
+ "Snow -> Lion Migration, not in default locations",
+ ("/Volumes/old", "/"),
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/NonStandard/CalendarServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/NonStandard/CalendarServer/Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/private/etc/carddavd/carddavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/NonStandard/AddressBookServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/NonStandard/AddressBookServer/Data</string>
+ </dict>
+ </plist>
+ """,
+ "/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/old/NonStandard/CalendarServer/Documents/calendars/" : True,
+ "/Volumes/old/NonStandard/CalendarServer/Data/" : True,
+ "/Volumes/old/NonStandard/AddressBookServer/Documents/addressbooks/" : True,
+ "/Volumes/old/NonStandard/AddressBookServer/Data/" : True,
+ },
+ (
+ None, # Old ServerRoot value
+ "/NonStandard/CalendarServer/Documents", # Old Cal DocRoot Value
+ "/NonStandard/CalendarServer/Data", # Old Cal DataRoot Value
+ "/NonStandard/AddressBookServer/Documents", # Old AB DocRoot Value
+ 93, 93, # user id, group id
+ )
+ ),
+
+ (
+ "Snow -> Lion Migration, in internal/external locations",
+ ("/Volumes/old", "/"),
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Volumes/External/CalendarServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Volumes/External/CalendarServer/Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/private/etc/carddavd/carddavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/AddressBookServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/AddressBookServer/Data</string>
+ </dict>
+ </plist>
+ """,
+ "/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/External/CalendarServer/Documents/calendars/" : True,
+ "/Volumes/External/CalendarServer/Data/" : True,
+ "/Volumes/old/Library/AddressBookServer/Documents/addressbooks/" : True,
+ "/Volumes/old/Library/AddressBookServer/Data/" : True,
+ },
+ (
+ None, # Old ServerRoot value
+ "/Volumes/External/CalendarServer/Documents", # Old Cal DocRoot Value
+ "/Volumes/External/CalendarServer/Data", # Old Cal DataRoot Value
+ "/Library/AddressBookServer/Documents", # Old AB DocRoot Value
+ 93, 93, # user id, group id
+ )
+ ),
+
+
+ (
+ "Snow -> Lion Migration, only AddressBook data",
+ ("/Volumes/old", "/"),
+ {
+ "/Volumes/old/private/etc/carddavd/carddavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/AddressBookServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/AddressBookServer/Data</string>
+ </dict>
+ </plist>
+ """,
+ "/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/old/Library/AddressBookServer/Documents/addressbooks/" : True,
+ "/Volumes/old/Library/AddressBookServer/Data/" : True,
+ },
+ (
+ None, # Old ServerRoot value
+ None, # Old Cal DocRoot value
+ None, # Old Cal DataRoot value
+ "/Library/AddressBookServer/Documents", # Old AB DocRoot value
+ 93, 93, # user id, group id
+ )
+ ),
+
+ (
+ "Lion -> Lion Migration, all in default locations",
+ ("/Volumes/old", "/"),
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/Library/Server/Calendar and Contacts/Documents/" : True,
+ "/Volumes/old/Library/Server/Calendar and Contacts/Data/" : True,
+ },
+ (
+ "/Library/Server/Calendar and Contacts", # Old ServerRoot value
+ "Documents", # Old Cal DocRoot value
+ "Data", # Old Cal DataRoot value
+ None, # Old AB Docs
+ 93, 93, # user id, group id
+ )
+ ),
+
+ (
+ "Lion -> Lion Migration, not in default locations",
+ ("/Volumes/old", "/"),
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/NonStandard/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>/Volumes/External/Calendar/Documents</string>
+ <key>DataRoot</key>
+ <string>/Volumes/External/Calendar/Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/NonStandard/Calendar and Contacts/Documents/" : True,
+ "/Volumes/old/NonStandard/Calendar and Contacts/Data/" : True,
+ },
+ (
+ "/NonStandard/Calendar and Contacts", # Old ServerRoot value
+ "/Volumes/External/Calendar/Documents", # Old Cal DocRoot value
+ "/Volumes/External/Calendar/Data", # Old Cal DataRoot value
+ None, # Old AB Docs
+ 93, 93, # user id, group id
+ )
+ ),
+
+ (
+ "Lion -> Lion Migration, non-/ targetRoot",
+ ("/Volumes/old", "/Volumes/new"),
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/Library/Server/Calendar and Contacts/Documents/" : True,
+ "/Volumes/old/Library/Server/Calendar and Contacts/Data/" : True,
+ },
+ (
+ "/Library/Server/Calendar and Contacts", # Old ServerRoot value
+ "Documents", # Old Cal DocRoot value
+ "Data", # Old Cal DocRoot value
+ None, # Old AB Docs
+ 93, 93, # user id, group id
+ )
+ ),
+
+ (
+ "Lion -> Lion Migration, external ServerRoot with absolute external DocumentRoot and internal DataRoot",
+ ("/Volumes/old", "/Volumes/new"),
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Volumes/External/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>/Volumes/External/CalendarDocuments/</string>
+ <key>DataRoot</key>
+ <string>/CalendarData</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/External/Library/Server/Calendar and Contacts/" : True,
+ "/Volumes/External/CalendarDocuments/" : True,
+ "/Volumes/old/CalendarData" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts/" : True,
+ },
+ (
+ "/Volumes/External/Server/Calendar and Contacts", # Old ServerRoot value
+ "/Volumes/External/CalendarDocuments/", # Old Cal DocRoot value
+ "/CalendarData", # Old Cal DocRoot value
+ None, # Old AB Docs
+ 93, 93, # user id, group id
+ )
+ ),
+
+
+
+ (
+ "Empty migration, nothing exists",
+ ("/Volumes/old", "/Volumes/new"),
+ {
+ },
+ (
+ None, # Old ServerRoot value
+ None, # Old Cal DocRoot value
+ None, # Old Cal DocRoot value
+ None, # Old AB Docs
+ -1, -1, # user id, group id
+ )
+ ),
+
+
+ ]
+
+ for description, (source, target), paths, expected in info:
+ # print "-=-=-=- %s -=-=-=-" % (description,)
+ accessor = StubDiskAccessor(paths)
+ actual = examinePreviousSystem(source, target, diskAccessor=accessor)
+ self.assertEquals(expected, actual)
+
+
+ def test_relocateData(self):
+
+ info = [
+
+ (
+ "Snow -> Lion Migration, all in default locations",
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/CalendarServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/CalendarServer/Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/private/etc/carddavd/carddavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/AddressBookServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/AddressBookServer/Data</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/old/Library/CalendarServer/Documents/calendars/" : True,
+ "/Volumes/old/Library/CalendarServer/Data/" : True,
+ "/Volumes/old/Library/AddressBookServer/Documents/addressbooks/" : True,
+ "/Volumes/old/Library/AddressBookServer/Data/" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts" : True,
+ },
+ ( # args
+ "/Volumes/old", # sourceRoot
+ "/Volumes/new", # targetRoot
+ None, # oldServerRootValue
+ "/Library/CalendarServer/Documents", # oldCalDocumentRootValue
+ "/Library/CalendarServer/Data", # oldCalDataRootValue
+ "/Library/AddressBookServer/Documents", # oldABDocumentRootValue
+ 93, 93, # user id, group id
+ ),
+ ( # expected return values
+ "/Volumes/new/Library/Server/Calendar and Contacts",
+ "/Library/Server/Calendar and Contacts",
+ "Documents",
+ "Data"
+ ),
+ [ # expected DiskAccessor history
+ ('ditto', '/Volumes/old/Library/CalendarServer/Documents', '/Volumes/new/Library/Server/Calendar and Contacts/Documents'),
+ ('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts/Documents', 93, 93),
+ ('ditto', '/Volumes/old/Library/CalendarServer/Data', '/Volumes/new/Library/Server/Calendar and Contacts/Data'),
+ ('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts/Data', 93, 93),
+ ('ditto', '/Volumes/old/Library/AddressBookServer/Documents/addressbooks', '/Volumes/new/Library/Server/Calendar and Contacts/Documents/addressbooks'),
+ ('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts/Documents/addressbooks', 93, 93),
+ ('chown', '/Volumes/new/Library/Server/Calendar and Contacts', 93, 93),
+ ]
+ ),
+
+ (
+ "Snow -> Lion Migration, in non-standard locations",
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/NonStandard/CalendarServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/NonStandard/CalendarServer/Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/private/etc/carddavd/carddavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/NonStandard/AddressBookServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/NonStandard/AddressBookServer/Data</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/old/NonStandard/CalendarServer/Documents/calendars/" : True,
+ "/Volumes/old/NonStandard/CalendarServer/Data/" : True,
+ "/Volumes/old/NonStandard/AddressBookServer/Documents/addressbooks/" : True,
+ "/Volumes/old/NonStandard/AddressBookServer/Data/" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts" : True,
+ },
+ ( # args
+ "/Volumes/old", # sourceRoot
+ "/Volumes/new", # targetRoot
+ None, # oldServerRootValue
+ "/NonStandard/CalendarServer/Documents", # oldCalDocumentRootValue
+ "/NonStandard/CalendarServer/Data", # oldCalDataRootValue
+ "/NonStandard/AddressBookServer/Documents", # oldABDocumentRootValue
+ 93, 93, # user id, group id
+ ),
+ ( # expected return values
+ "/Volumes/new/Library/Server/Calendar and Contacts",
+ "/Library/Server/Calendar and Contacts",
+ "Documents",
+ "Data"
+ ),
+ [
+ ('ditto', '/Volumes/old/NonStandard/CalendarServer/Documents', '/Volumes/new/Library/Server/Calendar and Contacts/Documents'),
+ ('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts/Documents', 93, 93),
+ ('ditto', '/Volumes/old/NonStandard/CalendarServer/Data', '/Volumes/new/Library/Server/Calendar and Contacts/Data'),
+ ('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts/Data', 93, 93),
+ ('ditto', '/Volumes/old/NonStandard/AddressBookServer/Documents/addressbooks', '/Volumes/new/Library/Server/Calendar and Contacts/Documents/addressbooks'),
+ ('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts/Documents/addressbooks', 93, 93),
+ ('chown', '/Volumes/new/Library/Server/Calendar and Contacts', 93, 93),
+ ]
+ ),
+
+ (
+ "Snow -> Lion Migration, internal AB, external Cal",
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Volumes/External/CalendarServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Volumes/External/CalendarServer/Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/old/private/etc/carddavd/carddavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>DocumentRoot</key>
+ <string>/Library/AddressBookServer/Documents</string>
+ <key>DataRoot</key>
+ <string>/Library/AddressBookServer/Data</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/External/CalendarServer/Documents" : True,
+ "/Volumes/External/CalendarServer/Data" : True,
+ "/Volumes/old/Library/AddressBookServer/Documents/addressbooks/" : True,
+ "/Volumes/old/Library/AddressBookServer/Data/" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts" : True,
+ },
+ ( # args
+ "/Volumes/old", # sourceRoot
+ "/Volumes/new", # targetRoot
+ None, # oldServerRootValue
+ "/Volumes/External/CalendarServer/Documents", # oldCalDocumentRootValue
+ "/Volumes/External/CalendarServer/Data", # oldCalDataRootValue
+ "/Library/AddressBookServer/Documents", # oldABDocumentRootValue
+ 93, 93, # user id, group id
+ ),
+ ( # expected return values
+ "/Volumes/new/Library/Server/Calendar and Contacts",
+ "/Library/Server/Calendar and Contacts",
+ "/Volumes/External/CalendarServer/Documents",
+ "/Volumes/External/CalendarServer/Data"
+ ),
+ [
+ ('ditto', '/Volumes/old/Library/AddressBookServer/Documents/addressbooks', '/Volumes/External/CalendarServer/Documents/addressbooks'),
+ ('chown-recursive', '/Volumes/External/CalendarServer/Documents/addressbooks', 93, 93),
+ ('chown', '/Volumes/new/Library/Server/Calendar and Contacts', 93, 93),
+ ]
+ ),
+
+ (
+ "Lion -> Lion Migration, all in default locations",
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/old/Library/Server/Calendar and Contacts/Documents/" : True,
+ "/Volumes/old/Library/Server/Calendar and Contacts/Data/" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts/" : True,
+ },
+ ( # args
+ "/Volumes/old", # sourceRoot
+ "/Volumes/new", # targetRoot
+ "/Library/Server/Calendar and Contacts", # oldServerRootValue
+ "Documents", # oldCalDocumentRootValue
+ "Data", # oldCalDataRootValue
+ None, # oldABDocumentRootValue
+ 93, 93, # user id, group id
+ ),
+ ( # expected return values
+ "/Volumes/new/Library/Server/Calendar and Contacts",
+ "/Library/Server/Calendar and Contacts",
+ "Documents",
+ "Data"
+ ),
+ [
+ ('ditto', '/Volumes/old/Library/Server/Calendar and Contacts/Documents', '/Volumes/new/Library/Server/Calendar and Contacts/Documents'),
+ ('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts/Documents', 93, 93),
+ ('ditto', '/Volumes/old/Library/Server/Calendar and Contacts/Data', '/Volumes/new/Library/Server/Calendar and Contacts/Data'),
+ ('chown-recursive', '/Volumes/new/Library/Server/Calendar and Contacts/Data', 93, 93),
+ ('chown', '/Volumes/new/Library/Server/Calendar and Contacts', 93, 93),
+ ]
+ ),
+
+ (
+ "Lion -> Lion Migration, external ServerRoot with relative DocumentRoot and DataRoot",
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Volumes/External/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/External/Library/Server/Calendar and Contacts/Documents/" : True,
+ "/Volumes/External/Library/Server/Calendar and Contacts/Data/" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts/" : True,
+ },
+ ( # args
+ "/Volumes/old", # sourceRoot
+ "/Volumes/new", # targetRoot
+ "/Volumes/External/Library/Server/Calendar and Contacts", # oldServerRootValue
+ "Documents", # oldCalDocumentRootValue
+ "Data", # oldCalDataRootValue
+ None, # oldABDocumentRootValue
+ 93, 93, # user id, group id
+ ),
+ ( # expected return values
+ "/Volumes/External/Library/Server/Calendar and Contacts",
+ "/Volumes/External/Library/Server/Calendar and Contacts",
+ "Documents",
+ "Data"
+ ),
+ [
+ ('chown', '/Volumes/External/Library/Server/Calendar and Contacts', 93, 93),
+ ]
+ ),
+
+
+ (
+ "Lion -> Lion Migration, external ServerRoot with absolute external DocumentRoot and internal DataRoot",
+ {
+ "/Volumes/old/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Volumes/External/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>/Volumes/External/CalendarDocuments/</string>
+ <key>DataRoot</key>
+ <string>/CalendarData</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+ "/Volumes/new/private/etc/caldavd/caldavd.plist" : """
+ <plist version="1.0">
+ <dict>
+ <key>ServerRoot</key>
+ <string>/Library/Server/Calendar and Contacts</string>
+ <key>DocumentRoot</key>
+ <string>Documents</string>
+ <key>DataRoot</key>
+ <string>Data</string>
+ <key>UserName</key>
+ <string>calendar</string>
+ <key>GroupName</key>
+ <string>calendar</string>
+ </dict>
+ </plist>
+ """,
+
+ "/Volumes/External/Library/Server/Calendar and Contacts/" : True,
+ "/Volumes/External/CalendarDocuments/" : True,
+ "/Volumes/old/CalendarData" : True,
+ "/Volumes/new/Library/Server/Calendar and Contacts/" : True,
+ },
+ ( # args
+ "/Volumes/old", # sourceRoot
+ "/Volumes/new", # targetRoot
+ "/Volumes/External/Library/Server/Calendar and Contacts", # oldServerRootValue
+ "/Volumes/External/CalendarDocuments/", # oldCalDocumentRootValue
+ "/CalendarData", # oldCalDataRootValue
+ None, # oldABDocumentRootValue
+ 93, 93, # user id, group id
+ ),
+ ( # expected return values
+ "/Volumes/External/Library/Server/Calendar and Contacts",
+ "/Volumes/External/Library/Server/Calendar and Contacts",
+ "/Volumes/External/CalendarDocuments",
+ "Data" # Note that DataRoot was copied over to external volume
+ ),
+ [
+ ('ditto', '/Volumes/old/CalendarData', '/Volumes/External/Library/Server/Calendar and Contacts/Data'),
+ ('chown-recursive', '/Volumes/External/Library/Server/Calendar and Contacts/Data', 93, 93),
+ ('chown', '/Volumes/External/Library/Server/Calendar and Contacts', 93, 93),
+ ]
+ ),
+
+ (
+ "Empty migration",
+ { # no files
+ },
+ ( # args
+ "/Volumes/old", # sourceRoot
+ "/Volumes/new", # targetRoot
+ None, # oldServerRootValue
+ None, # oldCalDocumentRootValue
+ None, # oldCalDataRootValue
+ None, # oldABDocumentRootValue
+ -1, -1, # user id, group id
+ ),
+ ( # expected return values
+ "/Volumes/new/Library/Server/Calendar and Contacts",
+ "/Library/Server/Calendar and Contacts",
+ "Documents",
+ "Data"
+ ),
+ [ # no history
+ ]
+ ),
+
+ ]
+
+ for description, paths, args, expected, history in info:
+ # print "-=-=-=- %s -=-=-=-" % (description,)
+ accessor = StubDiskAccessor(paths)
+ actual = relocateData(*args, diskAccessor=accessor)
+ self.assertEquals(expected, actual)
+ self.assertEquals(history, accessor.history)
+
+
+ def test_stubDiskAccessor(self):
+
+ paths = {
+ "/a/b/c/d" : "foo",
+ "/a/b/c/e" : "bar",
+ "/x/y/z/" : True,
+ }
+ accessor = StubDiskAccessor(paths)
+
+ shouldExist = ["/a", "/a/", "/a/b", "/a/b/", "/a/b/c/d", "/x/y/z"]
+ shouldNotExist = ["/b", "/x/y/z/Z"]
+
+ for path in shouldExist:
+ self.assertTrue(accessor.exists(path))
+ for path in shouldNotExist:
+ self.assertFalse(accessor.exists(path))
+
+ for key, value in paths.iteritems():
+ if value is not True:
+ self.assertEquals(accessor.readFile(key), value)
+
+
+ def test_relativize(self):
+ """
+ Make sure child paths are made relative to their parent
+ """
+ info = [
+ (("/abc/", "/abc/def"), ("/abc", "def")),
+ (("/abc", "/abc/def"), ("/abc", "def")),
+ (("/abc", "/def"), ("/abc", "/def")),
+ ]
+ for args, expected in info:
+ self.assertEquals(expected, relativize(*args))
+
+
+class StubDiskAccessor(object):
+ """
+ A stub which allows testing without actually having real files
+ """
+
+ def __init__(self, paths):
+ self.paths = paths
+ self._fillInDirectories()
+
+ self.reset()
+
+ def _fillInDirectories(self):
+ for key in self.paths.keys():
+ parts = key.split("/")
+ for i in xrange(len(parts)):
+ path = "/".join(parts[:i])
+ self.paths[path] = True
+
+ def addPath(self, path, value):
+ self.paths[path] = value
+ self._fillInDirectories()
+
+ def reset(self):
+ self.history = []
+
+ def exists(self, path):
+ return self.paths.has_key(path.rstrip("/"))
+
+ def readFile(self, path):
+ return self.paths[path]
+
+ def mkdir(self, path):
+ self.history.append(("mkdir", path))
+ self.addPath(path, True)
+
+ def rename(self, before, after):
+ self.history.append(("rename", before, after))
+
+ def isfile(self, path):
+ # FIXME: probably want a better way to denote a directory than "True"
+ return self.exists(path) and self.paths[path] is not True
+
+ def symlink(self, orig, link):
+ self.history.append(("symlink", orig, link))
+
+ def chown(self, path, uid, gid, recursive=False):
+ self.history.append(("chown-recursive" if recursive else "chown", path, uid, gid))
+
+ def walk(self, path, followlinks=True):
+ yield [], [], []
+
+ def listdir(self, path):
+ return []
+
+ def ditto(self, src, dest):
+ self.history.append(("ditto", src, dest))
+ self.addPath(dest, True)
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110408/0f66da39/attachment-0001.html>
More information about the calendarserver-changes
mailing list