Building a GuixSD Vagrant box

July 20, 2019

Tools DevOps 

Originally posted at https://tech.labs.oliverwyman.com/blog/2019/07/20/vagrant-box/

I’ve been curious about the use of declarative mechanisms for creating operating systems for some time. In contrast to most configuration management tools which say certain things that will be true and let everything else do what it likes (particular packages will be installed, particular services in a named state, etc), declarative mechanisms declare the entire system, and get rid of almost everything else. This has the advantage that you can strip a system down to just what you need, then easily remove/manage things if you change your mind as to what you need to have.

Nix is the best known of these tools, but I’ve generally found it hard to work with—the simple example from the manual shows a good example of the amounts of magic that I found fiddly. On the other hand, there’s also Guix which does the same sort of thing, but starts from the base of an existing programming language (Guile, an implementation of Scheme, which is a Lisp dialect), which means a lot more of it feels readable (or at least it does to a Lisp fan like myself, even if Guile isn’t quite up to the standards of Clojure).

I’d like to play around with using this for full system configuration (possibly with an eye to implementing the IoT firewall), and so usually I’d just spin up a Virtualbox machine via Vagrant. Except, when I started this, there weren’t any Vagrant boxes available. This surprised me as I’m used to there being Vagrant boxes available for everything (well, every Linux distro at least—Windows usually has been a bit thinner on the ground). Well I guess I’ve got to make one from scratch.

I could just do this by hand or I could take the QEMU image they provide and convert it to Virtualbox format, but neither of those appealed, primarily because I don’t like doing anything complicated by hand (as you often need to redo things if you get something wrong, and that’s really annoying when doing things by hand), but also because I was curious about the processes available for doing this automatically. It turns out that Hashicorp, who make Vagrant, also make Packer, which is a tool for making machine images automatically, and I hadn’t got around to using it before, so this seemed like a good time to learn.

It turns out to be useful, although the turnaround time on making changes is poor as it’s having to spin up an entire VM from scratch each time. Several features make it doable:

You end up testing many of these things manually at first anyway, double-checking the set of commands and then repeatedly making a small set of changes more automatically. This approach meant I could get things right (which I wouldn’t have got from the QEMU image) e.g. adding the Vagrant user and setting it up for passwordless sudo.

However, even having done all of that and published it onto Vagrant Cloud, Vagrant still didn’t know how to manage the box, so many features didn’t work. It turns out there are ‘guest detection plugins’ built-in to Vagrant that tell it how to do various things, and GuixSD isn’t in the standard set. So, Step 2 here is to make a plugin that’ll detect GuixSD and tell Vagrant how to work with it. There’s a good guide on how to do this plus the existing ones are there for you to crib from. I’ve made a plugin that does most things (although the guest additions don’t work yet, so you need to use rsync for shared folders instead).

Now you can easily spin up your own GuixSD box with the following Vagrant config:

Vagrant.require_version ">= 2.1.3" # config.vagrant.plugins support
Vagrant.configure("2") do |config|
    config.vm.box = "palfrey/guixsd"
    config.vagrant.plugins = "vagrant-guixsd-guest"
    config.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: ".git/", rsync__chown: false
end

Source for all of this is in the usual sort of place. Sadly there’s no CI this time, but that’s mostly because AFAIK none of the free ones support Virtualbox (not that I blame them).

Previously: Lego Telepresence bot: how not to try and build one Next: Strife: Using OAuth to make a Discord profile page