Using launchd
launchd is Mac OS X's system wide and per-user daemon/agent manager. It handles many tasks previously handled by various scripts (/etc/rc) and programs (xinitd, cron, SystemStarter). Introduced in Mac OS X 10.4 Tiger, it fully replaces the traditional init program and should be used to manage all server jobs, particularly on Mac OS X 10.5 Leopard and later. For more information on launchd, see the launchd(8) man page or http://developer.apple.com/macosx/launchd.html.
It is fairly easy to run a buildbot slave or master as a launchd job.
Sample launchd job property list for a buildbot slave
The following launchd job property list file describes a buildbot slave using Mac OS X 10.5's built-in Python 2.5 interpreter but also includes the default site packages directory in PYTHONPATH in order to use a manually installed Twisted 2.5.0 package (Mac OS X 10.5 includes Twisted 2.4.0). It also adds MacPorts's default binary path to PATH.
Note that the specified process owner, buildbot, is not part of the built-in system users on Mac OS X 10.5. Additional users can be created through the Accounts prefpane, with the dscl utility, or by using Workgroup Manager, part of the server administration programs freely available from Apple.
If setting up through dscl or Workgroup Manager, note that you should specify a home directory (a NFSHomeDirectory attribute in the DirectoryServices user record) for the user you decide to run your buildbots as. This will ensure that programs who wish to write configuration or runtime files in their user's home directory (such as Subversion's .subversion directory or ssh's .ssh directory) may do so. In the case of this sample file, the buildbot user has its NFSHomeDirectory attribute set to /var/buildbot.
Finally, the reason the daemon group is used is to allow write access into /var/run. This directory should be used for pid files because it is cleaned up when the system boots. It therefore ensures the slave (or master) will properly start, as there will not be any old pid file potentially pointing to an existing process (thus causing the slave or master to abort).
This properly list should be named after the job label (here net.sourceforge.buildbot.slave.rivenx) with the addition of a plist extension (thus in this example, net.sourceforge.buildbot.slave.rivenx.plist) and placed in the /Library/LaunchDaemons directory. The property list must be owned by root:wheel, otherwise the system will not load it. For details on managing launchd jobs, see the launchctl(1) man page.
Note that placing the launchd plist in /Library/LaunchDaemons will cause buildbot to launch on booting the machine, even if the buildbot user does not have a graphical context (auto login on boot, say). If the machine you're setting this up as is a test slave and requires a GUI context to run tests with, you should place this plist inside ~buildbot/Library/LaunchAgents, which means that builbot will only run when the buildbot user auto logs in (don't forget to set auto login in the Accounts prefpane). This will avoid any issues with a system-wide context trying to access a GUI context, which blocks certain API level calls.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/opt/local/bin:/sbin:/usr/sbin:/bin:/usr/bin</string> <key>PYTHONPATH</key> <string>/Library/Python/2.5/site-packages</string> </dict> <key>GroupName</key> <string>daemon</string> <key>KeepAlive</key> <dict> <key>SuccessfulExit</key> <false/> </dict> <key>Label</key> <string>net.sourceforge.buildbot.slave.rivenx</string> <key>OnDemand</key> <false/> <key>ProgramArguments</key> <array> <string>/usr/local/bin/twistd</string> <string>--nodaemon</string> <string>--python=buildbot.tac</string> <string>--logfile=buildbot.log</string> <string>--prefix=rivenx-slave</string> <string>--pidfile=/var/run/rivenx-slave.pid</string> </array> <key>RunAtLoad</key> <true/> <key>UserName</key> <string>buildbot</string> <key>WorkingDirectory</key> <string>/var/buildbot/rivenx-slave</string> </dict> </plist>
![[Buildbot Logo]](/trac/chrome/site/header-text-transparent.png)