Tuesday, February 4, 2014

Configuring OSX Mavericks and Jenkins to Support Interactive Jobs

While developing iOS applications we leverage Jenkins on OSX Mavericks for our Xcode / iOS and Android builds. We perform application level automated testing (i.e. in the Simulator or Emulator) and as such need a Windowed environment can't simply run in a Daemon mode. In addition, OSX Server on Mavericks integrates a "GUI" Apache Server that we want to integrate.

An initial installation of Jenkins on a Mac using the Jenkins supplied installer is ok, but it only supports a headless execution. There are many times that our jobs need a head or window manager to execute (Xcode Automation Tests). To support this on Mac we need to reorganize this. Basically, we want to change the jenkins process from running as a LaunchDaemon and to run as LaunchAgent defined the jenkins user itself. Here is a cookbook for doing this with a fresh Mac install.
  1. If you don't have Java installed, install it by attempting to run the following and follow the instructions. java -version (I’d recommend to install the Java 7 version directly from Oracle).
  2. Download & Install the Jenkins Mac Installer.
  3. This will create a user named jenkins. In the user manager it will have an empty name, go ahead and name it Jenkins User in System Preferences -> User & Groups. You will also want to set a password at this time. It's not necessary, nor recommend to make this user an Administrator
  4. Now, we need to disable the Jenkins LaunchDaemon. You can unload and force it not to load again by executing "sudo launchctl unload -w /Library/LaunchDaemons/org.jenkins-ci.plist"
  5. We now need to create a LaunchAgents script, and this can be done by copying "cp /Library/LaunchDaemons/org.jenkins-ci.plist to ~/Library/LaunchAgents/org.jenkins-ci.plist"
  6. For Jenkins to start on a fresh system boot, you would configure System Preferences -> User & Groups -> Login Options to automatically login to the Jenkins User account.
  7. We should now be good to go and can start jenkins by logging in to the jenkins account (and out if already logged in).
One thing to keep in mind, is by default Jenkins can not update itself. To fix this you can do the following.
  1. Change the owner on the jenkins.war and directory. "sudo chown /Applications/Jenkins jenkins; sudo chown /Applications/Jenkins/jenkins.war jenkins"
Next we would also like Jenkins to play nicely with OSX Server (You might need to install it if it's not already installed from the App Store). Ideally, we want http://{SERVER_NAME}/jenkins to forward proxy to http://localhost:8080/jenkins.
  1. If Websites aren’t enabled, go ahead and turn that on in OSX Server. Make sure to “Allow overrides using .htaccess files” is enabled in the Advanced settings of the "Server Website" and "Server Website (SSL)” sites
  2. We need to configure Jenkins to respond to /jenkins as well, and this can be done by adding a prefix to the preferences. "sudo defaults write /Library/Preferences/org.jenkins-ci.plist prefix /jenkins"
  3. We need to configure OSX Server to redirect any non-SSL traffic to https for /jenkins. We did this in the OSX Server App by click on Websites -> Server Website -> Redirects -> Edit and adding a Permanent redirect for anything /jenkins to go to https://{SERVER_NAME}/jenkins.
  4. We need to configure OSX Server to forward proxy any /jenkins requests to the local jenkins server. Do this by adding an .htaccess file to /Library/Server/Web/Data/Sites/Default/jenkins/.htaccess with the following content.
RewriteEngine on
RewriteCond %{HTTPS} =on
RewriteRule ^(.*)$ http://localhost:8080%{REQUEST_URI} [P]

After that we should now be able to access jenkins from http://{SERVER_NAME}/jenkins and it should redirect the user to https://{SERVER_NAME}/jenkins and allow you to login and continue the Jenkins configuration and create jobs that start windows (i.e. iOS Simulator and the Android Emulator).