Launching services after Vagrant mount

tags = [, , , , ]

I recently had to set up a Vagrant project where all the configuration files for services like nginx, supervisor, mysql where symlinks pointing to files residing on the Vagrant synced folder. This turned out to be a bit of a problem, when the Vagrant box boots, one of the last things it does is mount the synced folder, so those services would fail to start because of missing configuration files.

To fix the problem you need to ensure that all services are started after Vagrant had the chance to mount the synced /vagrant/ folder and to do this there are a couple of ways depending on the type of init script that the service has.

Upstart

There is an upstart event that Vagrant emits each time it mounts a synced folder that is called vagrant-mounted so we can modify the upstart configuration file for services that depend on the Vagrant synced folder to listen and start after the vagrant-mounted event is emitted.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# nginx
description "nginx http daemon"
author "Silviu Tantos "

# Listen and start after the vagrant-mounted event
start on vagrant-mounted
stop on runlevel [!2345]

env DAEMON=/usr/sbin/nginx
env PID=/var/run/nginx.pid

expect fork
respawn
respawn limit 10 5

pre-start script
        $DAEMON -t
        if [ $? -ne 0 ]
                then exit $?
        fi
end script

exec $DAEMON

System-V

If you are not running Ubuntu as the guest OS or you don’t want to convert your init script to upstart, there’s still hope, albeit a bit more complicated. Underneath Vagrant uses VirtualBox’s shared folder for it’s synced folder so we can hook-up to udev events and trigger a script execution after the VirtualBox mount event has fired, this of course will also works for VirtualBox’s shared folder not just for Vagrant’s synced folders.

Finding out the udev event

This step is not needed as I already wrote the udev rule, it’s just to show how I came up with it. If you’re not interested in it just skip to writing the udev rule.

Fire up a terminal and listen to udev events:

1
2
3
root@vagrant:~# udevadm monitor --property --kernel
monitor will print the received events for:
KERNEL - the kernel uevent

Fire up another terminal and trigger a mount:

1
root@vagrant:~# mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` /vagrant /vagrant

Now we should see the event in the first terminal window:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
root@vagrant:~# udevadm monitor --property --kernel
monitor will print the received events for:
KERNEL - the kernel uevent

KERNEL[4234.545610] add      /devices/virtual/bdi/vboxsf-13 (bdi)
ACTION=add
DEVPATH=/devices/virtual/bdi/vboxsf-13
SEQNUM=1407
SUBSYSTEM=bdi
UDEV_LOG=3

Writing the udev rule

We can see that the subsystem is bdi and the action is add so we can write a udev rule for the event. I use /etc/udev/rules.d/50-vagrant-mount.rules as the file name and path.

1
2
3
4
# Start on mount
SUBSYSTEM=="bdi",ACTION=="add",RUN+="/usr/bin/screen -m -d bash -c 'sleep 5; /etc/init.d/nginx start'"
# Stop on unmount
SUBSYSTEM=="bdi",ACTION=="remove",RUN+="/usr/bin/screen -m -d bash -c 'sleep 5; /etc/init.d/nginx stop'"

This will run each time a VirtualBox shared folder is mounted. It spawns a screen session (of course you need to have the screen package installed) to prevent the command from being killed by systemd when parent udev exits, sleeps for 5 seconds to make sure Vagrant had the chance to mount the synced folder and exits successfully and finally start the service.

Don’t forget to type in the full paths otherwise udev won’t be able to find the command. For more information consult the udev manual.

Go Top