My vagrant setup on OSX

Tags: apple, python, django, plone

I said in using vagrant for developing on OSX: why? that I chose vagrant for setting up my development environment. Now it’s time for some specifics.

Vagrant box setup and location

Per virtual machine, vagrant uses a directory with a Vagrantfile in it. As a convention, I place my vagrant directories as subdirectory inside ~/vm/. The name of the subdirectory (I’ll use “django” as an example in this blog post) is the name I use for the virtual machine. So ~/vm/django/Vagrantfile is the vagrant file for my “django” virtual machine.

I have one other (“barebones”), but I already know I’m also going to make a “php” one for three mysql/php sites that I sometimes do a bit of work on. Those end up in ~/vm/php/ and so.

Everything that’s not in git (/svn/hg/bzr) doesn’t exist, so I’ve versioned my ~/vm/ directory. I ignore (.gitignore) the django/php/barebones directories. The Vagrantfiles in those directories are symlinks to ~/vm/vagrantfile_django and so on. There’s a README.txt to help me set it all up when I move to a new computer.

I also have a fabfile for setting up the (django) box automatically. Some of the things the fabfile does:

Source code location

I edit my code locally on OSX and I prefer to continue doing that. I also sometimes want to copy downloaded files directly to my source code. Or edit images in an OSX image editor.

So: I want to have some part of my directory structure available both in OSX and inside the virtual machine. I’ve handled that in my Vagrantfile. The file is mostly the vagrant-provided default one. The relevant filesystem line is:

# Share an additional folder to the guest VM. The first argument is
# an identifier, the second is the path on the guest to mount the
# folder, and the third is the path on the host to the actual folder.
config.vm.share_folder "v-data", "/vagrant", ".", :nfs => true

This mounts the ~/vm/django/ folder on OSX to /vagrant/ inside the virtual machine (with NFS), making them available on both. I checkout my source code in /vagrant/some_category/some_project on the virtual machine, which ends up as ~/vm/django/some_category/some_project on OSX.

Note that I use checkoutmanager to create and update my svn/git/hg checkouts, so it was simple for me to split its configuration. I have a separate checkoutmanager config for my django virtual machine and one for OSX.

SSH, hostname, username

Vagrant provides a vagrant ssh command that gives you an ssh shell for the virtual machine in whose directory you are. But I don’t want to cd to a directory first. So I set up a hostname and ssh config for my virtual machines. I can do ssh django now to get inside my virtual machine.

In /etc/hosts: django barebones php

In ~/.ssh/config:

Host django
    User vagrant
    ForwardAgent yes

Host barebones
    User vagrant
    ForwardAgent yes

Host php
    User vagrant
    ForwardAgent yes

The User line logs me in as user “vagrant” even though I’m “reinout” in OSX. And “ForwardAgent” lets me re-use my ssh key if I connect to servers from within the virtual machine.

Editing on OSX, running commands on vagrant

I have emacs (emacs server) running all the time and open files in emacs from the commandline. And I want to do git add from the commandline. So I want to be inside the actual OSX source directory when working, not inside some ssh session inside the virtual machine: I cannot access my OSX emacs from there.

All fine, as I’ve set up my directories the right way (see above).

But… what about running commands? Starting django? Running a buildout? I need to do that inside the virtual machine: that’s why I set it up in the first place.

That’s where a tiny utility I made comes in. I use fabric quite a lot. Fabric allows you to execute commands remotely via ssh. Hey, that’s just what I need. I know my own conventions for filesystem placement, so I can figure out whether my shell is inside a vagrant directory (~/vm/django/somewhere/) and how to map that to a directory (/vagrant/somewhere/) inside the right virtual machine (“django”).

You can find my file on github. You need fabric to run it. I’ve set it up as the vc command, named after “Vagrant Command”. So this is what I regulary do with it:

~/vm/django/utils/checkoutmanager $ vc bin/test
[django] Executing task 'run_cmd'
[django] run: bin/test
[django] out: Running tests at level 1
[django] out: Running zope.testing.testrunner.layer.UnitTests tests:
[django] out:   Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
[django] out:   Running:
[django] out: .........................
[django] out:   Ran 25 tests with 0 failures and 0 errors in 0.044 seconds.
[django] out: Tearing down left over layers:
[django] out:   Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds.

It runs the bin/test command inside the correct directory inside the correct virtual machine.

As an extra proof, here’s the pwd (“print working directory”) command output:

~/vm/django/utils/checkoutmanager $ vc pwd
[django] Executing task 'run_cmd'
[django] run: pwd
[django] out: /vagrant/utils/checkoutmanager

Works like a charm!

Closing comments

I’m pretty happy with my setup and with vagrant. It took a few days of finding out the right way to use it, but I’m settled now. The vc command coupled with a good filesystem layout works fine in practice.

And I’m happy that I can now use ubuntu to manage all those pesky OS-level dependencies! And that I can still use all the OSX goodies. logo

About me

My name is Reinout van Rees and I work a lot with Python (programming language) and Django (website framework). I live in The Netherlands and I'm happily married to Annie van Rees-Kooiman.

Weblog feeds

Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):