Ubuntu – Pre-populate vagrant synced folder contents

ruby-on-railsUbuntuupstartvagrant

I'm currently building an rather complicated server stack (a ruby on rails app) that I want developers to be able to work on without having to install everything themselves. Therefore I use Vagrant to allow them to do that.

The idea is that when you first install the image it will pull the latest sources and installs the dependencies, the sources are exposed by synced folders (a feature built in vagrant) so that developers can commit sources and edit them in their own environment. The Vagrant-box is only for the server.

Synced folder entry in Vagrantfile:

config.vm.synced_folder "gameeso/", "/var/gameeso", :create => "true" 

The image is a Ubuntu server with a upstart script (script is executed on boot and only when internet connection is up) that:

  • Pulls the latest development branch from Github (if folder not exists already)

  • Installs the dependencies (this is done by a script)

  • Starts the server

All this happens in a synced folder. I had some problems with this approach, mainly that Vagrant clears the synced folder on my guest system.
I solved this issue by adding 'sleep 10' in the upstart script, so it can wait until Vagrant sets up the synced folders.

Ofcourse, this is not a safe way to do it (in case booting takes longer than 10 seconds, though unlikely these days, I'd rather not like to find out ;))

My question is: Is there a better way to let the guest-host (the vagrant image) populate a synced folder?

Ofcourse, many thanks in advance!

Best Answer

Vagrant's built-in provisioning features should be a perfect fit for this. There are a whole bunch of ways you could do it, but the simplest is probably to take the guts of your Upstart script and make them a plain shell script. Then, put one of these blocks in your Vagrantfile:

  1. Using an "inline" script. Vagrant will copy the contents from the Vagrantfile into a script in the /tmp directory and execute it.

    $script = <<<SCRIPT
    // The contents of your script go here
    SCRIPT
    
    config.vm.provision "shell", inline: $script
    

    Note that the script here is inside a "heredoc", which means that you need to be careful to make sure that the SCRIPT token which ends the heredoc is in the right place - i.e. on a line by itself, without extra whitespace. (The link about heredoc above does show a way to allow whitespace, but you need to be careful anyway.)

  2. Pointing to a script file. Vagrant will copy this file into the /tmp directory and execute it.

    config.vm.provision "shell", path: "setup.sh"
    

    Note that the path here is relative to the Vagrantfile location. However, the file is not executed from that location, so if you need the file to be in a certain directory, you should follow method #3.

  3. Using an "inline" script that points to a script file. This way, you can execute a script in a chosen location (in the example below, that's in /vagrant after you have done prerequisites like chmod or setting environment variables.

    $script = <<SCRIPT
    chmod +x /vagrant/setup.sh
    cd /vagrant
    ./setup.sh
    SCRIPT
    
    config.vm.provision "shell", inline: $script
    

You could also use a provisioning method that works through a "real" deployment and provisioning system, but depending on your requirements that may be overkill.