[CalendarServer-changes] [11410] CalendarServer/branches/users/glyph/launchd-wrapper
source_changes at macosforge.org
source_changes at macosforge.org
Wed Jun 26 00:56:42 PDT 2013
Revision: 11410
http://trac.calendarserver.org//changeset/11410
Author: glyph at apple.com
Date: 2013-06-26 00:56:42 -0700 (Wed, 26 Jun 2013)
Log Message:
-----------
Adds process type "Agent" -- an on-demand AMP service spawned by launchd, meant for servicing configuration commands
Modified Paths:
--------------
CalendarServer/branches/users/glyph/launchd-wrapper/bin/caldavd
CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tap/caldav.py
CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/gateway.py
CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/calendarserver.plist
CalendarServer/branches/users/glyph/launchd-wrapper/txdav/base/datastore/subpostgres.py
Added Paths:
-----------
CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/agent.py
CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/agent.plist
Modified: CalendarServer/branches/users/glyph/launchd-wrapper/bin/caldavd
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper/bin/caldavd 2013-06-26 07:56:16 UTC (rev 11409)
+++ CalendarServer/branches/users/glyph/launchd-wrapper/bin/caldavd 2013-06-26 07:56:42 UTC (rev 11410)
@@ -31,7 +31,7 @@
profile="";
twistd_reactor="";
child_reactor=""
-extra="-o FailIfUpgradeNeeded=False";
+extra="";
py_version ()
{
Modified: CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tap/caldav.py 2013-06-26 07:56:16 UTC (rev 11409)
+++ CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tap/caldav.py 2013-06-26 07:56:42 UTC (rev 11410)
@@ -105,6 +105,7 @@
from calendarserver.push.notifier import PushDistributor
from calendarserver.push.amppush import AMPPushMaster, AMPPushForwarder
from calendarserver.push.applepush import ApplePushNotifierService
+from calendarserver.tools.agent import makeAgentService
try:
from calendarserver.version import version
@@ -388,9 +389,10 @@
# Having CalDAV *and* CardDAV both disabled is an illegal configuration
# for a running server (but is fine for command-line utilities)
- if not config.EnableCalDAV and not config.EnableCardDAV:
- print("Neither EnableCalDAV nor EnableCardDAV are set to True.")
- sys.exit(1)
+ if config.ProcessType not in ["Agent", "Utility"]:
+ if not config.EnableCalDAV and not config.EnableCardDAV:
+ print("Neither EnableCalDAV nor EnableCardDAV are set to True.")
+ sys.exit(1)
uid, gid = None, None
@@ -1234,6 +1236,22 @@
return self.storageService(toolServiceCreator, None, uid=uid, gid=gid)
+ def makeService_Agent(self, options):
+ """
+ Create an agent service which listens for configuration requests
+ """
+
+ # Don't use memcached -- calendar server might take it away at any
+ # moment
+ config.Memcached.Pools.Default.ClientEnabled = False
+
+ def agentServiceCreator(pool, store, ignored):
+ return makeAgentService(store)
+
+ uid, gid = getSystemIDs(config.UserName, config.GroupName)
+ return self.storageService(agentServiceCreator, None, uid=uid, gid=gid)
+
+
def storageService(self, createMainService, logObserver, uid=None, gid=None):
"""
If necessary, create a service to be started used for storage; for
Added: CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/agent.py
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/agent.py (rev 0)
+++ CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/agent.py 2013-06-26 07:56:42 UTC (rev 11410)
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+
+##
+# Copyright (c) 2013 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 __future__ import print_function
+
+import cStringIO
+import socket
+from twext.python.plistlib import readPlistFromString, writePlistToString
+from calendarserver.tap.util import getRootResource
+from twisted.application.internet import StreamServerEndpointService
+from twisted.internet.endpoints import AdoptedStreamServerEndpoint
+from twisted.protocols import amp
+from twisted.internet.protocol import Factory
+from twisted.internet.defer import inlineCallbacks, returnValue
+
+# TODO, implement this:
+# from launchd import getLaunchdSocketFds
+
+# For the sample client, below:
+from twisted.internet import reactor
+from twisted.internet.protocol import ClientCreator
+
+from twext.python.log import Logger
+log = Logger()
+
+"""
+A service spawned on-demand by launchd, meant to handle configuration requests
+from Server.app. When a request comes in on the socket specified in the launchd
+agent.plist, launchd will run "caldavd -t Agent" which ends up creating this
+service. AMP protocol commands sent to this socket are passed to gateway.Runner.
+"""
+
+class GatewayAMPCommand(amp.Command):
+ """
+ A command to be executed by gateway.Runner
+ """
+ arguments = [('command', amp.String())]
+ response = [('result', amp.String())]
+
+
+class GatewayAMPProtocol(amp.AMP):
+ """
+ Passes commands to gateway.Runner and returns the results
+ """
+
+ def __init__(self, store, davRootResource, directory):
+ """
+ @param store: an already opened store
+ @param davRootResource: the root resource, required for principal
+ operations
+ @param directory: a directory service
+ """
+ amp.AMP.__init__(self)
+ self.store = store
+ self.davRootResource = davRootResource
+ self.directory = directory
+
+
+ @GatewayAMPCommand.responder
+ @inlineCallbacks
+ def gatewayCommandReceived(self, command):
+ """
+ Process a command via gateway.Runner
+
+ @param command: GatewayAMPCommand
+ @returns: a deferred returning a dict
+ """
+ command = readPlistFromString(command)
+ output = cStringIO.StringIO()
+ from calendarserver.tools.gateway import Runner
+ runner = Runner(self.davRootResource, self.directory, self.store,
+ [command], output=output)
+
+ try:
+ yield runner.run()
+ result = output.getvalue()
+ output.close()
+ except Exception as e:
+ error = {
+ "Error" : str(e),
+ }
+ result = writePlistToString(error)
+
+ output.close()
+ returnValue(dict(result=result))
+
+
+class GatewayAMPFactory(Factory):
+ """
+ Builds GatewayAMPProtocols
+ """
+ protocol = GatewayAMPProtocol
+
+ def __init__(self, store):
+ """
+ @param store: an already opened store
+ """
+ self.store = store
+ from twistedcaldav.config import config
+ self.davRootResource = getRootResource(config, self.store)
+ self.directory = self.davRootResource.getDirectory()
+
+ def buildProtocol(self, addr):
+ return GatewayAMPProtocol(self.store, self.davRootResource,
+ self.directory)
+
+
+def makeAgentService(store):
+ """
+ Returns a service which will process GatewayAMPCommands, using a socket
+ file descripter acquired by launchd
+
+ @param store: an already opened store
+ @returns: service
+ """
+ from twisted.internet import reactor
+
+ # TODO: remove this
+ def getLaunchdSocketFds():
+ return {}
+
+ # TODO: implement this
+ sockets = getLaunchdSocketFds()
+ fd = sockets["AgentSocket"][0]
+
+ # TODO: use UNIX socket
+ family = socket.AF_INET
+ endpoint = AdoptedStreamServerEndpoint(reactor, fd, family)
+ return StreamServerEndpointService(endpoint, GatewayAMPFactory(store))
+
+
+
+#
+# A test client
+#
+
+command = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>command</key>
+ <string>getLocationAndResourceList</string>
+</dict>
+</plist>"""
+
+def getList():
+ creator = ClientCreator(reactor, amp.AMP)
+ # TODO: use UNIX socket
+ d = creator.connectTCP('127.0.0.1', 12345)
+
+ def connected(ampProto):
+ return ampProto.callRemote(GatewayAMPCommand, command=command)
+ d.addCallback(connected)
+
+ def resulted(result):
+ return result['result']
+ d.addCallback(resulted)
+
+ def done(result):
+ print('Done: %s' % (result,))
+ reactor.stop()
+ d.addCallback(done)
+
+if __name__ == '__main__':
+ getList()
+ reactor.run()
Property changes on: CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/agent.py
___________________________________________________________________
Added: svn:executable
+ *
Modified: CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/gateway.py
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/gateway.py 2013-06-26 07:56:16 UTC (rev 11409)
+++ CalendarServer/branches/users/glyph/launchd-wrapper/calendarserver/tools/gateway.py 2013-06-26 07:56:42 UTC (rev 11410)
@@ -159,23 +159,26 @@
class Runner(object):
- def __init__(self, root, directory, store, commands):
+ def __init__(self, root, directory, store, commands, output=None):
self.root = root
self.dir = directory
self.store = store
self.commands = commands
+ if output is None:
+ output = sys.stdout
+ self.output = output
def validate(self):
# Make sure commands are valid
for command in self.commands:
if 'command' not in command:
- respondWithError("'command' missing from plist")
+ self.respondWithError("'command' missing from plist")
return False
commandName = command['command']
methodName = "command_%s" % (commandName,)
if not hasattr(self, methodName):
- respondWithError("Unknown command '%s'" % (commandName,))
+ self.respondWithError("Unknown command '%s'" % (commandName,))
return False
return True
@@ -189,17 +192,17 @@
if hasattr(self, methodName):
(yield getattr(self, methodName)(command))
else:
- respondWithError("Unknown command '%s'" % (commandName,))
+ self.respondWithError("Unknown command '%s'" % (commandName,))
except Exception, e:
- respondWithError("Command failed: '%s'" % (str(e),))
+ self.respondWithError("Command failed: '%s'" % (str(e),))
raise
# Locations
def command_getLocationList(self, command):
- respondWithRecordsOfTypes(self.dir, command, ["locations"])
+ self.respondWithRecordsOfTypes(self.dir, command, ["locations"])
@inlineCallbacks
@@ -212,7 +215,7 @@
try:
record = (yield updateRecord(True, self.dir, "locations", **kwargs))
except DirectoryError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
readProxies = command.get("ReadProxies", None)
@@ -220,7 +223,7 @@
principal = principalForPrincipalID(record.guid, directory=self.dir)
(yield setProxies(self.store, principal, readProxies, writeProxies, directory=self.dir))
- respondWithRecordsOfTypes(self.dir, command, ["locations"])
+ self.respondWithRecordsOfTypes(self.dir, command, ["locations"])
@inlineCallbacks
@@ -228,18 +231,18 @@
guid = command['GeneratedUID']
record = self.dir.recordWithGUID(guid)
if record is None:
- respondWithError("Principal not found: %s" % (guid,))
+ self.respondWithError("Principal not found: %s" % (guid,))
return
recordDict = recordToDict(record)
principal = principalForPrincipalID(guid, directory=self.dir)
if principal is None:
- respondWithError("Principal not found: %s" % (guid,))
+ self.respondWithError("Principal not found: %s" % (guid,))
return
recordDict['AutoSchedule'] = principal.getAutoSchedule()
recordDict['AutoAcceptGroup'] = principal.getAutoAcceptGroup()
recordDict['ReadProxies'], recordDict['WriteProxies'] = (yield getProxies(principal,
directory=self.dir))
- respond(command, recordDict)
+ self.respond(command, recordDict)
command_getResourceAttributes = command_getLocationAttributes
@@ -260,7 +263,7 @@
try:
record = (yield updateRecord(False, self.dir, "locations", **kwargs))
except DirectoryError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
readProxies = command.get("ReadProxies", None)
@@ -279,15 +282,15 @@
try:
self.dir.destroyRecord("locations", **kwargs)
except DirectoryError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
- respondWithRecordsOfTypes(self.dir, command, ["locations"])
+ self.respondWithRecordsOfTypes(self.dir, command, ["locations"])
# Resources
def command_getResourceList(self, command):
- respondWithRecordsOfTypes(self.dir, command, ["resources"])
+ self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
@inlineCallbacks
@@ -300,7 +303,7 @@
try:
record = (yield updateRecord(True, self.dir, "resources", **kwargs))
except DirectoryError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
readProxies = command.get("ReadProxies", None)
@@ -308,7 +311,7 @@
principal = principalForPrincipalID(record.guid, directory=self.dir)
(yield setProxies(self.store, principal, readProxies, writeProxies, directory=self.dir))
- respondWithRecordsOfTypes(self.dir, command, ["resources"])
+ self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
@inlineCallbacks
@@ -328,7 +331,7 @@
try:
record = (yield updateRecord(False, self.dir, "resources", **kwargs))
except DirectoryError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
readProxies = command.get("ReadProxies", None)
@@ -347,13 +350,13 @@
try:
self.dir.destroyRecord("resources", **kwargs)
except DirectoryError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
- respondWithRecordsOfTypes(self.dir, command, ["resources"])
+ self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
def command_getLocationAndResourceList(self, command):
- respondWithRecordsOfTypes(self.dir, command, ["locations", "resources"])
+ self.respondWithRecordsOfTypes(self.dir, command, ["locations", "resources"])
# Proxies
@@ -363,9 +366,9 @@
def command_listWriteProxies(self, command):
principal = principalForPrincipalID(command['Principal'], directory=self.dir)
if principal is None:
- respondWithError("Principal not found: %s" % (command['Principal'],))
+ self.respondWithError("Principal not found: %s" % (command['Principal'],))
return
- (yield respondWithProxies(self.dir, command, principal, "write"))
+ (yield self.respondWithProxies(self.dir, command, principal, "write"))
@inlineCallbacks
@@ -373,90 +376,90 @@
principal = principalForPrincipalID(command['Principal'],
directory=self.dir)
if principal is None:
- respondWithError("Principal not found: %s" % (command['Principal'],))
+ self.respondWithError("Principal not found: %s" % (command['Principal'],))
return
proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
if proxy is None:
- respondWithError("Proxy not found: %s" % (command['Proxy'],))
+ self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
return
try:
(yield addProxy(self.root, self.dir, self.store, principal, "write", proxy))
except ProxyError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
except ProxyWarning, e:
pass
- (yield respondWithProxies(self.dir, command, principal, "write"))
+ (yield self.respondWithProxies(self.dir, command, principal, "write"))
@inlineCallbacks
def command_removeWriteProxy(self, command):
principal = principalForPrincipalID(command['Principal'], directory=self.dir)
if principal is None:
- respondWithError("Principal not found: %s" % (command['Principal'],))
+ self.respondWithError("Principal not found: %s" % (command['Principal'],))
return
proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
if proxy is None:
- respondWithError("Proxy not found: %s" % (command['Proxy'],))
+ self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
return
try:
(yield removeProxy(self.root, self.dir, self.store, principal, proxy, proxyTypes=("write",)))
except ProxyError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
except ProxyWarning, e:
pass
- (yield respondWithProxies(self.dir, command, principal, "write"))
+ (yield self.respondWithProxies(self.dir, command, principal, "write"))
@inlineCallbacks
def command_listReadProxies(self, command):
principal = principalForPrincipalID(command['Principal'], directory=self.dir)
if principal is None:
- respondWithError("Principal not found: %s" % (command['Principal'],))
+ self.respondWithError("Principal not found: %s" % (command['Principal'],))
return
- (yield respondWithProxies(self.dir, command, principal, "read"))
+ (yield self.respondWithProxies(self.dir, command, principal, "read"))
@inlineCallbacks
def command_addReadProxy(self, command):
principal = principalForPrincipalID(command['Principal'], directory=self.dir)
if principal is None:
- respondWithError("Principal not found: %s" % (command['Principal'],))
+ self.respondWithError("Principal not found: %s" % (command['Principal'],))
return
proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
if proxy is None:
- respondWithError("Proxy not found: %s" % (command['Proxy'],))
+ self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
return
try:
(yield addProxy(self.root, self.dir, self.store, principal, "read", proxy))
except ProxyError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
except ProxyWarning, e:
pass
- (yield respondWithProxies(self.dir, command, principal, "read"))
+ (yield self.respondWithProxies(self.dir, command, principal, "read"))
@inlineCallbacks
def command_removeReadProxy(self, command):
principal = principalForPrincipalID(command['Principal'], directory=self.dir)
if principal is None:
- respondWithError("Principal not found: %s" % (command['Principal'],))
+ self.respondWithError("Principal not found: %s" % (command['Principal'],))
return
proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
if proxy is None:
- respondWithError("Proxy not found: %s" % (command['Proxy'],))
+ self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
return
try:
(yield removeProxy(self.root, self.dir, self.store, principal, proxy, proxyTypes=("read",)))
except ProxyError, e:
- respondWithError(str(e))
+ self.respondWithError(str(e))
return
except ProxyWarning, e:
pass
- (yield respondWithProxies(self.dir, command, principal, "read"))
+ (yield self.respondWithProxies(self.dir, command, principal, "read"))
@inlineCallbacks
@@ -473,27 +476,45 @@
cutoff.setDateOnly(False)
cutoff.offsetDay(-retainDays)
eventCount = (yield PurgeOldEventsService.purgeOldEvents(self.store, cutoff, DEFAULT_BATCH_SIZE))
- respond(command, {'EventsRemoved' : eventCount, "RetainDays" : retainDays})
+ self.respond(command, {'EventsRemoved' : eventCount, "RetainDays" : retainDays})
- at inlineCallbacks
-def respondWithProxies(directory, command, principal, proxyType):
- proxies = []
- subPrincipal = proxySubprincipal(principal, proxyType)
- if subPrincipal is not None:
- membersProperty = (yield subPrincipal.readProperty(davxml.GroupMemberSet, None))
- if membersProperty.children:
- for member in membersProperty.children:
- proxyPrincipal = principalForPrincipalID(str(member), directory=directory)
- proxies.append(proxyPrincipal.record.guid)
+ @inlineCallbacks
+ def respondWithProxies(self, directory, command, principal, proxyType):
+ proxies = []
+ subPrincipal = proxySubprincipal(principal, proxyType)
+ if subPrincipal is not None:
+ membersProperty = (yield subPrincipal.readProperty(davxml.GroupMemberSet, None))
+ if membersProperty.children:
+ for member in membersProperty.children:
+ proxyPrincipal = principalForPrincipalID(str(member), directory=directory)
+ proxies.append(proxyPrincipal.record.guid)
- respond(command, {
- 'Principal' : principal.record.guid, 'Proxies' : proxies
- })
+ self.respond(command, {
+ 'Principal' : principal.record.guid, 'Proxies' : proxies
+ })
+ def respondWithRecordsOfTypes(self, directory, command, recordTypes):
+ result = []
+ for recordType in recordTypes:
+ for record in directory.listRecords(recordType):
+ recordDict = recordToDict(record)
+ result.append(recordDict)
+ self.respond(command, result)
+
+
+
+ def respond(self, command, result):
+ self.output.write(writePlistToString({'command' : command['command'], 'result' : result}))
+
+
+ def respondWithError(self, msg, status=1):
+ self.output.write(writePlistToString({'error' : msg, }))
+
+
def recordToDict(record):
recordDict = {}
for key, info in attrMap.iteritems():
@@ -509,26 +530,10 @@
pass
return recordDict
-
-
-def respondWithRecordsOfTypes(directory, command, recordTypes):
- result = []
- for recordType in recordTypes:
- for record in directory.listRecords(recordType):
- recordDict = recordToDict(record)
- result.append(recordDict)
- respond(command, result)
-
-
-
-def respond(command, result):
- sys.stdout.write(writePlistToString({'command' : command['command'], 'result' : result}))
-
-
-
def respondWithError(msg, status=1):
sys.stdout.write(writePlistToString({'error' : msg, }))
+
if __name__ == "__main__":
main()
Copied: CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/agent.plist (from rev 11409, CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/calendarserver.plist)
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/agent.plist (rev 0)
+++ CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/agent.plist 2013-06-26 07:56:42 UTC (rev 11410)
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Copyright (c) 2013 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.
+ -->
+
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+
+ <key>Label</key>
+ <string>org.calendarserver.agent</string>
+
+ <key>ProgramArguments</key>
+ <array>
+ <string>/Applications/Server.app/Contents/ServerRoot/usr/sbin/caldavd</string>
+ <string>-t</string>
+ <string>Agent</string>
+ <string>-X</string>
+ <string>-R</string>
+ <string>caldav_kqueue</string>
+ <string>-o</string>
+ <string>PIDFile=agent.pid</string>
+ </array>
+
+ <key>InitGroups</key>
+ <true/>
+
+ <key>ServiceIPC</key>
+ <true/>
+
+ <key>Sockets</key>
+ <dict>
+ <key>AgentSocket</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>12345</string>
+ <key>SockFamily</key>
+ <string>IPv4</string>
+ </dict>
+ <!--
+ <key>AgentSocket</key>
+ <dict>
+ <key>SockFamily</key>
+ <string>UNIX</string>
+ <key>SockPathName</key>
+ <string>/some/path/org.calendarserver.agent.sock</string>
+ </dict>
+ -->
+ </dict>
+
+ <key>HardResourceLimits</key>
+ <dict>
+ <key>NumberOfFiles</key>
+ <integer>12000</integer>
+ </dict>
+
+ <key>SoftResourceLimits</key>
+ <dict>
+ <key>NumberOfFiles</key>
+ <integer>12000</integer>
+ </dict>
+
+ <key>PreventsSleep</key>
+ <true/>
+
+ <key>StandardOutPath</key>
+ <string>/var/log/caldavd/agent.log</string>
+
+ <key>StandardErrorPath</key>
+ <string>/var/log/caldavd/agent.log</string>
+
+</dict>
+</plist>
Modified: CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/calendarserver.plist
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/calendarserver.plist 2013-06-26 07:56:16 UTC (rev 11409)
+++ CalendarServer/branches/users/glyph/launchd-wrapper/contrib/launchd/calendarserver.plist 2013-06-26 07:56:42 UTC (rev 11410)
@@ -32,6 +32,8 @@
<string>-X</string>
<string>-R</string>
<string>caldav_kqueue</string>
+ <string>-o</string>
+ <string>FailIfUpgradeNeeded=False</string>
</array>
<key>InitGroups</key>
Modified: CalendarServer/branches/users/glyph/launchd-wrapper/txdav/base/datastore/subpostgres.py
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper/txdav/base/datastore/subpostgres.py 2013-06-26 07:56:16 UTC (rev 11409)
+++ CalendarServer/branches/users/glyph/launchd-wrapper/txdav/base/datastore/subpostgres.py 2013-06-26 07:56:42 UTC (rev 11410)
@@ -402,6 +402,7 @@
createDatabaseCursor.execute("commit")
return createDatabaseConn, createDatabaseCursor
+ # TODO: always go through pg_ctl start
try:
createDatabaseConn, createDatabaseCursor = createConnection()
except pgdb.DatabaseError:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130626/2ff9eb47/attachment-0001.html>
More information about the calendarserver-changes
mailing list