[CalendarServer-changes] [5969] CalendarServer/branches/users/wsanchez/deployment
source_changes at macosforge.org
source_changes at macosforge.org
Mon Aug 2 19:13:55 PDT 2010
Revision: 5969
http://trac.macosforge.org/projects/calendarserver/changeset/5969
Author: cdaboo at apple.com
Date: 2010-08-02 19:13:55 -0700 (Mon, 02 Aug 2010)
Log Message:
-----------
Allow importing of old proxy database into new DB types.
Modified Paths:
--------------
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/calendaruserproxy.py
Added Paths:
-----------
CalendarServer/branches/users/wsanchez/deployment/bin/caldav_load_proxydb
CalendarServer/branches/users/wsanchez/deployment/calendarserver/tools/loadproxydb.py
Added: CalendarServer/branches/users/wsanchez/deployment/bin/caldav_load_proxydb
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/bin/caldav_load_proxydb (rev 0)
+++ CalendarServer/branches/users/wsanchez/deployment/bin/caldav_load_proxydb 2010-08-03 02:13:55 UTC (rev 5969)
@@ -0,0 +1,40 @@
+#!/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()
+
+ if child.wait() == 0:
+ sys.path[0:0] = path.split(":")
+
+ print sys.path
+ from calendarserver.tools.loadproxydb import main
+ main()
Property changes on: CalendarServer/branches/users/wsanchez/deployment/bin/caldav_load_proxydb
___________________________________________________________________
Added: svn:executable
+ *
Added: CalendarServer/branches/users/wsanchez/deployment/calendarserver/tools/loadproxydb.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/calendarserver/tools/loadproxydb.py (rev 0)
+++ CalendarServer/branches/users/wsanchez/deployment/calendarserver/tools/loadproxydb.py 2010-08-03 02:13:55 UTC (rev 5969)
@@ -0,0 +1,161 @@
+#!/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.
+##
+
+from calendarserver.tools.util import loadConfig, getDirectory,\
+ autoDisableMemcached
+from getopt import getopt, GetoptError
+from grp import getgrnam
+from pwd import getpwnam
+from sys import stdout, stderr
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks
+from twisted.python.log import addObserver, removeObserver
+from twisted.python.util import switchUID
+from twistedcaldav.config import config, ConfigurationError
+from twistedcaldav.directory import calendaruserproxy
+from twistedcaldav.log import setLogLevelForNamespace
+import os
+import sys
+from twistedcaldav.directory.calendaruserproxy import ProxySqliteDB,\
+ OldCalendarUserProxyDatabase
+
+class UsageError (StandardError):
+ pass
+
+class StandardIOObserver (object):
+ """
+ Log observer that writes to standard I/O.
+ """
+ def emit(self, eventDict):
+ text = None
+
+ if eventDict["isError"]:
+ output = stderr
+ if "failure" in eventDict:
+ text = eventDict["failure"].getTraceback()
+ else:
+ output = stdout
+
+ if not text:
+ text = " ".join([str(m) for m in eventDict["message"]]) + "\n"
+
+ output.write(text)
+ output.flush()
+
+ def start(self):
+ addObserver(self.emit)
+
+ def stop(self):
+ removeObserver(self.emit)
+
+def usage(e=None):
+ if e:
+ print e
+ print ""
+
+ name = os.path.basename(sys.argv[0])
+ print "usage: %s [options] FILE" % (name,)
+ print ""
+ print "Populate an sqlite or PostgreSQL proxy database with values"
+ print "from an sqlite proxy database file."
+ print ""
+ print "FILE: Specify sqlite proxy database file path"
+ print ""
+ print "options:"
+ print " -h --help: print this help and exit"
+ print " -f --config: Specify caldavd.plist configuration path"
+
+ if e:
+ sys.exit(64)
+ else:
+ sys.exit(0)
+
+def main():
+ try:
+ (optargs, args) = getopt(
+ sys.argv[1:], "hf:", [
+ "config=",
+ "help",
+ ],
+ )
+ except GetoptError, e:
+ usage(e)
+
+ configFileName = None
+
+ for opt, arg in optargs:
+ if opt in ("-h", "--help"):
+ usage()
+
+ elif opt in ("-f", "--config"):
+ configFileName = arg
+
+
+ if len(args) != 1:
+ usage("Wrong number of arguments: %s" % (" ".join(args),))
+ oldDB = args[0]
+ if not os.path.exists(oldDB):
+ usage("Database does not exist: %s" % (oldDB,))
+
+ observer = StandardIOObserver()
+ observer.start()
+
+ #
+ # Get configuration
+ #
+ try:
+ loadConfig(configFileName)
+ setLogLevelForNamespace(None, "warn")
+
+ # 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)
+
+ config.directory = getDirectory()
+ autoDisableMemcached(config)
+ except ConfigurationError, e:
+ usage("Unable to start: %s" % (e,))
+
+ #
+ # Start the reactor
+ #
+ reactor.callLater(0, run, oldDB)
+ reactor.run()
+
+ at inlineCallbacks
+def run(oldDB):
+
+ try:
+ # Read in old records
+ olddb = OldCalendarUserProxyDatabase(oldDB)
+ items = olddb.exportAll()
+ print "Read %d items" % (len(items),)
+
+ # Write to new records
+ db = calendaruserproxy.ProxyDBService
+ yield db.importAll(items)
+
+ print "Added %d items" % (len(items),)
+ finally:
+ #
+ # Stop the reactor
+ #
+ reactor.stop()
Property changes on: CalendarServer/branches/users/wsanchez/deployment/calendarserver/tools/loadproxydb.py
___________________________________________________________________
Added: svn:executable
+ *
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/calendaruserproxy.py 2010-08-02 22:54:55 UTC (rev 5968)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/calendaruserproxy.py 2010-08-03 02:13:55 UTC (rev 5969)
@@ -44,8 +44,10 @@
from twistedcaldav.resource import CalDAVComplianceMixIn
from twistedcaldav.directory.util import NotFilePath
from twistedcaldav.log import LoggingMixIn
+from twistedcaldav.sql import AbstractSQLDatabase
import itertools
+import os
import time
class PermissionsMixIn (ReadOnlyWritePropertiesResourceMixIn):
@@ -764,7 +766,19 @@
yield super(ProxyDB, self).clean()
+ @inlineCallbacks
+ def exportAll(self):
+
+ # Get all members and memberships from old DB
+ allItems = (yield self.query("select GROUPNAME, MEMBER from GROUPS"))
+ returnValue(allItems)
+ @inlineCallbacks
+ def importAll(self, items):
+
+ for group, member in items:
+ yield self._add_to_db_one(group, member)
+
ProxyDBService = None # Global proxyDB service
@@ -788,7 +802,244 @@
ADBAPIPostgreSQLMixin.__init__(self, )
ProxyDB.__init__(self, "Proxies", "pgdb", (), host=host, database=database, user=user, password=password)
+class OldCalendarUserProxyDatabase(AbstractSQLDatabase):
+ """
+ A database to maintain calendar user proxy group memberships.
+ SCHEMA:
+
+ Group Database:
+
+ ROW: GROUPNAME, MEMBER
+
+ """
+
+ dbType = "CALENDARUSERPROXY"
+ dbFilename = "calendaruserproxy.sqlite"
+ dbFormatVersion = "4"
+
+ class ProxyDBMemcacher(Memcacher):
+
+ def setMembers(self, guid, members):
+ return self.set("members:%s" % (guid,), str(",".join(members)))
+
+ def setMemberships(self, guid, memberships):
+ return self.set("memberships:%s" % (guid,), str(",".join(memberships)))
+
+ def getMembers(self, guid):
+ def _value(value):
+ if value:
+ return set(value.split(","))
+ elif value is None:
+ return None
+ else:
+ return set()
+ d = self.get("members:%s" % (guid,))
+ d.addCallback(_value)
+ return d
+
+ def getMemberships(self, guid):
+ def _value(value):
+ if value:
+ return set(value.split(","))
+ elif value is None:
+ return None
+ else:
+ return set()
+ d = self.get("memberships:%s" % (guid,))
+ d.addCallback(_value)
+ return d
+
+ def deleteMember(self, guid):
+ return self.delete("members:%s" % (guid,))
+
+ def deleteMembership(self, guid):
+ return self.delete("memberships:%s" % (guid,))
+
+ def __init__(self, path):
+ super(OldCalendarUserProxyDatabase, self).__init__(path, True)
+
+ self._memcacher = OldCalendarUserProxyDatabase.ProxyDBMemcacher("proxyDB")
+
+ @inlineCallbacks
+ def setGroupMembers(self, principalUID, members):
+ """
+ Add a group membership record.
+
+ @param principalUID: the UID of the group principal to add.
+ @param members: a list UIDs of principals that are members of this group.
+ """
+
+ # Get current members before we change them
+ current_members = yield self.getMembers(principalUID)
+ if current_members is None:
+ current_members = ()
+ current_members = set(current_members)
+
+ # Remove what is there, then add it back.
+ self._delete_from_db(principalUID)
+ self._add_to_db(principalUID, members)
+ self._db_commit()
+
+ # Update cache
+ update_members = set(members)
+
+ remove_members = current_members.difference(update_members)
+ add_members = update_members.difference(current_members)
+ for member in itertools.chain(remove_members, add_members,):
+ _ignore = yield self._memcacher.deleteMembership(member)
+ _ignore = yield self._memcacher.deleteMember(principalUID)
+
+ @inlineCallbacks
+ def removeGroup(self, principalUID):
+ """
+ Remove a group membership record.
+
+ @param principalUID: the UID of the group principal to remove.
+ """
+
+ self._delete_from_db(principalUID)
+ self._db_commit()
+
+ # Update cache
+ members = yield self.getMembers(principalUID)
+ if members:
+ for member in members:
+ yield self._memcacher.deleteMembership(member)
+ yield self._memcacher.deleteMember(principalUID)
+
+ @inlineCallbacks
+ def getMembers(self, principalUID):
+ """
+ Return the list of group member UIDs for the specified principal.
+
+ @return: a deferred returning a C{set} of members.
+ """
+
+ def _members():
+ members = set()
+ for row in self._db_execute("select MEMBER from GROUPS where GROUPNAME = :1", principalUID):
+ members.add(row[0])
+ return members
+
+ # Pull from cache
+ result = yield self._memcacher.getMembers(principalUID)
+ if result is None:
+ result = _members()
+ yield self._memcacher.setMembers(principalUID, result)
+ returnValue(result)
+
+ @inlineCallbacks
+ def getMemberships(self, principalUID):
+ """
+ Return the list of group principal UIDs the specified principal is a member of.
+
+ @return: a deferred returning a C{set} of memberships.
+ """
+
+ def _members():
+ members = set()
+ for row in self._db_execute("select GROUPNAME from GROUPS where MEMBER = :1", principalUID):
+ members.add(row[0])
+ return members
+
+ # Pull from cache
+ result = yield self._memcacher.getMemberships(principalUID)
+ if result is None:
+ result = _members()
+ yield self._memcacher.setMemberships(principalUID, result)
+ returnValue(result)
+
+ def exportAll(self):
+
+ # Get all members and memberships from old DB
+ return tuple(self._db_execute("select GROUPNAME, MEMBER from GROUPS"))
+
+ def _add_to_db(self, principalUID, members):
+ """
+ Insert the specified entry into the database.
+
+ @param principalUID: the UID of the group principal to add.
+ @param members: a list of UIDs or principals that are members of this group.
+ """
+ for member in members:
+ self._db_execute(
+ """
+ insert into GROUPS (GROUPNAME, MEMBER)
+ values (:1, :2)
+ """, principalUID, member
+ )
+
+ def _delete_from_db(self, principalUID):
+ """
+ Deletes the specified entry from the database.
+
+ @param principalUID: the UID of the group principal to remove.
+ """
+ self._db_execute("delete from GROUPS where GROUPNAME = :1", principalUID)
+
+ def _db_version(self):
+ """
+ @return: the schema version assigned to this index.
+ """
+ return OldCalendarUserProxyDatabase.dbFormatVersion
+
+ def _db_type(self):
+ """
+ @return: the collection type assigned to this index.
+ """
+ return OldCalendarUserProxyDatabase.dbType
+
+ def _db_init_data_tables(self, q):
+ """
+ Initialise the underlying database tables.
+ @param q: a database cursor to use.
+ """
+
+ #
+ # GROUPS table
+ #
+ q.execute(
+ """
+ create table GROUPS (
+ GROUPNAME text,
+ MEMBER text
+ )
+ """
+ )
+ q.execute(
+ """
+ create index GROUPNAMES on GROUPS (GROUPNAME)
+ """
+ )
+ q.execute(
+ """
+ create index MEMBERS on GROUPS (MEMBER)
+ """
+ )
+
+ def _db_upgrade_data_tables(self, q, old_version):
+ """
+ Upgrade the data from an older version of the DB.
+ @param q: a database cursor to use.
+ @param old_version: existing DB's version number
+ @type old_version: str
+ """
+
+ # Add index if old version is less than "4"
+ if int(old_version) < 4:
+ q.execute(
+ """
+ create index GROUPNAMES on GROUPS (GROUPNAME)
+ """
+ )
+ q.execute(
+ """
+ create index MEMBERS on GROUPS (MEMBER)
+ """
+ )
+
+
##
# Utilities
##
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100802/8ba05768/attachment-0001.html>
More information about the calendarserver-changes
mailing list