Picking up where we left off with Jenkins, let’s look at one possible workflow to get autopkg projects working. Specifically when paired with Munki, this requires a bit more thought, but the Jenkins ‘workspace’ model and sane use of variables allows us to make one all-purpose script for most contingencies we’d deal with. As those that have been following my saga trying to support the Lync recipe may be aware, upstream ahem changes (read: drunken interns wildin’ out on the XML) can cause recipes to fail. If you’re used to running autopkg with the list verb, and one recipe succeeds before another fails in a new and exciting way that isn’t yet caught by error-handling, you could have products that already were pushed to the munki repo but the MakeCatalogs recipe never ran. Since the catalog isn’t rebuilt, this leads to the dreaded __1
naming getting appended to the product… without it actually being available to customers.
One way to remove points of failure is to split up each recipe into its own job, and put the MakeCatalogs recipe immediately after each individual product run. That may seem like a bit to have to configure for each job, and as you may already have dozens of recipes you use, there’s a real fear of death by page refresh. Why don’t we automate creating Jenkins jobs? (Insert yo dawg meme here.) There is a Puppet module for Jenkins that enables you to build jobs from a template, and plugins that dynamically create jobs, but I usually like simpler-to-understand methods. Bundled with Jenkins is a (java jarfile-driven) CLI component that handles auth, listing jobs(with…
list-jobs
), exporting a job in xml to stdout(via get-job
, which you can redirect to a file) and what we’re really after, generating new jobs with a script, like below.
<code>declare -ax NEWJOBARRAY=("MacID.munki" "Knock.munki")# bash arrays are not particularly fun, but for job in ${NEWJOBARRAY[@]}; do java -jar jenkins-cli.jar -s http://jenkins:8080/ create-job $job < /path/to/project/template.xml done </code>
What each job actually runs as part of that template is the script below, which is shared between workspaces and checks for either a traceback, some other recipe failure, or a new download, and inserts comments into the notification that the Jenkins mailer plugin would send. It uses a variable built-in to Jenkins to populate the JOB_NAME.
<code>#!/bin/sh /usr/local/bin/autopkg run -v ${JOB_NAME} MakeCatalogs.munki 2>&1 | tee /Users/Shared/jenks/tmp/${JOB_NAME}.log FAILED=`grep -E 'raceback|failed' /Users/Shared/jenks/tmp/${JOB_NAME}.log` if [ -n "$FAILED" ]; then echo "${JOB_NAME} failed." exit 1 fi RESULT=`grep rebuilt /Users/Shared/jenks/tmp/${JOB_NAME}.log` if [ -n "$RESULT" ]; then echo "${JOB_NAME} added to Munki repository." exit 1 else echo "Nothing downloaded/added to munki." exit 0 fi </code>
And finally, I have a ‘master’ multi-configuration project that runs the stuff for general consumption on one schedule, separate from other ones I want to run less frequently(like Atom or Apple Printer Drivers). This means each time we decide to support a new product I just run the jenkins-cli snippet above, and add the project name to the list of downstream tasks in my ‘master’ as appropriate. I’m sure this wasn’t the whole picture to help everyone who’s brave enough to use Jenkins in the first place, so please let me know your questions in the comments, or let me know where I’m doin it rong!
Recent Comments