[CalendarServer-changes] [2645] CalendarServer/branches/sqlpropstore-2629
source_changes at macosforge.org
source_changes at macosforge.org
Mon Jun 30 14:12:04 PDT 2008
Revision: 2645
http://trac.macosforge.org/projects/calendarserver/changeset/2645
Author: cdaboo at apple.com
Date: 2008-06-30 14:12:03 -0700 (Mon, 30 Jun 2008)
Log Message:
-----------
Add mechanism to upgrade xattrs->sqlite properties triggered by an explicit -U/--upgrade
command line option. This also merges in the code that does proxy-db, principal hierarchy
upgrade/clean-up.
Modified Paths:
--------------
CalendarServer/branches/sqlpropstore-2629/bin/caldavd
CalendarServer/branches/sqlpropstore-2629/run
CalendarServer/branches/sqlpropstore-2629/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/branches/sqlpropstore-2629/twistedcaldav/tap.py
CalendarServer/branches/sqlpropstore-2629/twistedcaldav/test/test_tap.py
Added Paths:
-----------
CalendarServer/branches/sqlpropstore-2629/twistedcaldav/test/test_upgrade.py
CalendarServer/branches/sqlpropstore-2629/twistedcaldav/upgrade.py
Modified: CalendarServer/branches/sqlpropstore-2629/bin/caldavd
===================================================================
--- CalendarServer/branches/sqlpropstore-2629/bin/caldavd 2008-06-30 18:12:25 UTC (rev 2644)
+++ CalendarServer/branches/sqlpropstore-2629/bin/caldavd 2008-06-30 21:12:03 UTC (rev 2645)
@@ -84,6 +84,7 @@
echo "Options:";
echo " -h Print this help and exit";
echo " -X Do not daemonize";
+ echo " -U Upgrade Only";
echo " -u User name to run as";
echo " -g Group name to run as";
echo " -f Configuration file to read";
Modified: CalendarServer/branches/sqlpropstore-2629/run
===================================================================
--- CalendarServer/branches/sqlpropstore-2629/run 2008-06-30 18:12:25 UTC (rev 2644)
+++ CalendarServer/branches/sqlpropstore-2629/run 2008-06-30 21:12:03 UTC (rev 2645)
@@ -43,6 +43,7 @@
read_key="";
profile="";
reactor="";
+ upgrade="";
usage ()
{
@@ -52,13 +53,13 @@
echo "Usage: ${program} [-hvgsfnpdkrR] [-K key] [-iI dst] [-t type] [-S statsdirectory] [-P plugin]";
echo "Options:";
- echo " -h Print this help and exit";
- echo " -v Be verbose";
- echo " -g Get dependencies only; don't run setup or run the server.";
- echo " -s Run setup only; don't run server";
- echo " -f Force setup to run";
- echo " -n Do not run setup";
- echo " -p Print PYTHONPATH value for server and exit";
+ echo " -h Print this help and exit";
+ echo " -v Be verbose";
+ echo " -g Get dependencies only; don't run setup or run the server";
+ echo " -s Run setup only; don't run server";
+ echo " -f Force setup to run";
+ echo " -n Do not run setup";
+ echo " -p Print PYTHONPATH value for server and exit";
echo " -d Run caldavd as a daemon";
echo " -k Stop caldavd";
echo " -r Restart caldavd";
@@ -67,8 +68,9 @@
echo " -I Perform a home install into dst; implies -s";
echo " -t Select the server process type (Master, Slave or Combined) [${service_type}]";
echo " -S Write a pstats object for each process to the given directory when the server is stopped.";
- echo " -P Select the twistd plugin name [${plugin_name}]";
+ echo " -P Select the twistd plugin name [${plugin_name}]";
echo " -R Twisted Reactor plugin to execute [${reactor}]";
+ echo " -U Upgrade the server's data only when running it";
if [ "${1-}" == "-" ]; then return 0; fi;
exit 64;
@@ -85,6 +87,7 @@
'd') daemonize=""; ;;
'P') plugin_name="${OPTARG}"; ;;
'R') reactor="-R ${OPTARG}"; ;;
+ 'U') upgrade="-U"; ;;
't') service_type="${OPTARG}"; ;;
'K') read_key="${OPTARG}"; ;;
'S') profile="-p ${OPTARG}"; ;;
@@ -251,7 +254,8 @@
-T "${twisted}/bin/twistd" \
-P "${plugin_name}" \
-t "${service_type}" \
- ${reactor} \
+ ${reactor} \
+ ${upgrade} \
${profile};
cd /;
fi;
Modified: CalendarServer/branches/sqlpropstore-2629/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/sqlpropstore-2629/twistedcaldav/directory/calendaruserproxy.py 2008-06-30 18:12:25 UTC (rev 2644)
+++ CalendarServer/branches/sqlpropstore-2629/twistedcaldav/directory/calendaruserproxy.py 2008-06-30 21:12:03 UTC (rev 2645)
@@ -336,6 +336,7 @@
dbType = "CALENDARUSERPROXY"
dbFilename = "calendaruserproxy.sqlite"
+ dbOldFilename = db_prefix + "calendaruserproxy"
dbFormatVersion = "4"
class ProxyDBMemcacher(Memcacher):
Modified: CalendarServer/branches/sqlpropstore-2629/twistedcaldav/tap.py
===================================================================
--- CalendarServer/branches/sqlpropstore-2629/twistedcaldav/tap.py 2008-06-30 18:12:25 UTC (rev 2644)
+++ CalendarServer/branches/sqlpropstore-2629/twistedcaldav/tap.py 2008-06-30 21:12:03 UTC (rev 2645)
@@ -54,6 +54,7 @@
from twistedcaldav.static import CalendarHomeProvisioningFile
from twistedcaldav.static import TimezoneServiceFile
from twistedcaldav.timezones import TimezoneCache
+from twistedcaldav.upgrade import UpgradeTheServer, UpgradeError
from twistedcaldav import pdmonster
from twistedcaldav import memcachepool
@@ -80,9 +81,12 @@
class CalDAVOptions(Options):
- optParameters = [[
- "config", "f", "/etc/caldavd/caldavd.plist", "Path to configuration file."
- ]]
+ optFlags = [
+ ["upgradeonly", "U", "Do server upgrade only."],
+ ]
+ optParameters = [
+ ["config", "f", "/etc/caldavd/caldavd.plist", "Path to configuration file."],
+ ]
zsh_actions = {"config" : "_files -g '*.plist'"}
@@ -708,6 +712,13 @@
makeService_Single = makeService_Slave
def makeService(self, options):
+
+ # Check for upgrade only
+ if options.get('upgradeonly', False):
+ # Now do any on disk upgrades we might need.
+ UpgradeTheServer.doUpgrade()
+ raise UpgradeError("Upgrade Completed Successfully")
+
serverType = config.ProcessType
serviceMethod = getattr(self, "makeService_%s" % (serverType,), None)
Modified: CalendarServer/branches/sqlpropstore-2629/twistedcaldav/test/test_tap.py
===================================================================
--- CalendarServer/branches/sqlpropstore-2629/twistedcaldav/test/test_tap.py 2008-06-30 18:12:25 UTC (rev 2644)
+++ CalendarServer/branches/sqlpropstore-2629/twistedcaldav/test/test_tap.py 2008-06-30 21:12:03 UTC (rev 2645)
@@ -39,6 +39,7 @@
from twistedcaldav.directory.sudo import SudoDirectoryService
from twistedcaldav.directory.directory import UnknownRecordTypeError
+from twistedcaldav.upgrade import UpgradeError
class TestCalDAVOptions(CalDAVOptions):
"""
@@ -237,6 +238,30 @@
return service.services[0].args[1].protocolArgs['requestFactory']
+class UpgradeTests(BaseServiceMakerTests):
+ """
+ Test the supgrade behavior
+ """
+
+ def test_upgrade_U(self):
+ """
+ Test the default options of the dispatching makeService
+ """
+
+ self.options.parseOptions(['-f', self.configFile, "-U"])
+
+ self.assertRaises(UpgradeError, CalDAVServiceMaker().makeService, self.options)
+
+ def test_upgrade_dashdash(self):
+ """
+ Test the default options of the dispatching makeService
+ """
+
+ self.options.parseOptions(['-f', self.configFile, "--upgrade"])
+
+ self.assertRaises(UpgradeError, CalDAVServiceMaker().makeService, self.options)
+
+
class CalDAVServiceMakerTests(BaseServiceMakerTests):
"""
Test the service maker's behavior
Added: CalendarServer/branches/sqlpropstore-2629/twistedcaldav/test/test_upgrade.py
===================================================================
--- CalendarServer/branches/sqlpropstore-2629/twistedcaldav/test/test_upgrade.py (rev 0)
+++ CalendarServer/branches/sqlpropstore-2629/twistedcaldav/test/test_upgrade.py 2008-06-30 21:12:03 UTC (rev 2645)
@@ -0,0 +1,320 @@
+##
+# Copyright (c) 2005-2007 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 twisted.web2.dav import davxml
+from twisted.web2.dav.resource import TwistedGETContentMD5
+from twistedcaldav import caldavxml, customxml
+from twistedcaldav.config import config
+from twistedcaldav.directory.calendaruserproxy import CalendarUserProxyDatabase
+from twistedcaldav.sqlprops import SQLPropertiesDatabase
+from twistedcaldav.static import CalDAVFile, CalendarHomeFile
+from twistedcaldav.upgrade import UpgradeXattrsToSqlite, UpgradePrincipalCollectionInMemory, UpgradeError
+import os
+import twistedcaldav.test.util
+import xattr
+
+class ProxyDBUpgradeTests(twistedcaldav.test.util.TestCase):
+
+ def setUpInitialStates(self):
+
+ self.setUpOldDocRoot()
+ self.setUpOldDocRootWithoutDB()
+ self.setUpNewDocRoot()
+
+ self.setUpNewDataRoot()
+ self.setUpDataRootWithProxyDB()
+
+ def setUpOldDocRoot(self):
+
+ # Set up doc root
+ self.olddocroot = self.mktemp()
+ os.mkdir(self.olddocroot)
+
+ principals = os.path.join(self.olddocroot, "principals")
+ os.mkdir(principals)
+ os.mkdir(os.path.join(principals, "__uids__"))
+ os.mkdir(os.path.join(principals, "users"))
+ os.mkdir(os.path.join(principals, "groups"))
+ os.mkdir(os.path.join(principals, "locations"))
+ os.mkdir(os.path.join(principals, "resources"))
+ os.mkdir(os.path.join(principals, "sudoers"))
+ os.mkdir(os.path.join(self.olddocroot, "calendars"))
+
+ proxyDB = CalendarUserProxyDatabase(principals)
+ proxyDB._db()
+ os.rename(
+ os.path.join(principals, CalendarUserProxyDatabase.dbFilename),
+ os.path.join(principals, CalendarUserProxyDatabase.dbOldFilename),
+ )
+
+ def setUpOldDocRootWithoutDB(self):
+
+ # Set up doc root
+ self.olddocrootnodb = self.mktemp()
+ os.mkdir(self.olddocrootnodb)
+
+ principals = os.path.join(self.olddocrootnodb, "principals")
+ os.mkdir(principals)
+ os.mkdir(os.path.join(principals, "__uids__"))
+ os.mkdir(os.path.join(principals, "users"))
+ os.mkdir(os.path.join(principals, "groups"))
+ os.mkdir(os.path.join(principals, "locations"))
+ os.mkdir(os.path.join(principals, "resources"))
+ os.mkdir(os.path.join(principals, "sudoers"))
+ os.mkdir(os.path.join(self.olddocrootnodb, "calendars"))
+
+ def setUpNewDocRoot(self):
+
+ # Set up doc root
+ self.newdocroot = self.mktemp()
+ os.mkdir(self.newdocroot)
+
+ os.mkdir(os.path.join(self.newdocroot, "calendars"))
+
+ def setUpNewDataRoot(self):
+
+ # Set up data root
+ self.newdataroot = self.mktemp()
+ os.mkdir(self.newdataroot)
+
+ def setUpDataRootWithProxyDB(self):
+
+ # Set up data root
+ self.existingdataroot = self.mktemp()
+ os.mkdir(self.existingdataroot)
+
+ proxyDB = CalendarUserProxyDatabase(self.existingdataroot)
+ proxyDB._db()
+
+ def test_normalUpgrade(self):
+ """
+ Test the behavior of normal upgrade from old server to new.
+ """
+
+ self.setUpInitialStates()
+
+ config.DocumentRoot = self.olddocroot
+ config.DataRoot = self.newdataroot
+
+ # Check pre-conditions
+ self.assertTrue(os.path.exists(os.path.join(config.DocumentRoot, "principals")))
+ self.assertTrue(os.path.isdir(os.path.join(config.DocumentRoot, "principals")))
+ self.assertTrue(os.path.exists(os.path.join(config.DocumentRoot, "principals", CalendarUserProxyDatabase.dbOldFilename)))
+ self.assertFalse(os.path.exists(os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)))
+
+ UpgradePrincipalCollectionInMemory.doUpgrade()
+
+ # Check post-conditions
+ self.assertFalse(os.path.exists(os.path.join(config.DocumentRoot, "principals",)))
+ self.assertTrue(os.path.exists(os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)))
+
+ def test_partialUpgrade(self):
+ """
+ Test the behavior of a partial upgrade (one where /principals exists but the proxy db does not) from old server to new.
+ """
+
+ self.setUpInitialStates()
+
+ config.DocumentRoot = self.olddocrootnodb
+ config.DataRoot = self.newdataroot
+
+ # Check pre-conditions
+ self.assertTrue(os.path.exists(os.path.join(config.DocumentRoot, "principals")))
+ self.assertTrue(os.path.isdir(os.path.join(config.DocumentRoot, "principals")))
+ self.assertFalse(os.path.exists(os.path.join(config.DocumentRoot, "principals", CalendarUserProxyDatabase.dbOldFilename)))
+ self.assertFalse(os.path.exists(os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)))
+
+ UpgradePrincipalCollectionInMemory.doUpgrade()
+
+ # Check post-conditions
+ self.assertFalse(os.path.exists(os.path.join(config.DocumentRoot, "principals",)))
+ self.assertFalse(os.path.exists(os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)))
+
+ def test_noUpgrade(self):
+ """
+ Test the behavior of running on a new server (i.e. no upgrade needed).
+ """
+
+ self.setUpInitialStates()
+
+ config.DocumentRoot = self.newdocroot
+ config.DataRoot = self.existingdataroot
+
+ # Check pre-conditions
+ self.assertFalse(os.path.exists(os.path.join(config.DocumentRoot, "principals")))
+ self.assertTrue(os.path.exists(os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)))
+
+ UpgradePrincipalCollectionInMemory.doUpgrade()
+
+ # Check post-conditions
+ self.assertFalse(os.path.exists(os.path.join(config.DocumentRoot, "principals",)))
+ self.assertTrue(os.path.exists(os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)))
+
+ def test_failedUpgrade(self):
+ """
+ Test the behavior of failed upgrade from old server to new where proxy DB exists in two locations.
+ """
+
+ self.setUpInitialStates()
+
+ config.DocumentRoot = self.olddocroot
+ config.DataRoot = self.existingdataroot
+
+ # Check pre-conditions
+ self.assertTrue(os.path.exists(os.path.join(config.DocumentRoot, "principals")))
+ self.assertTrue(os.path.isdir(os.path.join(config.DocumentRoot, "principals")))
+ self.assertTrue(os.path.exists(os.path.join(config.DocumentRoot, "principals", CalendarUserProxyDatabase.dbOldFilename)))
+ self.assertTrue(os.path.exists(os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)))
+
+ self.assertRaises(UpgradeError, UpgradePrincipalCollectionInMemory.doUpgrade)
+
+ # Check post-conditions
+ self.assertTrue(os.path.exists(os.path.join(config.DocumentRoot, "principals")))
+ self.assertTrue(os.path.isdir(os.path.join(config.DocumentRoot, "principals")))
+ self.assertTrue(os.path.exists(os.path.join(config.DocumentRoot, "principals", CalendarUserProxyDatabase.dbOldFilename)))
+ self.assertTrue(os.path.exists(os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)))
+
+class UpgradeSQLProps (twistedcaldav.test.util.TestCase):
+ """
+ SQL properties tests
+ """
+ data_dir = os.path.join(os.path.dirname(__file__), "data")
+
+ props = (
+ davxml.DisplayName.fromString("My Name"),
+ davxml.ACL(
+ davxml.ACE(
+ davxml.Principal(davxml.Authenticated()),
+ davxml.Grant(davxml.Privilege(davxml.Read())),
+ davxml.Protected(),
+ ),
+ ),
+ caldavxml.CalendarDescription.fromString("My Calendar"),
+ )
+
+ def setUp(self):
+
+ super(UpgradeSQLProps, self).setUp()
+
+ # First setup an xattr document root
+ self._setUpTestDocuments()
+
+ # Set to use sqlite prop store
+ config.PropertyStore = "SQL"
+ config.updatePropertyStore()
+
+ # Do the upgrade
+ UpgradeXattrsToSqlite.doUpgrade()
+
+ def _setUpTestDocuments(self):
+
+ config.PropertyStore = "xattr"
+ config.updatePropertyStore()
+
+ self.xattr_root, _ignore_url = self.mkdtemp("docs")
+ config.DocumentRoot = self.xattr_root
+ os.mkdir(os.path.join(self.xattr_root, "calendars"))
+ os.mkdir(os.path.join(self.xattr_root, "calendars", "__uids__"))
+
+ os.mkdir(os.path.join(self.xattr_root, "calendars", "__uids__", "12"))
+ os.mkdir(os.path.join(self.xattr_root, "calendars", "__uids__", "12", "34"))
+ self.user_home = os.path.join(self.xattr_root, "calendars", "__uids__", "12", "34", "12345-6789-10")
+ os.mkdir(self.user_home)
+
+ self.user_calendar = os.path.join(self.user_home, "calendar")
+ os.mkdir(self.user_calendar)
+
+ self.user_event = os.path.join(self.user_calendar, "12345.ics")
+ f = open(self.user_event, "w")
+ f.close()
+
+ # xattrs on user home
+ resource = CalDAVFile(self.user_home)
+ resource.deadProperties().set(davxml.QuotaAvailableBytes.fromString("1000"))
+ resource.deadProperties().set(davxml.QuotaUsedBytes.fromString("500"))
+
+ # xattrs on user calendar
+ resource = CalDAVFile(self.user_calendar)
+ resource.deadProperties().set(davxml.ResourceType.calendar) #@UndefinedVariable
+ resource.deadProperties().set(davxml.DisplayName.fromString("A Calendar"))
+ resource.deadProperties().set(caldavxml.CalendarDescription.fromString("A Calendar"))
+ resource.deadProperties().set(customxml.GETCTag.fromString("2008-06-30T13:00:00-123456"))
+
+ # xattr on calendar resource
+ resource = CalDAVFile(self.user_event)
+ resource.deadProperties().set(davxml.GETContentType.fromString("text/calendar"))
+ resource.deadProperties().set(TwistedGETContentMD5.fromString("ABCDEF-12345"))
+
+ def _testProperty(self, path, prop, description = ""):
+
+ if path == self.user_home:
+ class DummyCalendarHomeFile(CalendarHomeFile):
+
+ def __init__(self, path):
+ CalDAVFile.__init__(self, path)
+
+ resource = DummyCalendarHomeFile(path)
+ else:
+ resource = CalDAVFile(path)
+
+ self.assertTrue(resource.deadProperties().contains(prop.qname()),
+ msg="Could not find property %s %r." % (description, prop,))
+ self.assertTrue(resource.deadProperties().get(prop.qname()) == prop,
+ msg="Could not get property %s %r." % (description, prop,))
+
+ def _testNoXattrs(self, path):
+
+ x = xattr.xattr(path)
+ self.assertTrue(len(x) == 0)
+
+ def test_root(self):
+ self.assertFalse(os.path.exists(os.path.join(self.xattr_root, SQLPropertiesDatabase.dbFilename)))
+ self._testNoXattrs(self.xattr_root)
+
+ def test_calendars(self):
+ self.assertFalse(os.path.exists(os.path.join(self.xattr_root, "calendars", SQLPropertiesDatabase.dbFilename)))
+ self._testNoXattrs(os.path.join(self.xattr_root, "calendars"))
+
+ def test_uids(self):
+ self.assertFalse(os.path.exists(os.path.join(self.xattr_root, "calendars", "__uids__", SQLPropertiesDatabase.dbFilename)))
+ self._testNoXattrs(os.path.join(self.xattr_root, "calendars", "__uids__"))
+
+ def test_hashed(self):
+ self.assertFalse(os.path.exists(os.path.join(self.xattr_root, "calendars", "__uids__", "12", SQLPropertiesDatabase.dbFilename)))
+ self._testNoXattrs(os.path.join(self.xattr_root, "calendars", "__uids__", "12"))
+ self.assertFalse(os.path.exists(os.path.join(self.xattr_root, "calendars", "__uids__", "12", "34", SQLPropertiesDatabase.dbFilename)))
+ self._testNoXattrs(os.path.join(self.xattr_root, "calendars", "__uids__", "12", "34"))
+
+ def test_user_home(self):
+ self.assertTrue(os.path.exists(os.path.join(self.user_home, SQLPropertiesDatabase.dbFilename)))
+ self._testProperty(self.user_home, davxml.QuotaAvailableBytes.fromString("1000"), "on user home") #@UndefinedVariable
+ self._testProperty(self.user_home, davxml.QuotaUsedBytes.fromString("500"), "on user home")
+ self._testNoXattrs(self.user_home)
+
+ def test_user_calendar(self):
+ self.assertTrue(os.path.exists(os.path.join(self.user_home, SQLPropertiesDatabase.dbFilename)))
+ self.assertTrue(os.path.exists(os.path.join(self.user_calendar, SQLPropertiesDatabase.dbFilename)))
+ self._testProperty(self.user_calendar, davxml.ResourceType.calendar, "on user calendar") #@UndefinedVariable
+ self._testProperty(self.user_calendar, davxml.DisplayName.fromString("A Calendar"), "on user calendar")
+ self._testProperty(self.user_calendar, caldavxml.CalendarDescription.fromString("A Calendar"), "on user calendar")
+ self._testProperty(self.user_calendar, customxml.GETCTag.fromString("2008-06-30T13:00:00-123456"), "on user calendar")
+ self._testNoXattrs(self.user_calendar)
+
+ def test_user_event(self):
+ self.assertTrue(os.path.exists(os.path.join(self.user_calendar, SQLPropertiesDatabase.dbFilename)))
+ self._testProperty(self.user_event, davxml.GETContentType.fromString("text/calendar"), "on user event")
+ self._testProperty(self.user_event, TwistedGETContentMD5.fromString("ABCDEF-12345"), "on user event")
+ self._testNoXattrs(self.user_event)
Added: CalendarServer/branches/sqlpropstore-2629/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/branches/sqlpropstore-2629/twistedcaldav/upgrade.py (rev 0)
+++ CalendarServer/branches/sqlpropstore-2629/twistedcaldav/upgrade.py 2008-06-30 21:12:03 UTC (rev 2645)
@@ -0,0 +1,145 @@
+##
+# Copyright (c) 2006-2007 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 twistedcaldav.config import config
+from twisted.python.filepath import FilePath
+from twisted.web2.dav.xattrprops import xattrPropertyStore
+from twistedcaldav.sqlprops import sqlPropertyStore
+from twistedcaldav.log import Logger
+from twisted.web2.dav.fileop import rmdir
+from twistedcaldav.directory.calendaruserproxy import CalendarUserProxyDatabase
+import os
+
+log = Logger()
+
+class UpgradeTheServer(object):
+
+ @staticmethod
+ def doUpgrade():
+
+ UpgradePrincipalCollectionInMemory.doUpgrade()
+ UpgradeXattrsToSqlite.doUpgrade()
+
+class UpgradePrincipalCollectionInMemory(object):
+
+ @classmethod
+ def doUpgrade(cls):
+
+ # Look for the /principals/ directory on disk
+ old_principals = os.path.join(config.DocumentRoot, "principals")
+ if os.path.exists(old_principals):
+ # First move the proxy database and rename it
+ cls._doProxyDatabaseMoveUpgrade()
+
+ # Now delete the on disk representation of principals
+ rmdir(old_principals)
+ log.info(
+ "Removed the old principal directory at '%s'."
+ % (old_principals,)
+ )
+
+ @classmethod
+ def _doProxyDatabaseMoveUpgrade(cls):
+
+ # See if the old DB is present
+ old_db_path = os.path.join(config.DocumentRoot, "principals", CalendarUserProxyDatabase.dbOldFilename)
+ if not os.path.exists(old_db_path):
+ # Nothing to be done
+ return
+
+ # See if the new one is already present
+ new_db_path = os.path.join(config.DataRoot, CalendarUserProxyDatabase.dbFilename)
+ if os.path.exists(new_db_path):
+ # We have a problem - both the old and new ones exist. Stop the server from starting
+ # up and alert the admin to this condition
+ raise UpgradeError(
+ "Upgrade Error: unable to move the old calendar user proxy database at '%s' to '%s' because the new database already exists."
+ % (old_db_path, new_db_path,)
+ )
+
+ # Now move the old one to the new location
+ try:
+ os.rename(old_db_path, new_db_path)
+ except Exception, e:
+ raise UpgradeError(
+ "Upgrade Error: unable to move the old calendar user proxy database at '%s' to '%s' due to %s."
+ % (old_db_path, new_db_path, str(e))
+ )
+
+ log.info(
+ "Moved the calendar user proxy database from '%s' to '%s'."
+ % (old_db_path, new_db_path,)
+ )
+
+class UpgradeXattrsToSqlite(object):
+
+ @classmethod
+ def doUpgrade(cls):
+ """
+ Upgrade xattr properties to sqlite properties.
+ """
+
+ if config.PropertyStore == "SQL":
+ log.info("Doing xattr->sqlite property upgrade")
+ docroot = config.DocumentRoot
+ cls._upgradeItem(docroot, "")
+
+ @classmethod
+ def _upgradeItem(cls, docroot, path):
+
+ # Upgrade the properties at this path first
+ cls._upgradeXAttrs(docroot, path)
+
+ fullpath = os.path.join(docroot, path)
+ if os.path.isdir(fullpath):
+ for child in os.listdir(fullpath):
+ if child[0] == '.':
+ continue
+ childpath = os.path.join(path, child)
+ cls._upgradeItem(docroot, childpath)
+
+ @classmethod
+ def _upgradeXAttrs(cls, docroot, path):
+
+ class DummyResource:
+
+ def __init__(self, path):
+ self.fp = FilePath(path)
+
+ def isCollection(self):
+ return self.fp.isdir()
+
+ log.debug("Doing xattr->sqlite property upgrade for: %s" % (path,))
+ resource = DummyResource(os.path.join(docroot, path))
+ xprops = xattrPropertyStore(resource)
+
+ # Detect some special cases for sql properties
+ root_resource = (len(path) == 0)
+ avoid_contention = path.startswith("calendars/__uids__/") and len(path.split("/")) == 5
+ sqlprops = sqlPropertyStore(resource, root_resource=root_resource, avoid_contention=avoid_contention)
+
+ for propname in list(xprops.list()):
+ try:
+ sqlprops.set(xprops.get(propname))
+ except Exception, e:
+ log.debug("Unable to upgrade property '%s' on '%s' because of %s" % (propname, path, e,))
+ xprops.delete(propname)
+
+
+class UpgradeError(RuntimeError):
+ """
+ Generic upgrade error.
+ """
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080630/115debac/attachment-0001.html
More information about the calendarserver-changes
mailing list