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