<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>zomo tech &#187; sw</title>
	<atom:link href="http://www.zomo.co.uk/category/sw/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zomo.co.uk</link>
	<description>Is it done yet?</description>
	<lastBuildDate>Wed, 24 Feb 2010 09:18:37 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>cron</title>
		<link>http://www.zomo.co.uk/2010/02/cron/</link>
		<comments>http://www.zomo.co.uk/2010/02/cron/#comments</comments>
		<pubDate>Wed, 24 Feb 2010 09:18:37 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=217</guid>
		<description><![CDATA[Obviously cron jobs are abundantly useful for so many things, all the way from basic housekeeping up to big application functionality.
They&#8217;re also the source of plenty of flail. What do I mean?

They are neither code nor data, so often get overlooked, or shonkily installed, by application deployment tools
They run with a minimal environment that can [...]]]></description>
			<content:encoded><![CDATA[<p>Obviously cron jobs are abundantly useful for so many things, all the way from basic housekeeping up to big application functionality.</p>
<p>They&#8217;re also the source of plenty of flail. What do I mean?</p>
<ul>
<li>They are neither code nor data, so often get overlooked, or shonkily installed, by application deployment tools</li>
<li>They run with a minimal environment that can catch out the unwary: scripts that work in interactive shell sometimes don&#8217;t from cron</li>
<li>The default behaviour of mailing output to the cronjob owner generates large amounts of mail that gets ignored, filtered or bounced</li>
<li>Jobs can fail silently and no-one notices until, say, you need to restore that backup that hasn&#8217;t run for last six months</li>
<li>Jobs that helpfully append their output to a log commonly don&#8217;t rotate that log</li>
<li>It&#8217;s easy to have jobs overlapping if they get stuck or take longer than expected to complete. This is a splendid way of wedging a machine.</li>
</ul>
<p>The mail aspect is a particular peeve. In some jobs my mailbox has enjoyed several thousand cron generated mails a day, and there&#8217;s no way I&#8217;m able to accurately look at each one and react to it. Mostly they contain expected output from successful job execution, so they&#8217;re easy to skip. But I don&#8217;t trust my eyes to get that right all the time.</p>
<p>One approach to this is to arrange for jobs to only send mail on error. This is an improvement, but can lead into thinking that a job is happily succeeding when in fact it&#8217;s either not running or the only-on-error logic is bust. Since cron jobs often cover essential system tasks like backing up, syncing data around and reporting it&#8217;s vital that they don&#8217;t fail silently.</p>
<p> I&#8217;ve worked somewhere that tackled this by collating cron-generated mails from diverse systems into a system mailbox and pattern matching them for failure signs. This seems slightly dubious &#8212; it&#8217;s fragile and labour intensive  &#8212; but at least the system also flagged if expected jobs failed to arrive and got our inboxes tamed. </p>
<p>To tackle these problems I find myself writing wrappers for cronjobs. I&#8217;ve written several variants to meet different situation&#8217;s needs. Unhelpfully I call them all <code>cronwrap</code>.  These wrappers sets out to</p>
<ul>
<li>Engage the amazingly useful <a href="http://unixwiz.net/tools/lockrun.html"><code>lockrun</code></a> utility to guard against multiple execution of stuck crons</li>
<li>Place cron output into timestamped logs that can be both aged out and made available to interested parties</li>
<li>Hook into local monitoring systems:
<ol>
<li>On execution, update a run counter (SNMP data or some simple text file)</li>
<li>On failure, send a SNMP trap or leave some bait for Nagios. Also, update a fail counter</li>
<li>If <code>lockrun</code> has prevented a job running owing to overlap, send a SNMP trap or similarly bait Nagios</li>
</ol>
</li>
<li>If required, send output by mail somewhere (sometimes this is necessary, even with the concerns listed above)</li>
</ul>
<p>So, nothing surprising there. Using such wrappers helps keep cron jobs tamed and reliable, and it&#8217;s monitoring them near to where the action occurs, rather than mediating via SMTP.</p>
<p>This is hardly invention either, there&#8217;s <a href="http://www.google.com/codesearch?q=cronwrap&#038;hl=en&#038;btnG=Search+Code">plenty</a> of prior art with different nuances in behaviour to meet the needs of different environments. Perhaps I&#8217;ll merge the variants of my efforts and publish too.</p>
<p>What&#8217;s curious is that this functionality isn&#8217;t available inside the cron daemon<sup>1</sup> itself. It is perfectly placed to catch exit status, divert output and know if a job has overrun; and would remove the need for all this additional monkeying to make jobs reliable and well behaved. If my C wasn&#8217;t just read-only I&#8217;d have a crack at it!</p>
<p>There, I&#8217;ve finally condensed all my cron rant into one sustained piece.</p>
<ol class="footnotes"><li id="footnote_0_217" class="footnote"> To be clear, I&#8217;m talking about the BSD cron written by Paul Vixie. None of the variants I&#8217;ve seen address these concerns either. I&#8217;d love to know if there&#8217;s any I&#8217;ve missed.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2010/02/cron/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>SOAP in unexpected &#8220;actually, quite easy&#8221; incident.</title>
		<link>http://www.zomo.co.uk/2009/09/soap-in-unexpected-actually-quite-easy-incident/</link>
		<comments>http://www.zomo.co.uk/2009/09/soap-in-unexpected-actually-quite-easy-incident/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 21:02:18 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=203</guid>
		<description><![CDATA[In web service access shuffle, today&#8217;s mission is introducing large N number of new backend pools, traffic rules and virtual servers to Zeus ZXTM balancers. No time for monkeying around in the web UI, better check out their well documented API. It uses SOAP, which I&#8217;ve never got busy with before &#8211; slightly apprehensive.
The reference [...]]]></description>
			<content:encoded><![CDATA[<p>In web service access shuffle, today&#8217;s mission is introducing large N number of new backend pools, traffic rules and virtual servers to Zeus <a href="http://www.zeus.com/products/zxtm/">ZXTM</a> balancers. No time for monkeying around in the web UI, better check out their <a href="http://knowledgehub.zeus.com/media/5.1/ZXTM_5.1_Control_API.pdf">well documented</a> API. It uses <a href="http://en.wikipedia.org/wiki/SOAP">SOAP</a>, which I&#8217;ve never got busy with before &#8211; slightly apprehensive.</p>
<p>The reference documentation has examples in Perl and PHP which got me so far, but I&#8217;m most comfortable in Ruby now, and was happy to find <a href="http://knowledgehub.zeus.com/code/2009/04/09/ruby_and_soap_example_2"><sup>1</sup> this</a> pointer to using the <a href="http://dev.ctor.org/soap4r">soap4r</a> library.</p>
<p>Chief bonus here is the <code>wsdl2ruby.rb</code> tool that&#8217;ll transform the <a href="http://www.w3.org/TR/wsdl">WSDL</a> data into Ruby objects with heirarchy, attribute accessors and everything else to make operating the API really comfortable. If your WSDL is a moving target during development it&#8217;ll even do this on the fly.</p>
<p>This meant getting the scripting done to configure the ZXTMs was pretty straightforward, without any faffing with the underlying access mech. Refreshing!</p>
<ol class="footnotes"><li id="footnote_0_203" class="footnote">I was going to paste example code, but this&#8217;ll do</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2009/09/soap-in-unexpected-actually-quite-easy-incident/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ipmitool for OSX</title>
		<link>http://www.zomo.co.uk/2009/09/ipmitool-for-osx/</link>
		<comments>http://www.zomo.co.uk/2009/09/ipmitool-for-osx/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 08:51:49 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=196</guid>
		<description><![CDATA[Nothing searchable in MacPorts, but found this.
Update: Turns out this build is missing isol mode serial-on-LAN for IPMI 1.5 hosts1, and building the ipmitool distribution wasn&#8217;t so hard after all. Packaging systems have made me lazy!
Dell R200 uses IPMI 1.5, Dell R410 uses 2.0. Both do SOL and remote power management well enough]]></description>
			<content:encoded><![CDATA[<p>Nothing searchable in <a href="http://www.macports.org/">MacPorts</a>, but found <a href="http://freebsdgirl.com/2008/07/ipmitool-for-osx.html">this</a>.</p>
<p>Update: Turns out this build is missing <code>isol</code> mode serial-on-LAN for IPMI 1.5 hosts<sup>1</sup>, and building the <a href="http://ipmitool.sourceforge.net/">ipmitool</a> distribution wasn&#8217;t so hard after all. Packaging systems have made me lazy!</p>
<ol class="footnotes"><li id="footnote_0_196" class="footnote">Dell R200 uses IPMI 1.5, Dell R410 uses 2.0. Both do SOL and remote power management well enough</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2009/09/ipmitool-for-osx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>vxargs &#8211; visual parallel xargs</title>
		<link>http://www.zomo.co.uk/2009/09/vxargs-visual-parallel-xargs/</link>
		<comments>http://www.zomo.co.uk/2009/09/vxargs-visual-parallel-xargs/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 07:34:36 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=182</guid>
		<description><![CDATA[Flag for vxargs, an xargs-a-like that runs its multiple command invocations in parallel and provides a (ncurses) histogram of the progress. Its companion program pattern provides an easy way to generate IP / hostnames based on a logical sequence. Together the make a reasonble way to run a command on a bunch of hosts and [...]]]></description>
			<content:encoded><![CDATA[<p>Flag for <a href="http://vxargs.sourceforge.net/">vxargs</a>, an xargs-a-like that runs its multiple command invocations in parallel and provides a (ncurses) histogram of the progress. Its companion program <a href="http://code.activestate.com/recipes/355531/">pattern</a> provides an easy way to generate IP / hostnames based on a logical sequence. Together the make a reasonble way to run a command on a bunch of hosts and collate the stdout, stderr and exit status of each.</p>
<p>As a same-same-but-different alternative to</p>
<ul>
<li><a href="http://www.theether.org/pssh/">pssh</a></li>
<li>That xterm multiplexer I can never remember the name of</li>
<li><a href="http://www.gnu.org/software/screen/">screen(1)</a> and <a href="http://en.wikipedia.org/wiki/Apple_Terminal">Terminal.app</a>&#8217;s send-to-many option</li>
<li>Quick and dirty shell scripts iterating over a host list</li>
<li><a href="http://www.capify.org/index.php/">Capistrano</a>&#8217;s shell (even on hosts that don&#8217;t run any other Ruby!)</li>
</ul>
<p>&#8230; it&#8217;s proving pretty solid.</p>
<p>Example:<br />
<code><br />
[admin@manage3 tmp]$ pattern.py foo[1-8] | vxargs -y -o ~/tmp ssh {} varnishadm -Tlocalhost:6082 ping<br />
</code></p>
<p>Terminal clears, and shows progress:<br />
<code><br />
8/8:ssh -l root foo8 varnishadm -Tlocalhost:6082 ping<br />
Done<br />
Done<br />
Done<br />
Done<br />
Done<br />
( 10s)  6: foo7<br />
Done<br />
</code><br />
and exits<br />
<code><br />
exit code 0: 7 job(s)<br />
exit code 1: 1 job(s)<br />
total number of jobs: 8<br />
</code><br />
Now you can inspect the output from each host, exit status and an overall failure list<br />
<code><br />
[admin@manage3 tmp]$ cat ~/tmp/abnormal_list<br />
foo5<br />
[admin@manage3 tmp]$ cat ~/tmp/foo5.err<br />
Warning: Permanently added 'foo5,10.221.11.0' (RSA) to the list of known hosts.<br />
connect(): Connection refused<br />
An error occured in receiving status.<br />
</code></p>
<p>Via <a href="http://chneukirchen.org/trivium/2009-09-13">Trivium</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2009/09/vxargs-visual-parallel-xargs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>irssi client certificate patch</title>
		<link>http://www.zomo.co.uk/2009/09/irssi-client-certificate-patch/</link>
		<comments>http://www.zomo.co.uk/2009/09/irssi-client-certificate-patch/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 07:18:21 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=169</guid>
		<description><![CDATA[Patch for irssi so it can prompt for your X509 client certificate correctly.
]]></description>
			<content:encoded><![CDATA[<p><a href="http://bugs.irssi.org/index.php?do=details&#038;task_id=305">Patch</a> for <a href="http://www.irss.org">irssi</a> so it can prompt for your X509 client certificate correctly.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2009/09/irssi-client-certificate-patch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL replication health</title>
		<link>http://www.zomo.co.uk/2008/09/mysql-replication-health/</link>
		<comments>http://www.zomo.co.uk/2008/09/mysql-replication-health/#comments</comments>
		<pubDate>Tue, 30 Sep 2008 07:05:48 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=116</guid>
		<description><![CDATA[It&#8217;s possible for MySQL&#8217;s statement-based replication to get out of sync. I&#8217;ve yet to see a real example myself, perhaps because the DB abstraction layers I encounter not creating the &#8220;dangerous&#8221; queries that can make this happen. Still, other than monitoring replication health with SHOW SLAVE STATUS and friends I&#8217;ve sometimes been concerned about whether [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s possible for MySQL&#8217;s statement-based replication to get out of sync. I&#8217;ve yet to see a real example myself, perhaps because the DB abstraction layers I encounter not creating the <a href="http://www.xaprb.com/blog/2007/11/08/how-mysql-replication-got-out-of-sync/">&#8220;dangerous&#8221; queries</a> that can make this happen. Still, other than monitoring replication health with <code>SHOW SLAVE STATUS</code> and friends I&#8217;ve sometimes been concerned about whether my MySQL slaves are faithful copies of the master. Finding that out during a failover moment is the wrong time.</p>
<p>The author of the piece linked above has scratched this itch with <a href="http://code.google.com/p/maatkit/">Maatkit</a>, a suite of replication-focused MySQL tools which include some for checksumming tables.</p>
<p>This can run with standalone instances but most appealing is the way it runs across a replication chain: the statements to perform the table checksums are themselves introduced into the replication and store their results in a table alongside the master&#8217;s checksums. You can then compare and contrast on each slave: neat. All straightforward to roll into Nagios or other monitoring.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2008/09/mysql-replication-health/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Single Sign-On To Integrate Ning With An External Site</title>
		<link>http://www.zomo.co.uk/2008/08/using-single-sign-on-to-integrate-ning-with-an-external-site/</link>
		<comments>http://www.zomo.co.uk/2008/08/using-single-sign-on-to-integrate-ning-with-an-external-site/#comments</comments>
		<pubDate>Wed, 20 Aug 2008 18:14:10 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[all]]></category>
		<category><![CDATA[sw]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=77</guid>
		<description><![CDATA[Overview
Ning provide off the peg hosted social networks. The service is free unless you pay to not have their context-driven ads on your pages. Within a few minutes of sign-up you&#8217;re away.
Particulary cool is that they will let you at the source of your network. You can&#8217;t then wander off and run it elsewhere, it [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Overview</strong><br />
<a href="http://www.ning.com/">Ning</a> provide off the peg hosted social networks. The service is free unless you pay to not have their context-driven ads on your pages. Within a few minutes of sign-up you&#8217;re away.</p>
<p>Particulary cool is that they will let you at the source of your network. You can&#8217;t then wander off and run it elsewhere, it sits atop of their core web framework that you can&#8217;t see. With the source (which is encouragingly well written PHP) you can do perform all manner of modifications to bend the template network to your will.</p>
<p>Ning provide their own authentication system, and there&#8217;s no API to hook in someone else&#8217;s which is a hassle if you&#8217;re trying to build a social network alongside another site: maintaining a login for each site is going to annoy the users and be a nightmare to manage. Nil points.</p>
<p>One solution is to build a <a href="http://en.wikipedia.org/wiki/Single_sign-on">single sign-on</a> system around what Ning already provide, which is robust, tested and better presented than anything we could achieve! I&#8217;d sketched out such a system for a proposal years ago but never had the opportunity to build it. A current project provided the perfect excuse to try this out.</p>
<p><strong>Layout</strong><br />
<a href="http://www.zomo.co.uk/wp-content/uploads/2008/08/ning-sso.png"><img src="http://www.zomo.co.uk/wp-content/uploads/2008/08/ning-sso.png" alt="" title="ning-sso" width="300" height="197" class="aligncenter size-medium wp-image-96" /></a><br />
<strong>Operation</strong><br />
The numbers here match those in the diagram.</p>
<ol>
<li>User visits <em>www.example.com</em> (which for us happens to be a <a href="http://www.rubyonrails.org/">Rails</a>) site.</li>
<li>The PageController notices the browser supplied no cookie and must therefore log on to Ning before proceeding. The site returns a redirect to Ning&#8217;s authentication page.</li>
<li>The browser follows this redirect to Ning.</li>
<li>Ning authenticates the user. The login code is modified from the original Ning behaviour. Here, it issues a redirect to <em>sso.example.com</em> with some parameters, including the user&#8217;s Ning ID and a salted hash to prevent spoofing. In this redirect Ning sets a range of cookies, including one that identifies the user to Ning.</li>
<li>The browser follows this redirect to the SSO server (which happens to be a <a href="http://merbivore.com/">Merb</a> site &#8211; I wanted to try it out!)</li>
<li>The SSO app checks the provided hash against its own idea of what it should be. Assuming they match it considers the Ning ID to be valid. Finally, the SSO app issues another redirect along with cookies for just <em>.example.com</em>. This cookie identifies the user to the external site</li>
<li>In passing, the SSO app keeps track of users it has seen, and if this is a new user it will make an API request to Ning to fetch that user&#8217;s profile data and create a matching user on the <em>www.example.com</em> site.</li>
<li>The browser follows this last redirect back to Ning. It could be back to <em>www.example.com</em> or Ning  depending on the situation.</li>
<li>Ning knows who the user is by merit of its cookies.</li>
<li>As does our external site.</li>
</ol>
<p><strong>Notes</strong></p>
<ul>
<li>Having the SSO app different from the <em>www.example.com</em> site is perhaps a bit baroque. It works because the SSO app issues a cookie for <em>.example.com</em> which the browser will offer to both <em>sso.example.com</em> and <em>www.example.com</em>. In favour of this approach is that the SSO app is simple, and thus less likely to fail during development iterations than the nascent <em>www.example.com</em> site. A failure in the SSO app is bad, becaise it locks people out of Ning too. That Rails and Merb can share session data (and a database) is cool.</li>
<li>The SSO app&#8217;s fetching of Ning profile data allows us to maintain a local version of a user&#8217;s profile to avoid the need to fetch it from Ning every time we need. There&#8217;s a nuance of Ning API authentication that meant I had to write a custom widget (Ning site component) to handle that.</li>
</ul>
<p><strong>Specifics</strong><br />
I was about to paste bits of modified Ning code, but I&#8217;ll need to check if I can under the various blurbs you agree too when signing up! Anyhow, the information above should help answer some of the requests for details from the Ning developers forum.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2008/08/using-single-sign-on-to-integrate-ning-with-an-external-site/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>High Availability Rails Cluster</title>
		<link>http://www.zomo.co.uk/2008/08/high-availability-rails-cluster/</link>
		<comments>http://www.zomo.co.uk/2008/08/high-availability-rails-cluster/#comments</comments>
		<pubDate>Tue, 19 Aug 2008 18:33:30 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[all]]></category>
		<category><![CDATA[sw]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://tech.zomo.co.uk/?p=38</guid>
		<description><![CDATA[I&#8217;ve been asked about this a few times, so I figured I&#8217;d post here. This is a brief description of a highly available Rails cluster I&#8217;ve built. Some preliminaries:

There&#8217;s no invention here, I believe this setup is very common.
High availability isn&#8217;t the same thing as load balanced. There is nothing here to intelligently shared load [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been asked about this a few times, so I figured I&#8217;d post here. This is a brief description of a highly available Rails cluster I&#8217;ve built. Some preliminaries:</p>
<ul>
<li>There&#8217;s no invention here, I believe this setup is very common.</li>
<li>High availability isn&#8217;t the same thing as load balanced. There is nothing here to intelligently shared load across the frontend servers, and one backend server is essentially idle all the time.</li>
<li>This cluster is built with a bunch of open-source software on non-fancy kit. As such it doesn&#8217;t have the enormous capacity of clusters built upon commercial shared-storage products, SAN kit, layer 7 web switches etc. Its ambition is to run a few busy Rails sites well whilst coping with hardware failure gracefully.</li>
</ul>
<p><strong>Layout</strong><br />
<img src="http://tech.zomo.co.uk/wp-content/uploads/2008/08/high-availability.png" alt="" title="high-availability" width="253" height="300" class="aligncenter size-medium wp-image-37" /></p>
<p><strong>Operation</strong></p>
<ul>
<li>Web traffic is spread across the managed frontend interfaces by multiple A records in the DNS.</li>
<li><a href="http://www.backhand.org/wackamole/">Wackamole</a> uses a <a href="http://www.spread.org/">Spread messaging network</a> to ensure these multiple A record IPs are always present across the frontend. It achieves this by managing the hosts&#8217; interfaces when it detects hosts joining or leaving the cluster.</li>
<li>A pair of <a href="http://mysql.com/">MySQL</a> servers run in master:master configuration on the backend hosts</li>
<li>The backend hosts use <a href="http://www.drbd.org/">DRBD</a> to maintain a mirrored block device between them.</li>
<li>These block devices back a <a href="http://en.wikipedia.org/wiki/Network_File_System_(protocol)">NFS</a> filesystem.</li>
<li><a href="http://www.linux-ha.org/">Heartbeat</a> runs on the backend hosts to do several tasks:
<ol>
<li>Manage which host is the DRBD primary and therefore can be written to.</li>
<li>Manage which host has the DRBD filesystem mounted and exported with NFS.</li>
<li>Manage the IP through which the frontend mounts the filesystem and talks to MySQL.</li>
</ol>
</li>
<li>With all this in place, <a href="http://nginx.net/">Nginx</a> accepts web connections and serves static assets off the NFS mount and passess other requests to <a href="http://mongrel.rubyforge.org/">Mongrel</a>, a HTTP server that&#8217;s well suited to running a <a href="http://www.rubyonrails.org/">Rails</a> instance.</li>
</ul>
<p><strong>Notes</strong>
<ul>
<li>One of the main hazards of MySQL master:master setups is primary key collision if an INSERT occurs on both hosts at once. We avoid that here by letting Hearbeat manage the IP that the frontends connect to.</li>
<li>I&#8217;ve built two of these clusters to date. The second one is now four servers wide on the frontend.</li>
</ul>
<p><strong>Future work</strong>
<ul>
<li>DRBD can now run in dual-primary mode, allowing both hosts to accept writes. This makes it a candidate for filesystems like <a href="http://www.redhat.com/gfs/">GFS</a> that use shared storage to present a filesystem that can be written to on multiple hosts. More <a href="http://www.drbd.org/users-guide/ch-gfs.html">here</a>.</li>
<li>To add some load balancing I&#8217;m considering using <a href="http://haproxy.1wt.eu/">HAProxy</a> or <a href="http://www.linuxvirtualserver.org/">LVS</a> to actively distribute traffic across the frontends.</li>
<li>HA aside, there&#8217;s also some cool things like <a href="http://swiftiply.swiftcore.org/mongrel.html">evented Mongrel</a> that it would be interesting to try.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2008/08/high-availability-rails-cluster/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Moving Dictionary.app</title>
		<link>http://www.zomo.co.uk/2008/05/moving-dictionaryapp/</link>
		<comments>http://www.zomo.co.uk/2008/05/moving-dictionaryapp/#comments</comments>
		<pubDate>Fri, 02 May 2008 08:21:46 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[all]]></category>
		<category><![CDATA[sw]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[Yak shaving]]></category>

		<guid isPermaLink="false">http://tech.zomo.co.uk/?p=34</guid>
		<description><![CDATA[OS X does a good job of tracking what applications are where and what they do. I have little idea how this works, but if I move VLC.app into a new home then all the files that open in VLC still work. Great. I imagine it involves FSEvents and gobs of XML somewhere.
However the magic [...]]]></description>
			<content:encoded><![CDATA[<p>OS X does a good job of tracking what applications are where and what they do. I have little idea how this works, but if I move VLC.app into a new home then all the files that open in VLC still work. Great. I imagine it involves FSEvents and gobs of XML somewhere.</p>
<p>However the magic doesn&#8217;t touch everything. I was so bold as to move Dictionary.app from its default home in<code> /Applications</code> into the <code>Utilities</code> subdirectory. This broke the Ctrl-Cmd-D system-wide (Cocoa-wide?) lookup box. I don&#8217;t use it <em>that</em> much but that irked me nonetheless.</p>
<p>Console logs included this:</p>
<blockquote><p><code>com.apple.launchd[335] (com.apple.DictionaryPanelAgent[490]): posix_spawn("/Applications/Dictionary.app/Contents/SharedSupport/DictionaryPanel.app/Contents/MacOS/DictionaryPanel", ...): No such file or directory</code></p></blockquote>
<p>Clearly something thinks it knows where the nested DictionaryPanel application should live. This thing is a <code>launchd</code>-managed process used by the keyboard shortcut, configured out of <code>/System/Library/LaunchAgents/com.apple.DictionaryPanelAgent.plist</code>.</p>
<p>The hoojah to tweak this does of course involve XML:</p>
<blockquote><p><code><br />
$ launchctl unload /System/Library/LaunchAgents/com.apple.DictionaryPanelAgent.plist</code></p>
<p><code>$ plutil  -convert xml1 -o - /System/Library/LaunchAgents/com.apple.DictionaryPanelAgent.plist  | perl -pe 's|/Applications/Dictionary.app/|/Applications/Utilities/Dictionary.app/|;' > /var/tmp/com.apple.DictionaryPanelAgent.plist</code></p>
<p><code>$ plutil -lint /var/tmp/com.apple.DictionaryPanelAgent.plist<br />
/var/tmp/com.apple.DictionaryPanelAgent.plist: OK</code><br />
<code><br />
$ plutil -convert binary1 /var/tmp/com.apple.DictionaryPanelAgent.plist</code></p>
<p><code>$ mkdir /Library/LaunchAgents-orig</code></p>
<p><code>$ sudo mv /System/Library/LaunchAgents/com.apple.DictionaryPanelAgent.plist /Library/LaunchAgents-orig &#038;&#038; sudo cp /var/tmp/com.apple.DictionaryPanelAgent.plist /System/Library/LaunchAgents/com.apple.DictionaryPanelAgent.plist</code></p>
<p><code>$ launchctl load /System/Library/LaunchAgents/com.apple.DictionaryPanelAgent.plist</code></p>
</blockquote>
<p>The last step was intended to make the change work this session, but it didn&#8217;t work. The DictionaryPanelAgent still loads but didn&#8217;t do anything until logged out and in again. I think this is something to do with <code>launchctl</code> domains / sessiontype. Blunder factor is high.</p>
<p>This violates the &#8220;don&#8217;t frig with stuff in <code>/System</code>&#8221; principle but I don&#8217;t know how else to solve it. The modified plist could go in <code>/Library/LaunchAgents</code> of course, but I&#8217;d still need to disable the system version (with <code>launchctl unload -w</code>) which is equally naughty. I think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2008/05/moving-dictionaryapp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ZFS on FreeBSD</title>
		<link>http://www.zomo.co.uk/2008/01/zfs-on-freebsd/</link>
		<comments>http://www.zomo.co.uk/2008/01/zfs-on-freebsd/#comments</comments>
		<pubDate>Wed, 30 Jan 2008 16:42:58 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[all]]></category>
		<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://tech.zomo.co.uk/?p=30</guid>
		<description><![CDATA[&#8230; rocks! However, some early VM-related kernel panics &#8211; kmem_map too small panic &#8211; knocked confidence a bit. Seems ZFS really nails the kernel&#8217;s memory demands.
Happily &#8220;the vm_kern.c.2 patch&#8221; (it&#8217;s well known!) sorted things. I stressed ZFS-backed IO massively without any further wobbles.
Now I can micro-quota all my jail(8)s with obsession!
]]></description>
			<content:encoded><![CDATA[<p>&#8230; rocks! However, some early VM-related kernel panics &#8211; <code>kmem_map too small</code> panic &#8211; knocked confidence a bit. Seems ZFS really nails the kernel&#8217;s memory demands.</p>
<p>Happily <a href="http://people.freebsd.org/~pjd/patches/vm_kern.c.2.patch">&#8220;the vm_kern.c.2 patch&#8221;</a> (it&#8217;s well known!) sorted things. I stressed ZFS-backed IO massively without any further wobbles.</p>
<p>Now I can micro-quota all my <code>jail(8)</code>s with obsession!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2008/01/zfs-on-freebsd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
