<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Repeatable Systems</title>
	
	<link>http://relistan.com</link>
	<description>Building stuff that works</description>
	<lastBuildDate>Mon, 10 Dec 2012 20:42:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/RepeatableSystems" /><feedburner:info uri="repeatablesystems" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Writing CoffeeScript Modules for Node.js</title>
		<link>http://feedproxy.google.com/~r/RepeatableSystems/~3/bKT-QY48vlY/</link>
		<comments>http://relistan.com/writing-coffeescript-modules-for-node-js/#comments</comments>
		<pubDate>Mon, 10 Dec 2012 20:42:30 +0000</pubDate>
		<dc:creator>relistan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://relistan.com/?p=105</guid>
		<description><![CDATA[If you write a module in CoffeeScript, you probably intend for it to be available to the wider Node.js community and not limit it to working in CoffeeScript projects. This is not hard to do and there are several successful strategies. The chief among these are: Compile to Javascript before pushing to the npm repository, [...]]]></description>
			<content:encoded><![CDATA[<p>If you write a module in CoffeeScript, you probably intend for it to be available to the wider Node.js community and not limit it to working in CoffeeScript projects.  This is not hard to do and there are several successful strategies.  The chief among these are:</p>
<ol>
<li>Compile to Javascript before pushing to the npm repository, so you are just uploading native Javascript</li>
<li>Compile to Javascript on installation, using the coffee-script npm package</li>
</ol>
<p>There are potential advantages to both but for <a href="http://github.com/relistan/troll-opt">Troll-opt</a>, I chose to compile my code at installation time rather than beforehand.  There is not much overhead to doing this and the advantage is that it makes it rather easy to facilitate continuous integration (i.e. with something like <a href="http://travis-ci.org">Travis CI</a>) because you can rely on the configuration in package.json to tell the CI system how to install and run the tests.</p>
<p>Here is all it takes to distribute things this way:</p>
<ul>
<li>Get the right configuration in package.json</li>
<li>Add a .npmignore file and a .gitignore with the right settings</li>
</ul>
<p>The first of those really only involves making</p>
<img src="http://feeds.feedburner.com/~r/RepeatableSystems/~4/bKT-QY48vlY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://relistan.com/writing-coffeescript-modules-for-node-js/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://relistan.com/writing-coffeescript-modules-for-node-js/</feedburner:origLink></item>
		<item>
		<title>CoffeeScript Testing on Travis CI</title>
		<link>http://feedproxy.google.com/~r/RepeatableSystems/~3/W2wVumZFqzc/</link>
		<comments>http://relistan.com/coffeescript-testing-on-travis-ci/#comments</comments>
		<pubDate>Sat, 08 Dec 2012 20:18:25 +0000</pubDate>
		<dc:creator>relistan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://relistan.com/?p=72</guid>
		<description><![CDATA[I have recently been working on Troll-opt, a powerful but simple command line parser for Node.js that was inspired by William Morgan&#8217;s Trollop gem for Ruby.  I wanted to get CI running and Travis CI is a free for open source service that makes continuous integration fairly painless.  It wasn&#8217;t obvious how to get it [...]]]></description>
			<content:encoded><![CDATA[<p>I have recently been working on <a href="http://github.com/relistan/troll-opt">Troll-opt</a>, a powerful but simple command line parser for Node.js that was inspired by William Morgan&#8217;s Trollop gem for Ruby.  I wanted to get CI running and <a href="http://travis-ci.org">Travis CI</a> is a free for open source service that makes continuous integration fairly painless.  It wasn&#8217;t obvious how to get it running with CoffeeScript, though, so here is what I learned.</p>
<p>I had already set up a <code>Cakefile</code> that builds and runs the tests on my project.  I&#8217;m testing with Pivotal&#8217;s Jasmine, which is a lot like RSpec and thus very familiar to me, and a darn nice tool.  In combination with jasmine-node, it works great from the command line, too.</p>
<p>The <code>Cakefile</code> looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span>spawn<span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> require <span style="color: #3366CC;">'child_process'</span>
<span style="color: #009900;">&#123;</span><span style="color: #000066;">print</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> require <span style="color: #3366CC;">'util'</span>
fs      <span style="color: #339933;">=</span> require <span style="color: #3366CC;">'fs'</span>
&nbsp;
spawnAndRun <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>command<span style="color: #339933;">,</span> args<span style="color: #339933;">,</span> callback<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-&gt;</span>
  subproc <span style="color: #339933;">=</span> spawn<span style="color: #009900;">&#40;</span>command<span style="color: #339933;">,</span> args<span style="color: #009900;">&#41;</span>
  subproc.<span style="color: #660066;">stderr</span>.<span style="color: #660066;">on</span> <span style="color: #3366CC;">'data'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>data<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-&gt;</span>
  process.<span style="color: #660066;">stderr</span>.<span style="color: #000066; font-weight: bold;">write</span> data.<span style="color: #660066;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  subproc.<span style="color: #660066;">stdout</span>.<span style="color: #660066;">on</span> <span style="color: #3366CC;">'data'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>data<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-&gt;</span>
  <span style="color: #000066;">print</span> data.<span style="color: #660066;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  subproc.<span style="color: #660066;">on</span> <span style="color: #3366CC;">'exit'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>code<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-&gt;</span>
  callback<span style="color: #339933;">?</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">if</span> code <span style="color: #000066; font-weight: bold;">is</span> <span style="color: #CC0000;">0</span>
&nbsp;
test <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>callback<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-&gt;</span>
  spawnAndRun <span style="color: #3366CC;">'jasmine-node'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">'--coffee'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'spec'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> callback
&nbsp;
build <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>callback<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-&gt;</span>
  fs.<span style="color: #660066;">mkdir</span> <span style="color: #3366CC;">'lib'</span><span style="color: #339933;">,</span> 0o0755
  <span style="color: #000066;">print</span> <span style="color: #3366CC;">&quot;compiling...&quot;</span>
  spawnAndRun <span style="color: #3366CC;">'coffee'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">'--compile'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'--output'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'lib'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'src'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> callback
  <span style="color: #000066;">print</span> <span style="color: #3366CC;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
&nbsp;
task <span style="color: #3366CC;">'test'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'Run all tests'</span><span style="color: #339933;">,</span> <span style="color: #339933;">-&gt;</span>
  test<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
&nbsp;
task <span style="color: #3366CC;">'build'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'Build the Javascript output'</span><span style="color: #339933;">,</span> <span style="color: #339933;">-&gt;</span>
  build<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>There&#8217;s no rocket science there, then.  It just creates a <code>build</code> and a <code>test</code> task that make it easy to invoke from Travis CI.  You could alternatively do this with a custom script, or with commands directly inserted in the Travis CI configuration (see below).  So, on to the actual integration.</p>
<p>First, you need your <code>package.json</code> file to contain some things it might not otherwise.  You need all the things you should have normally, including <code>devDependencies</code> to make sure this module can be built and tested.  But then, I added a <code>scripts</code> section which tells npm and also Travis CI, what to to do test and install this:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #3366CC;">&quot;devDependencies&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span> 
    <span style="color: #3366CC;">&quot;jasmine-node&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;&gt;=1.0.26&quot;</span><span style="color: #339933;">,</span> 
    <span style="color: #3366CC;">&quot;coffee-script&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;latest&quot;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
<span style="color: #3366CC;">&quot;scripts&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #3366CC;">&quot;test&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;./node_modules/.bin/cake test&quot;</span><span style="color: #339933;">,</span>
  <span style="color: #3366CC;">&quot;install&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;./node_modules/.bin/cake build&quot;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span></pre></div></div>

<p>The <code>devDependencies</code> guarantee that CoffeeScript and Jasmine are installed. The install script ensures that our code has been compiled to Javascript and put into the <code>lib</code> directory.</p>
<p>Note the paths.  These assume that you are installing your npm packages locally, hence the <code>./node_modules/.bin</code> path which is where npm puts binaries from installed packages.  The &#8220;test&#8221; command will be invoked by npm when you run <code>npm test</code>.  This ensures that Travis knows how to test your application.</p>
<p>Travis CI uses a YAML file to configure it, called <code>.travis.yml</code>.  We need to tell Travis that we are using Node.js so that it doesn&#8217;t try to build a Ruby project.  Then, we need to tell it which commands to run.  In this case, we are going to install the coffee-script package locally to make sure that cake is in the right path.  The <code>before_script</code> definition will call a script before any tests are run.  <code>before_install</code>, will likewise run before the normal <code>npm install</code> is called on the dependencies in the <code>package.json</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">language<span style="color: #339933;">:</span> node_js
node_js<span style="color: #339933;">:</span>
  <span style="color: #339933;">-</span> <span style="color: #CC0000;">0.8</span>
  <span style="color: #339933;">-</span> <span style="color: #CC0000;">0.6</span>
before_script<span style="color: #339933;">:</span>
  .<span style="color: #339933;">/</span>node_modules<span style="color: #339933;">/</span>.<span style="color: #660066;">bin</span><span style="color: #339933;">/</span>cake build
before_install<span style="color: #339933;">:</span>
  <span style="color: #339933;">-</span> npm install coffee<span style="color: #339933;">-</span>script</pre></div></div>

<p>Be sure to login to Travis and set up your GitHub account and authorize the commit hook from GitHub to trigger it.  This is a few simple steps.  Now, when you push to GitHub, your CoffeeScript should get compiled, and your tests should get run.  Status will be <a href="https://travis-ci.org/relistan/troll.opt">reported on Travis</a>, or optionally via an image you link into your <code>README.md</code> on GitHub.</p>
<img src="http://feeds.feedburner.com/~r/RepeatableSystems/~4/W2wVumZFqzc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://relistan.com/coffeescript-testing-on-travis-ci/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://relistan.com/coffeescript-testing-on-travis-ci/</feedburner:origLink></item>
		<item>
		<title>A Works-Anywhere Config For SSH Tunneling</title>
		<link>http://feedproxy.google.com/~r/RepeatableSystems/~3/rZfIKW8ujfs/</link>
		<comments>http://relistan.com/config-for-ssh-tunneling/#comments</comments>
		<pubDate>Sun, 22 Apr 2012 14:44:02 +0000</pubDate>
		<dc:creator>relistan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://relistan.com/?p=61</guid>
		<description><![CDATA[This is not a new topic but I think this is a novel way of handling it. I&#8217;ve had a number of solutions for SSH&#8217;ing through a jump host over the years. Some have worked better than others.  I recently built a setup that seems to work very well and that I am happy with [...]]]></description>
			<content:encoded><![CDATA[<p>This is not a new topic but I think this is a novel way of handling it. I&#8217;ve had a number of solutions for SSH&#8217;ing through a jump host over the years. Some have worked better than others.  I recently built a setup that seems to work very well and that I am happy with so I thought it was worth sharing.</p>
<p>Generally you have a jump box if you have a remote network of isolated hosts and you want to have a security pinch point on inbound SSH sessions.  You generally fortify the jump host as a bastion host and only allow SSH sessions on the remote internal network when they are inbound from the jump box. This is a fairly common architecture and I&#8217;ve seen it at a score of companies. What becomes a pain is initiating two ssh sessions every time you want to get to a host inside the remote network, or if you want to scp a file, you end up copying it twice.  So people often set up scripts for getting around this and connecting directly to the remote internal host over some kind of SSH tunnel.  Now you either need a config entry for each host, or a remote domain name that you can use to wildcard a &lt;code&gt;Host&lt;/code&gt; entry in your SSH config. But then you are not just typing the hostname each time you connect, you are also typing the domain name.  It&#8217;s annoying.</p>
<p>What I&#8217;ve set up is, I think, much better.  It connects a backgrounded tunnel to the jump host, running a SOCKS proxy.  All future connections are then tested to see if they would work directly, and if so they are connected.  Otherwise they are proxied over the SOCKS tunnel to the jump host.  It&#8217;s simple, and having used it in production now for awhile, it seems to work pretty well.  I don&#8217;t have to use the domain name for the host on the other side of the tunnel, and I don&#8217;t have to manage ssh config records.  Here&#8217;s the only entry you need in your SSH config:</p>
<p><script src="https://gist.github.com/2159451.js?file=ssh-config"></script> </p>
<p>You&#8217;ll want to replace &#8216;username&#8217; and &#8216;jumphost&#8217; with your actual remote username and jump host name.  You may also want an SSH config entry for that host to make sure it uses your RSA key for authentication.  And here is the script that runs it all, to be installed in <code>~bin/ssh-proxy.sh</code>:  </p>
<p><script src="https://gist.github.com/2159451.js?file=ssh-proxy.sh"></script></p>
<p>Enjoy!</p>
<img src="http://feeds.feedburner.com/~r/RepeatableSystems/~4/rZfIKW8ujfs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://relistan.com/config-for-ssh-tunneling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://relistan.com/config-for-ssh-tunneling/</feedburner:origLink></item>
		<item>
		<title>Discovering Pending Rails Migrations With Git</title>
		<link>http://feedproxy.google.com/~r/RepeatableSystems/~3/IipJMAAF5Ew/</link>
		<comments>http://relistan.com/discovering-pending-rails-migrations-with-git/#comments</comments>
		<pubDate>Sat, 31 Mar 2012 13:31:56 +0000</pubDate>
		<dc:creator>relistan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://relistan.com/?p=39</guid>
		<description><![CDATA[At MyDrive, Gavin and I came up with what I think is a pretty novel solution to discovering new Rails migrations at deployment time.  It's often nice to find out about pending migrations right up front.  Sometimes you just don't want to deploy right now if there are pending migrations.]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://mydrivesolutions.com/">MyDrive</a>, <a href="https://twitter.com/#!/gavinheavyside">Gavin</a> and I came up with what I think is a pretty novel solution to discovering new Rails migrations at deployment time. We deploy often but not on every commit.  We usually know about new migrations from reading the commits—but no one is perfect and sometimes you miss a commit or three. The standard checks for pending migrations involve deploying the new code and verifying the schema version against the database before reloading the app. This works but it&#8217;s slow and you don&#8217;t find out about the migrations until the code has been pushed to at least one system. Automating this is still a good idea. But it&#8217;s often nice to find out about pending migrations right up front.  Sometimes you just don&#8217;t want to deploy right now if there are pending migrations.</p>
<p>But, do we need to talk to the DB to find this out? Doesn&#8217;t git tell us what has changed in our code? Why yes, it does.</p>
<p>We tag each deployed ref with a git tag representing the deployment environment (Capistrano stage) and the time and date. This is tells us what code was running in any environment at any time. We now also have a moving git tag that identifies the last deployment to any environment. After each deployment we move the tag to the current <code>HEAD</code> ref. Finding new migrations is now as simple as <code>git diff</code> on the <code>db/migrate</code> tree against the previous deployment tag for this environment. Capistrano does this as part of the deployment and lets us choose to abort if we don&#8217;t want to deploy with migrations. It&#8217;s not perfect: it will generate false positives on any change to any file in the migrations tree, but old migrations are rarely changed. Here&#8217;s what it looks like:</p>
<p><script src="https://gist.github.com/2262674.js?file=migration_detected_with_git.txt"></script> Notably this needs to be done from a clean tree because you will be changing git tags on the local installation. So it should either be done from a deployment host or from a clean checkout of your code. It&#8217;s best to detect this in your deployment scripts as well so that you don&#8217;t get into trouble. If there is interest, we could probably release this as a Capistrano plugin. If you decide to implement it yourself, here are some <a href="https://gist.github.com/2262674">notes on helpful git commands</a> for doing so.</p>
<p><strong>Update: I have released two gems to do this for you.</strong> The first is called <a href="http://goo.gl/av9tE">capistrano-deploytags</a> and handles all of the tagging for you at deployment time.  The second, <a href="http://goo.gl/ICDwm">capistrano-detect-migrations</a> does what I described above.  It requires the functionality from <a href="http://goo.gl/av9tE">capistrano-deploytags</a>.</p>
<img src="http://feeds.feedburner.com/~r/RepeatableSystems/~4/IipJMAAF5Ew" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://relistan.com/discovering-pending-rails-migrations-with-git/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://relistan.com/discovering-pending-rails-migrations-with-git/</feedburner:origLink></item>
		<item>
		<title>HTTP Header Hell Starring X-Real-IP and X-Forwarded-For</title>
		<link>http://feedproxy.google.com/~r/RepeatableSystems/~3/NYa8C6J4mjE/</link>
		<comments>http://relistan.com/http-header-hell-starring-x-real-ip-and-x-forwarded-for/#comments</comments>
		<pubDate>Wed, 15 Feb 2012 20:58:03 +0000</pubDate>
		<dc:creator>relistan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://relistan.com/?p=29</guid>
		<description><![CDATA[It&#8217;s always fun to spend a whole day debugging something that should be simple.  Actually I think it&#8217;s always the things that should be simple that end up in a day of debugging. Sharing tales of woe can sometimes help people. Or at least people can laugh at your misery. Here&#8217;s one such tale. Happy [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s always fun to spend a whole day debugging something that should be simple.  Actually I think it&#8217;s always the things that should be simple that end up in a day of debugging. Sharing tales of woe can sometimes help people. Or at least people can laugh at your misery. Here&#8217;s one such tale.</p>
<h3>Happy Beginnings</h3>
<p>It all starts out like your average fairy tale.  For one of our production apps, we have a setup with a load balancer and some app servers behind it.  In this case the load balancer is HAproxy and the app servers are running Rails with a Sinatra application mounted, all on top of Phusion Passenger on Nginx.  This is a great setup for production systems.</p>
<h3>The Unhappy Middle Bit</h3>
<p>No story that is worth reading has a happy middle, so here&#8217;s where it went wrong.  The load balancer system needs to handle SSL termination which HAproxy does not support.  HAproxy is, however, a great load balancer through which I have in other jobs run absolutely massive traffic without issue.  It has the benefit of actively monitoring your servers so that it knows they are not responding before some request gets hung up checking for you.  It has great capability for routing traffic based on all kinds of HTTP header information.  Finally, it has a great stats page that gives you a lot of live information about the services it is handling.  We wanted to use HAproxy.</p>
<p>There are a number of solutions for running HAproxy where SSL termination is needed. The best of these is this right at hand. Nginx supports SSL termination, is really lightweight, and is event-based.  It scales to massive proportions without much trouble.  At an unnamed previous employer we were doing 35,000 rpm in production through a single Nginx install.  I know Nginx works fine as a load balancer, but it&#8217;s nowhere near as nice to run as HAproxy in production.</p>
<p>But&#8230; one final requirement, self-imposed for purposes of debugging, was that the app server logs actually contain the original source address of the client.  This now means that the original IP address needs to be relayed from Nginx to HAproxy, to Nginx, to Rails and Sinatra.  The easiest way to do that is to set HTTP headers like <em>X-Forwarded-For</em> or <em>X-Real-IP</em> on the load balancer. <em>X-Forwarded-For</em> is more common and lots of things muck with it.  I thought, to avoid trouble, let&#8217;s just use <em>X-Real-IP</em> in the SSL terminator&#8217;s <em>nginx.conf</em>. HAproxy will leave it alone and pass it along to Nginx and Rails/Sinatra on the app servers.  I can have Nginx log it on the app servers and it will be available to put in the <em>production.log</em> as well.</p>
<p><strong>WRONG</strong>.</p>
<p>This all seemed to work fine in Rails.  Just as expected.  Alas, any attempt to connect to the Sinatra apps mounted on the Rails installation resulted in <em>403</em> and an entire page body consisting of the word &#8220;Forbidden&#8221;.  This was from our Sinatra app as well as from Resque-web.</p>
<p><strong>First clue:</strong> connecting directly to HAproxy without going through the SSL-terminating Nginx  works as expected.</p>
<p><strong>Second clue:</strong> a tcpdump of the traffic sent to HAproxy from Nginx shows that both <em>X-Real-IP</em> and <em>X-Forwarded-For</em> are set but only <em>X-Forwarded-For</em> is set by HAproxy.</p>
<p>Poking around with <em>curl</em> and <em>netcat</em> reveals that I only have the problem when both headers are present.  Then after poking at this for awhile I discover that it only doesn&#8217;t work when they are both set and NOT the same.  What&#8217;s going on here?  Well Nginx is diligently setting <em>X-Real-IP</em> as expected, but HAproxy is configured to add <em>X-Forwarded-For</em> (leftover from a previous config).  So <em>X-Real-IP</em> is always the real client and <em>X-Forwarded-For</em> is always the IP address of the load balancer.</p>
<h3>The Happy Ending</h3>
<p>So what? There is a gem you perhaps don&#8217;t know about that is getting invoked in your application stack.  The culprit: <strong>rack-protection</strong>. This gem does a lot of sanity checking and validation on requests headed into a Rack stack. It is included in Rails but something is Rails overrides this particular behavior. Sinatra triggers it, even mounted on top of Rails. Grepping around revealed this test case in <strong>rack-protection</strong>:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">  it <span style="color:#996600;">'denies requests where IP and X-Forward-For are spoofed but not X-Real-IP'</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    get<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'/'</span>, <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span>,
      <span style="color:#996600;">'HTTP_CLIENT_IP'</span>       <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'1.2.3.5'</span>,
      <span style="color:#996600;">'HTTP_X_FORWARDED_FOR'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'1.2.3.5'</span>,
      <span style="color:#996600;">'HTTP_X_REAL_IP'</span>       <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'1.2.3.4'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    last_response.<span style="color:#9900CC;">should_not</span> be_ok
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>So this behavior is a, ermm, &#8220;feature&#8221; of rack-protection.  Knowing is half the battle–or well, all of it.  A quick one-line deletion from the HAproxy config, a new Chef run on the load balancer and we have a working app stack, SSL and all.</p>
<p>You may now either sigh with relief because I&#8217;ve helped you solve the same problem or laugh at my pain. For the therapeutic release of your laughter I do charge a small fee.  Simply post your bank account numbers in the comments section and it will be withdrawn automatically.</p>
<img src="http://feeds.feedburner.com/~r/RepeatableSystems/~4/NYa8C6J4mjE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://relistan.com/http-header-hell-starring-x-real-ip-and-x-forwarded-for/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://relistan.com/http-header-hell-starring-x-real-ip-and-x-forwarded-for/</feedburner:origLink></item>
		<item>
		<title>Kiwi Wikitext Parser at Wikimedia Data Summit</title>
		<link>http://feedproxy.google.com/~r/RepeatableSystems/~3/lSMpmJfHarE/</link>
		<comments>http://relistan.com/kiwi-wikitext-parser-at-wikimedia-data-summit/#comments</comments>
		<pubDate>Wed, 02 Feb 2011 03:09:35 +0000</pubDate>
		<dc:creator>relistan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[C Wikitext PEG Peg/Leg]]></category>

		<guid isPermaLink="false">http://relistan.com/?p=21</guid>
		<description><![CDATA[I will be presenting the Kiwi wikitext parser at the Wikimedia Data Summit at O&#8217;Reilly&#8217;s headquarters in Sebastopol, CA on Friday.  Kiwi is a formal parser written using a PEG and relying on the Peg/Leg tool from Ian Piumarta.  It&#8217;s in C and supports most of MediaWiki&#8217;s syntax in a more or less tolerant manner.  [...]]]></description>
			<content:encoded><![CDATA[<div style="float: right;"><a href="http://relistan.com/wp-content/uploads/2011/02/kiwi.png"><img class="alignnone size-full wp-image-22" title="kiwi" src="http://relistan.com/wp-content/uploads/2011/02/kiwi.png" alt="" width="250" /></a></div>
<p>I will be presenting the <a href="http://github.com/relistan/kiwi">Kiwi</a> wikitext parser at the Wikimedia Data Summit at <a href="http://oreilly.com">O&#8217;Reilly&#8217;s</a> headquarters in Sebastopol, CA on Friday.  Kiwi is a formal parser written using a PEG and relying on the Peg/Leg tool from Ian Piumarta.  It&#8217;s in C and supports most of MediaWiki&#8217;s syntax in a more or less tolerant manner.  This was a side project at AboutUs that <a href="http://github.com/thomasluce">Thomas Luce</a> started one Saturday.  I joined up with him shortly afterward and we have now got a mostly complete parser.  There is a lot of room for improvement, but it is fast, works in semi-production at AboutUs.org, and we hope it is a promising example of what can be done with MediaWiki&#8217;s syntax.  We&#8217;re hoping we can build some community support behind by presenting at the Data Summit.  If you want to check out the parser first hand you should visit <a href="http://drasticcode.com">Sam Goldstein</a>&#8216;s Ruby/Sinatra-based wiki site at <a href="http://kiwi.drasticcode.com">DrasticCode.com</a>.</p>
<p>Kiwi has been released under the permissive BSD 3-clause license and can be found on <a href="http://github.com/relistan/kiwi">GitHub</a>.</p>
<img src="http://feeds.feedburner.com/~r/RepeatableSystems/~4/lSMpmJfHarE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://relistan.com/kiwi-wikitext-parser-at-wikimedia-data-summit/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://relistan.com/kiwi-wikitext-parser-at-wikimedia-data-summit/</feedburner:origLink></item>
		<item>
		<title>Convert Chef Cookbooks to Puppet Modules</title>
		<link>http://feedproxy.google.com/~r/RepeatableSystems/~3/Arj30DkQRXE/</link>
		<comments>http://relistan.com/convert-chef-cookbooks-to-puppet-modules/#comments</comments>
		<pubDate>Wed, 19 Jan 2011 04:03:33 +0000</pubDate>
		<dc:creator>relistan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Chef Puppet Ruby DevOps]]></category>

		<guid isPermaLink="false">http://relistan.com/?p=5</guid>
		<description><![CDATA[What if you, for any number of reasons, needed to convert Chef cookbooks to Puppet modules and it were convenient to do it in an automated way? How hard the task would be to convert the cookbook depends largely on how off the ranch the recipes are with respect to the Chef DSL.  Since Chef [...]]]></description>
			<content:encoded><![CDATA[<p>What if you, for any number of reasons, needed to convert Chef cookbooks to Puppet modules and it were convenient to do it in an automated way? How hard the task would be to convert the cookbook depends largely on how off the ranch the recipes are with respect to the Chef DSL.  Since Chef recipes are just Ruby code, you can write whatever you want into the recipe.  But if the recipes were written in a way that mostly sticks with the Chef DSL you can get fairly clean Puppet output in a really simple way: take advantage of the fact that Chef&#8217;s DSL is Ruby, and write a  system for evaluating the Chef DSL and generating Puppet syntax output.  I found this to be a surprisingly legitimate case for heavy meta-programming as much of the Chef DSL translates pretty well directly to Puppet.</p>
<p>Hopefully no one is ready to start a flame war at this point.  I am not suggesting that anyone use one system or the other.  I recently had the need to convert a lot of site-specific Chef code to Puppet <a href="http://github.com/relistan/chef2puppet">so I wrote a tool </a>to save me a lot of time.  The general approach is to convert as much of the Chef code to a module formatted for use in Puppet as possible.  You will need to edit the module when it is done being converted.  Chef makes an assumption about the relationship between resources based on order.  Puppet does no such thing.  So you will likely need to managed the dependencies yourself.  However, if you specified them explicitly in Chef, they will work in Puppet out of the box in most cases. There are currently only three options you need to specify to run the tool:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">Usage: convert.rb <span style="color: #7a0874; font-weight: bold;">&#91;</span>options<span style="color: #7a0874; font-weight: bold;">&#93;</span>
-c, <span style="color: #660033;">--cookbook</span> COOKBOOK          Chef Cookbook directory <span style="color: #7a0874; font-weight: bold;">&#40;</span>e.g. contains <span style="color: #000000; font-weight: bold;">/</span>recipes, <span style="color: #000000; font-weight: bold;">/</span>attributes...<span style="color: #7a0874; font-weight: bold;">&#41;</span>
-o, <span style="color: #660033;">--output-dir</span> OUTPUT_DIR      Output directory <span style="color: #7a0874; font-weight: bold;">&#40;</span>where modules are written<span style="color: #7a0874; font-weight: bold;">&#41;</span>
-s, <span style="color: #660033;">--server-name</span> SERVER_NAME    The name of the Puppet server to be used <span style="color: #000000; font-weight: bold;">in</span> puppet:<span style="color: #000000; font-weight: bold;">//</span> URLs</pre></div></div>

<p>Here is what the converter handles:</p>
<ul>
<li>Converts cookbooks to a Puppet module directory structure</li>
<li>Converts recipes to mostly-right Puppet manifests in the proper location</li>
<li>Copies templates to the correct location in the Puppet module</li>
<li>Downloads remote_file resources into the Puppet module&#8217;s files directory</li>
<li>Tries to replace Chef&#8217;s node[:some][:var] variables with $some_var format</li>
<li>Edits templates to replace variable substitutions with the same format</li>
<li>Makes an attempt to replace not_if and only_if blocks with Puppet equivalents</li>
</ul>
<p>I am still working with the tool and it will probably evolve over time.  But it has a pretty good success rate now.  Here&#8217;s some sample output:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ .<span style="color: #000000; font-weight: bold;">/</span>convert.rb <span style="color: #660033;">-c</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chef-cookbooks<span style="color: #000000; font-weight: bold;">/</span>cookbooks<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf <span style="color: #660033;">-s</span> localhost.localdomain
Cookbook Name:   xen
Recipes Path:    <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chef-cookbooks<span style="color: #000000; font-weight: bold;">/</span>cookbooks<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>recipes
Templates Path:  <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chef-cookbooks<span style="color: #000000; font-weight: bold;">/</span>cookbooks<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>templates<span style="color: #000000; font-weight: bold;">/</span>default
Files Path:      <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chef-cookbooks<span style="color: #000000; font-weight: bold;">/</span>cookbooks<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>default
Output Path:     <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen
Working on recipe... <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chef-cookbooks<span style="color: #000000; font-weight: bold;">/</span>cookbooks<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>recipes<span style="color: #000000; font-weight: bold;">/</span>default.rb
Working on recipe... <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chef-cookbooks<span style="color: #000000; font-weight: bold;">/</span>cookbooks<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>recipes<span style="color: #000000; font-weight: bold;">/</span>dom0.rb
Fetching <span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>xen-Config.mk from some-bucket.s3.amazonaws.com to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>xen-Config.mk...
Fetching <span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>linux-2.6.31.12.tar.bz2 from some-bucket.s3.amazonaws.com to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>linux-2.6.31.12.tar.bz2...
Fetching <span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>patch-kernel.sh from some-bucket.s3.amazonaws.com to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>patch-kernel.sh...
Fetching <span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>xen-<span style="color: #000000;">3.4</span>-testing.tar.bz2 from some-bucket.s3.amazonaws.com to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>xen-<span style="color: #000000;">3.4</span>-testing.tar.bz2...
Fetching <span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>xen-patches-2.6.31-<span style="color: #000000;">12</span>.tar.bz2 from some-bucket.s3.amazonaws.com to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>xen-patches-2.6.31-<span style="color: #000000;">12</span>.tar.bz2...
Fetching <span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>make-initrd.sh from some-bucket.s3.amazonaws.com to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>make-initrd.sh...
Fetching <span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>initramfs_conf.tar.bz2 from some-bucket.s3.amazonaws.com to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>initramfs_conf.tar.bz2...
Fetching <span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>07_xen from some-bucket.s3.amazonaws.com to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>asdf<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>files<span style="color: #000000; font-weight: bold;">/</span>07_xen...
Modifying template <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chef-cookbooks<span style="color: #000000; font-weight: bold;">/</span>cookbooks<span style="color: #000000; font-weight: bold;">/</span>xen<span style="color: #000000; font-weight: bold;">/</span>templates<span style="color: #000000; font-weight: bold;">/</span>default<span style="color: #000000; font-weight: bold;">/</span>xen-kernel-config.erb...</pre></div></div>

<p>Find it on GitHub: <a href="http://github.com/relistan/chef2puppet">http://github.com/relistan/chef2puppet</a></p>
<img src="http://feeds.feedburner.com/~r/RepeatableSystems/~4/Arj30DkQRXE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://relistan.com/convert-chef-cookbooks-to-puppet-modules/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://relistan.com/convert-chef-cookbooks-to-puppet-modules/</feedburner:origLink></item>
	</channel>
</rss>
