Vagrant Shell Script Provision

By | December 7, 2017

Vagrant is a tool for quickly creating and starting virtual machines. One of the powerful features of vagrant is its ability to ‘provision‘ the virtual machines it creates. Provisioning involves connecting to the virtual machine and making any necessary installations or config changes. Vagrant can provision a virtual machine in a number of ways, and one of the simplest is to use a shell script. This post looks at how to provision a vagrant virtual machine with a shell script.

Shell Script Provision

Vagrantfile for Shell Script Provision

The vagrantfile controls the setup of a virtual machine. At it’s most basic, your vagrant file needs to specify that it will use a shell script to provision the machine, and the path to the shell script (it is also possible to use in-line shell commands to provision).

This example specifies that a script ‘script.sh’ will be used to provision the vagrant machine. This script will be run by vagrant once the basic box is created.

# -*- mode: ruby -*-
# vi: set ft=ruby :
# encoding: UTF-8

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.provision "shell", 
    path: "script.sh"
end

Writing New Provisioning Scripts

In many cases the provisioning script will be capturing a series of commands that would otherwise be typed in at the command line.

I suggest logging in to an un-provisioned virtual machine to test out the commands and scripts. This will help reveal any major version, dependency or permissions problems as before you write your provisioning script.

There are a few differences between running a script from within the machine and running the script via the vagrant provisioning, including;

Passing Arguments

If you need to pass arguments to your provisioning script, you can do this with an additional parameter for the provisioner ‘args’, which takes a string of space-separated values, just like they would be supplied at the command line. For example args: “argument_1 argument_2”.

In the following example I pass a url and a software version as arguments to the shell script.

# -*- mode: ruby -*-
# vi: set ft=ruby :
# encoding: UTF-8

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.provision "shell", 
    path: "script.sh",
    args: "http://math.nist.gov/oommf/dist/oommf20a0_20170929.tar.gz 8.6"
    config.vm.provider "virtualbox" do |v|
  v.gui = true
end
end

Changing Permissions

By default, Vagrant provisions its virtual machines as root. Unless you specify otherwise, other users of the virtual machine will not be able to access files and folders created by this user.

An Example Provisioning Script

The following is an example of a script for installing a desktop environment and then downloading and installing some additional software.

#!/bin/bash -e
# $1 = oommf source
# $2 = tcl/tk version e.g. 8.6
 
echo "Installing "$1
echo "With tcl/tk"$2

# Update apt
sudo apt-get update -y

# Install a desktop environments
sudo apt-get install --no-install-recommends lubuntu-desktop -y

# OOMMF compilation needs g++ from build-essential package
sudo apt-get install build-essential -y
 
# Install tcl/tk dev packages
sudo apt-get install tcl$2-dev -y
sudo apt-get install tk$2-dev -y
 
# need base tcl to be installed to run
sudo apt-get install tcl -y
 
# Download and unpack oommf version
wget -qO- $1 | tar xvz
 
# Build OOMMF
cd ./oommf
tclsh oommf.tcl pimake distclean
tclsh oommf.tcl pimake

# Change folder permissions
sudo chown -R vagrant /home/vagrant/oommf

 

Multiple Shell Scripts Provision

It can sometimes make sense to divide your provisioning up across multiple scripts. This is largely the same as for single script as you specify an starting or master script for vagrant to begin provisioning with. This script will then need to run the other scripts you need to provision your machine.

In following example I have separated the installation of a desktop environment into one script, and the installation of a piece of software into another.

‘Master Script’

This simple ‘master script’  executes two other scripts with separate functions.

#!/bin/bash -e

exec /vagrant/install_lubuntu.sh
exec /vagrant/install_oommf.sh $1 $2

Desktop Install Script

This script installs a lubuntu desktop on the virtual machine.

#!/bin/bash -e
echo "Installing Lubuntu Desktop"

# Update apt
sudo apt-get update -y

# Install a desktop environments
sudo apt-get install --no-install-recommends lubuntu-desktop -y

Software Download and Compile Script

This script deals with the downloading and installing of some software not in a package manager. It picks up the arguments passed through from the vagrantfile and the ‘master script’.

#!/bin/bash -e
# $1 = oommf source
# $2 = tcl/tk version e.g. 8.6
 
echo "Installing "$1
echo "With tcl/tk"$2

# Update apt
sudo apt-get update -y

# OOMMF compilation needs g++ from build-essential package
sudo apt-get install build-essential -y
 
# Install tcl/tk dev packages
sudo apt-get install tcl$2-dev -y
sudo apt-get install tk$2-dev -y
 
# need base tcl to be installed to run
sudo apt-get install tcl -y
 
# Download and unpack oommf version
wget -qO- $1 | tar xvz
 
# Build OOMMF
cd ./oommf
tclsh oommf.tcl pimake distclean
tclsh oommf.tcl pimake

# Change folder permissions
sudo chown -R vagrant /home/vagrant/oommf