Announcing Caryatid

2017-04-05

I wrote a Packer plugin ✨

It’s called Caryatid.

An Atlas is “a support sculpted in the form of a man”; a Caryatid is such a support in the form of a woman.

It lets you manage versions of Vagrant box files on local storage in a “Vagrant catalog” by automatically creating or updating that catalog at the end of your packer build. The catalog will present box version info the same way that Atlas does. In the future, it will support remote catalogs like over SSH as well. It’s basically a plugin that automates this tutorial which walks through manually setting up Vagrant catalogs.

I actually made the 1.0 release almost two months ago, but I haven’t gotten around to making a blog post til now. lol

I had never written a Packer plugin or, indeed, a single line of Go, so I’m pretty happy with how this turned out.

It’s written in Go, so it’s been tested on Windows and macOS, and it should work on Linux as well.

Example

Here is a packer template that uses Caryatid. Note that the weird {{isotime...}} thing in the version variable is specifying a date format of YYYYMMDDhhmmss, not the date itself.

"variables": {
  "boxname": "testbox",
  "version": "1.0.{{isotime \"20060102150405\"}}",
  "description": "a box for testing",
  "catalog_root_url": "file://{{env `HOME`}}/vagrantboxes"
},
"builders": [
  {
    "type": "virtualbox",
    ...<snip>...
  }
]
...<snip>...
"post-processors": [
  [
    { "type": "vagrant", },
    {
      "type": "caryatid",
      "name": "{{user `boxname`}}",
      "version": "{{user `version`}}",
      "description": "{{user `description`}}",
      "catalog_root_url": "{{user `catalog_root_url`}}"
    }
  ]
]

A successful packer invocation would result in a directory structure like this:

$HOME/vagrantboxes
    /testbox.json: the JSON catalog
    /testbox
        /testbox_1.0.0_virtualbox.box: the large VM box file itself

And the testbox.json catalog will look like this. Note that the isotime function call has resulted in a real date (corresponding to the time I was writing this post), which can pass for a very long component of a version number.

{
    "name": "testbox",
    "description": "a box for testing",
    "versions": [{
        "version": "1.0.201704051656",
        "providers": [{
            "name": "virtualbox",
            "url": "file:///srv/vagrant/testbox/testbox_virtualbox_1.0.201704051656.box",
            "checksum_type": "sha1",
            "checksum": "d3597dccfdc6953d0a6eff4a9e1903f44f72ab94"
        }]
    }]
}

You can then set the config.vm.box_url value in a Vagrantfile to point to file://$HOME/vagrantboxes/testbox.json (you may need to expand the $HOME variable to be its actual value, like /home/USERNAME), and Vagrant will pull the box from there. It works with multiple builders - so, if you have a VMware and a Fusion builder in your packer template, it will result in a testbox_virtualbox_1.0.201704051656.box and a testbox_vmware_1.0.201704051656.box, and have both a virtualbox and vmware provider in the resulting Vagrant catalog. Vagrant will choose the latest version of whatever provider is set as the config.vm.provider in the Vagrantfile.

Future

I really want to support remote Vagrant catalogs over SSH. Vagrant is supposed to support scp, but apparently doesn’t bundle a properly-built curl yet. This means you may need to build your own curl that supports scp, and possibly even replace your system-supplied curl with that one, in order to use catalogs hosted on scp with Vagrant. (Note that Caryatid will not rely on curl, so even if your curl is old, we will still be able to push to scp backends; the only concern is whether your system’s Vagrant can pull from them by default or not.)

I also have other ideas, like a WebDAV or S3 mode, that I’m considering.

Bug reports, feature ideas, and pull requests are welcome 🐙