Installing on my Mac at home

I’m in the office and I want to start installing some software on my laptop at home so it’s ready to try when I get back to my laptop. (The test suite is running and I know the install will take a while, so it can get going while I commute!) In particular, I was looking to try Vagrant, which requires VirtualBox.

First step: Back to my Mac. Turns out, if you’re sensible enough to have SSH running on your Mac (enable it under Sharing in System Preferences), it’s available from other Macs where you have your MobileMe account set up. Simply run:

ssh <hostname>.<MobileMe name>.members.mac.com

where <hostname> is the short name of your laptop and <MobileMe name> is your MobileMe login. So, for example:

ssh jura.mathie.members.mac.com

gets me to my laptop. (Interestingly, this doesn’t resolve on hosts where you’re not logged in to your MobileMe account, so there’s some DNS resolution magic going on locally. At least I hope so, and I’ve not just exposed myself on the Internet!)

Next up, let’s grab VirtualBox. Head across to the web site to figure out the latest download URL, and download it with curl:

curl -LO http://[...]/VirtualBox-4.0.2-69518-OSX.dmg

Once it’s downloaded, we have to mount the disk image. The simplest way with Mac OS X is to use hdiutil:

hdiutil attach VirtualBox-4.0.2-69518-OSX.dmg

This will mount the disk image on /Volumes/VirtualBox. Now we have to run the installer, which we can do headless:

sudo installer -pkg /Volumes/VirtualBox/VirtualBox.mpkg -target / -verbose

This needs to run as root, hence sudo. Since it’s verbose, it’ll spit out a bunch of progress stuff, because we asked it to be verbose. But that’s it. Thanks to having a standard installer, we can install Mac OS X packages without a GUI. Win.

We should tidy up after ourselves by unmounting the disk image:

hdiutil detach /Volumes/VirtualBox

And we’re done. VirtualBox is installed, and I can get onto the long running download of grabbing the demo Ubuntu 10.04 LTS image for Vagrant (which clocks in at nearly 500MB). Getting started with Vagrant is another story entirely, which I’m sure I’ll talk about sometime soon.

Well, we’re nearly done. Let’s finish up by freaking out whoever’s in the house:

say "We're watching you!"

:-)

Using SagePay in your Ruby Projects

Once upon a time, in a galaxy far, far away … Ok, I’ll stop now. A few years back, I was working on a client project and they needed to integrate with a billing platform. They’d already picked Protx (now SagePay) as their platform of choice, and in particular, the Server variant. Wait, I’ll backtrack. SagePay has three variants:

  • Form which is basically just sticking a random form/button on your web page that redirects to SagePay’s servers and redirects back afterwards. Useful if your budget is low, you don’t have a web developer on hand and your requirements are utterly trivial.

  • Server which is more full featured, and allows much finer control of the billing process, including delayed billing, recurring subscriptions, that kind of thing. It’s a little more involved, but you still don’t capture the credit card details themselves (that is still a redirect step to SagePay’s servers) so you get to sidestep the painful parts of PCI-DSS compliance. Which you want to do, unless you have a bucketload of money and want to be labelled clinically insane.

  • Direct which involves you doing the store/forward of the credit card details. Its the ultimate in flexibility and doesn’t tie you to SagePay in the long term (say, because they have all the CC numbers for your recurring payments!). Choosing this option, however, is one of the criteria for free entry to the PCI DSS loony bin.

I’d previously built an integration for a client with Protx Form, and had modified ActiveMerchant to support it (forked here, not that the patch ever got merged, but n’mind). So, naturally, the second time, I reached for ActiveMerchant again and started hacking away. Unfortunately, SagePay Server’s model doesn’t really work with ActiveMerchant because it’s half way between an integration and a gateway. We struggled on and got that working (see this fork here). (That patch was never merged back upstream either, but I’m less surprised by that.)

Fast forward a couple of years, and another client wants an integration with SagePay. Their requirements are more complex in that its a SaaS offering which requires flexible recurring billing, so the Server version definitely fits well. But this time I’ve decided for sure that AM is not a good fit.

So we start from scratch and model SagePay Server’s API natively in Ruby. The sage_pay gem is the result of our efforts. There’s also an example Rails application using most of it’s features just so you can see what’s happening. Its all available under a liberal license, so you’re free to do what you like with it. I’d love to here from you if you use it. I’d also be utterly delighted to accept patches and improvements.

Documentation is a little sparse so far, so your best bet is to check out the sample app and work from there. I’d be particularly happy to accept pull requests that contain documentation. ;-)

(Oh, and while I’m on the subject of ActiveMerchant forks that never made it back upstream, here’s one for Barclays ePDQ too.)

Converging your Home Directory with Chef

In this tutorial, I’ll take you through using Chef and Homebrew to manage your home directory in Mac OS X. I’ve also included a neat cookbook which will allow you to use Homebrew as your native packaging system in Chef.

TL;DR

  • Chef is awesome.

  • You can grab the cookbook to use Homebrew as the native packaging system for Chef on GitHub at chef-homebrew.

  • Managing your configuration isn’t just for servers.

  • If you spend any time at a command line, you owe it to yourself to use tmux (or screen).

  • The formatting of the code samples on this post is a work in progress… Sorry.

Getting Started with Chef

Mac OS X, and the current breed of open source developer tools (notably Homebrew and RVM) introduce an interesting possibility when it comes to managing one’s home directory. These mechanisms allow you to install arbitrary packages, owned and run by your own user.

So, you’ve got a package manager which installs software and allows you to start/stop services. You’ve got a bunch of configuration files, both for those services, and dotfiles in your home directory. What’s the best way to manage these? With some sort of configuration management tool, of course! There’s plenty to choose from (including lcfg, cfengine and Puppet) but the one I’ve been working with on and off for the past couple of years is Chef.

How do you get started? Well, personally, I’d just choose one piece of configuration to manage. Let’s say, for example, that you want to manage your tmux configuration. Let’s create a cookbook for that. Start with a repository:

mkdir personal-chef
cd personal-chef
touch README
git init
git add .
git commit -m "First post."

I like to use bundler to manage gem dependencies. There’s only one dependency right now — chef — but we might as well start out sensibly. Create a Gemfile in the root of your repository and give it the following content:

source :rubygems
gem 'chef'

Save that and run:

bundle

which will install chef & its dependencies. You might want to noodle around with a .rvmrc to get an isolated gemset for the project too (I do), but that’s very much a personal taste thing (that I’ll cover in another post).

Now let’s create a really basic configuration for chef-solo to allow it to put things in the right place, and to find its roles & cookbooks. Create a config folder in your new repository and add the following to config/solo.rb:

root_path = File.expand_path(File.join(File.dirname(__FILE__), '..'))
 
cookbook_path   File.join(root_path, 'cookbooks')
role_path       File.join(root_path, 'roles')
 
# Move all the state stuff from /var/chef. I wish there was a single config
# variable for this!
state_root_path = File.expand_path('~/.chef/state')
file_cache_path  "#{state_root_path}/cache"
checksum_path    "#{state_root_path}/checksums"
sandbox_path     "#{state_root_path}/sandbox"
file_backup_path "#{state_root_path}/backup"
cache_options[:path] = file_cache_path

I haven’t caught all the paths pointing to /var/chef but it has been enough for chef to stop whining at me so far. ;-)

Now let’s create ourselves some data that tells chef what we want to do with ourselves. As the configuration grows larger, I’m probably going to want to introduce roles, but let’s keep it simple for now. Create config/mathie.json (adjust to taste!) and fill it in with the following:

{
  "run_list": [ "recipe[tmux]" ]
}

Very simple for now. The final bit of context we’re going to want before we get to the interesting bits is a quick script to run chef. Here’s one I prepared earlier, called converge.sh:

#!/bin/bash
chef-solo -c config/solo.rb -j config/mathie.json $*

(That should probably be bundle exec chef-solo but it failed the time I tried it, and I haven’t yet tracked down why.) Make it executable:

chmod +x ./converge.sh

Add that lot to your git repository and commit if you haven’t been doing so already (little and often!). The last thing we need to do before we can verify the machinery is working is create a skeleton for the cookbook itself:

mkdir -p cookbooks/tmux/recipes
touch cookbooks/tmux/recipes/default.rb

All being well, the next thing we can do is test that it’s all wired up correctly:

./converge.sh

which should spit out ~6 lines from chef saying that it’s starting, finishing and tidying up. If that doesn’t work so well, try:

./converge.sh -l debug

(which is why we stuck the $* on the end of the chef-solo invocation in there!) and see if you can see what’s going wrong. If you can’t, drop me a comment and I’ll see if I can help!

Converging on tmux

So, we’ve got the infrastructure in place. Next thing we need to figure out is installing packages. Chef has some neat separation between what it refers to as ‘resources’ and ‘providers’ so that, in your recipes, you can say:

package 'tmux'

and it will do the right thing, no matter what platform you’re on. Unfortunately, Chef doesn’t ship with the ability to manage packages with Homebrew. That’s why I come in. I’ve put together a cookbook which will install homebrew if it doesn’t already exist, keep it up to date and, most importantly, hook into Chef to use Homebrew as the native package manager. Let’s pull that wonderful cookbook in using git’s subtree merge strategy (which, since we’re DevOps Ninjas, in this situation, is pretty much the way forward):

git remote add -f homebrew git://github.com/mathie/chef-homebrew.git
git merge -s ours --no-commit homebrew/master
git read-tree --prefix cookbooks/homebrew -u homebrew/master
git commit -m "Pull in mathie's awesome Homebrew cookbook."

(If I’ve just lost you, or you’re not using Git, head to https://github.com/mathie/chef-homebrew and stick the contents of that repository in cookbooks/homebrew.)

Now we should be good to go with getting tmux installed through Homebrew. Edit cookbooks/tmux/recipes/default.rb so that it contains:

include_recipe 'homebrew'
package 'tmux'

Save and commit (early and often!). Now run ./converge.sh. It should bumble around for a bit, installing Homebrew if you haven’t got it already, and installing tmux using Homebrew. Run it again, and it shouldn’t do a whole lot. Win.

Converging a tmux configuration

Last thing we’re going to do here, just to demonstrate managing configuration too, is installing a managed ~/.tmux.conf file. Add the following to cookbooks/tmux/recipes/default.rb:

template "#{ENV['HOME']}/.tmux.conf" do
  source "tmux.conf.erb"
end

and create cookbooks/tmux/templates/default/tmux.conf with your favourite tmux configuration. Let’s say, for example, that you’re on Mac OS X and you want to know the current battery level in your status bar:

set -g status-right "#[fg=green]#(pmset -g ps |awk 'BEGIN { FS=\"\t\" } /InternalBattery/ { print $2 }')"

(kinda useful, huh?) Now run:

    ./converge.sh

and your tmux configuration will magically be installed into ~/.tmux.conf. Neat, huh?

Conclusion

Chef isn’t just for managing your massively scaled production infrastructure. You can use it to manage lots of other things too, including your home directory. The win here is magnified with each computer you work with (home desktop, work desktop and a laptop while you’re out and about?).

So, have you tried using Chef to manage your home directory? How did you find it? Good stuff? Bad stuff? What other strategies have you tried?

Update In addition to publishing the Cookbook on Github as chef-homebrew I’ve also uploaded it to the Opscode Cookbooks. Get it here: homebrew.

Equality, Comparison and Uniqueness in Ruby

Ruby has the Comparable module, which, if you implement the spaceship operator <=> (winner of “Best Named Operator” 10 years running!) then it will give you a bunch of comparator operators for free (<, <=, ==, >= and >). Win. Enumerable’s #sort method uses the spaceship operator to do sorting too, so implementing the spaceship gives you a whole bunch of interesting behaviour pretty much for free.

However, while you might think that Array#uniq used ==, or even <=> directly, to implement its uniqueness semantics, you’d be wrong.

First, let’s take a step back. There are a few ways to determine different qualities of equality in Ruby:

  • == is value equality where you consider two values to be equal. So, 1 == 1 or 1 == 1.0.

  • eql? is stronger than == so that in addition to value equality they must have type equality. The above example demonstrates the difference: 1.eql?(1) is true but 1.eql?(1.0) is false.

  • equal? is even stronger still; they must be the same object id. To be honest, the only time I’ve had call to use this is when testing that a DataMapper-style implementation was doing the right thing.

And it turns out that Ruby uses .eql? to determine whether an object is uniq or not.

Here’s the first thing I found slightly surprising: eql? is not implemented in terms of ==. To my mind, it’s an obvious implementation:

def eql?(other)
  self.class == other.class && self == other
end

and there would be faster implementation in C, of course, but I guess there’s a reason it doesn’t do that. Then again, I wonder if that should be:

def eql?(other)
  is_a?(other) && self == other
end

It’s not really obvious from the Pickaxe, and I can’t think of an example to test it with. Anyway, back on track. So, if you’re wanting to customise the way that #uniq works, you’re going to have to implement #eql? on your own class.

And you’re still going to be surprised that doing so doesn’t make #uniq work. See, there’s a bit of a performance optimisation going on here. First of all, it uses #hash to group together potential duplicates, then it uses #eql? to verify that the duplicates are definitely are the same.

So, if you want to customise the way #uniq works for your particular class, you also have to implement #hash. Here’s what I came up with in the end (imagine that nominal_code fully encompasses the object’s identity and ordering if you will):

class NominalAccount
  include Comparable
  def <=>(other)
    nominal_code <=> other.nominal_code
  end

  def eql?(other)
    self.class == other.class && self <=> other
  end

  def hash
    nominal_code.hash
  end
end

Now I can sort and uniqueify collections of these objects through their natural primary key. Win.

Moving Home

So, it’s been a while, hasn’t it?

Notes from a Messy Desk is back to running on WordPress, which is a bit shinier than I remember it. And I’m back to posting, hopefully on a regular schedule. I’ve got a backlog of articles I’m aiming to tidy up and post over the next few weeks, and the interesting stuff I’m doing at FreeAgent Towers means I’ve always got plenty of material to turn into blog posts. :)

Anyhow, if you can see this, the transition has been successful. Unfortunately, I lost the comments on the articles authored in Squarespace because I restored from an old WP backup and transferred the rest across manually.

And it’s still a bit of a work in progress. The theme’s … OK, but nothing special. And FeedBurner seems to be acting up. But we’ll get there.

No longer a Free Agent!

If you’ve been following me on Twitter, you may have heard that my career has taken a slightly different direction in the past few weeks. I’ve been running Rubaidh for over 4 years now and for the most part it’s been a hugely enjoyable experience. I’ve learned a number of new skills both in technology and, most of all, in terms of what’s needed to run a successful business. I’ve also had the opportunity to work with a lot of really awesome people and on a number of great projects.

However, last year was pretty tough. I know it was tough for everyone, what with the media exacerbating a blip in the economy, but there were a couple of particular incidents (that I won’t go into because it wouldn’t be professional to do so) which made me decide if that’s how people do business, I really don’t want to do business.

Also, in general, I was spending more time stressing about money, pitching for new work and dealing with paperwork than I was doing the two things I love best:

  • writing great software; and
  • spending quality time with my family.

The latter, in particular, was suffering, and it wasn’t fair on Annabel & Malcolm. So at the start of this year, I quietly started looking for a new job.

And I’ve really landed on my feet. On Thursday, I started working at FreeAgent Central, who have created an awesome online accounting system for small businesses and freelancers. I’ve been a happy customer of FreeAgent for a couple of years now, and I already know that there’s an awesome team of people behind the project, so I’m really excited to be working there.

As for Rubaidh, it’s not going to disappear. I’ve still got a number of happy customers who can continue to rely on me to support them. I’ll also still be taking on the odd small project here and there, mostly as an excuse to play around with new technologies, which is sometimes more difficult in a large established application (I reckon it’ll be a wee while before FreeAgent bumps up to Rails 3, for example!).

Hopefully I’ll also have more spare time to contribute back to the open source community again, and to start keeping this blog a bit more up to date… That would be nice.

So. Here’s to new opportunities. 2010 is looking like it’s going to be an awesome year. :-)

(Oh, and if you sign up to FreeAgent Central with my referrer, we both get 10% off our accounts for life. What could be better than that?)

The Ruby Community

Most of you will already know that I am part of the triumvirate who runs the Scottish Ruby Conference (née Scotland on Rails) each year in Edinburgh. We’ve just wrapped up this year’s conference and it has been utterly awesome. I may write more about that later, but that’s not where I’m going today.

On the Saturday morning, I turned up, feeling the last whisky from the night before wasn’t such a great idea as it seemed at the time. Noticing that the battery was very low, I plugged my iPhone into my laptop, which was behind the registration desk, then disappeared off with Mark to eat the breakfasts we’d acquired from Greggs on the way in. From there, we headed straight in to Tim Bray‘s keynote (by the second morning, the conference practically runs itself!). Afterwards, I popped out to pick up my phone, knowing it would have been recharged by then.

Except it wasn’t there.

At first, I figured one of my fellow organisers had thought, “leaving a phone lying around is a stupid thing to do, anybody could steal it!” and pocketed it for safe keeping. A quick check discovered that wasn’t the case.

I logged in to MobileMe, and hit the “Find my iPhone” button. It had been switched off. That’s a little suspicious, because it was switched on and charging when I left it. I sent a message to the phone so that it would say, “This is @mathie’s iPhone. Please could you drop it off at the registration desk when you find it?” When MobileMe does that, it sends an email to the phone’s owner when the message has successfully been delivered. As of Monday evening I still haven’t received that message. Which means it’s still switched off, or the SIM has been removed.

So I’ve lost my iPhone. That’s sad. What’s worse is that I can’t help feeling it was probably one of our delegates (ie one of the Ruby community) who stole it. That really hurts.

Without a mobile phone, I didn’t see much of Twitter on Saturday or Sunday. After my family picked me up from the hotel on Sunday, we went shopping with the express purpose of finding a new iPhone. Turns out I really rely on the device for lots of things. It took a while because O2 seem to be renovating most of their Edinburgh stores. Still, third time lucky, and £570 poorer.

Then I get home and find this: Support @mathie and say thank you. Joe O’Brien, a friend I met through the first Scotland on Rails, had set up a Pledgie to encourage the conference attendees to help me cover the cost of replacing the iPhone. And by that point on Sunday evening, I was nearly half way towards what I’d just paid to replace it!

I cannot believe how kind people in the Ruby community can be! It’s just incredible, and I’m really touched. And that’s definitely the way I’m going to look back on this affair. There may be one or two bad apples in there but the Ruby community as a whole is … I can’t think of one word to described it. Awesome. Incredible. Generous. Kind.

I came to the Ruby community because of Rails. I’m definitely going to stay as a part of the Ruby community because of the people. Thank you, all.