Vagrant for the lazies

This post appeared originally in our sysadvent series and has been moved here following the discontinuation of the sysadvent microsite

Personally, I consider the script parameter in a Vagrantfile to be a feature that is not abused enough. It’s got a lot of potential - every script can have a parameter (or several). Modifying your Vagrant use to include this gives you a more flexible and reliable way of quickly deploying some test nodes.

That automation thing

While juggling around with Vagrant and provisioning boxes for the local test environment - which certainly is a lot of fun - I found myself deploying the same scripts on new hosts all the time. Even worse: when being lazy I just quickly installed the necessary tools manually.

When I repeat a certain task often enough, it crosses a border where it gets annoying. Annoying enough to be dealt with (that border is quite low actually). And I’d like to spend that time rather doing something else.

The idea is that a few small scripts could customize and generalize the installation of components on vagrant nodes very quickly - in the same way every time. Vagrant provides support for this through the script parameter in the Vagrantfile. By running scripts like this on a newly provisioned host, we can do pretty much anything we want with only a basic knowledge of bash.

These scripts are just quickly whipped together to deal with the repeating steps involved in repeatedly creating hosts with similar configurations. It is way below the level of complexity or capability of what you get with larger Configuration Management tools like Ansible, Chef and Puppet. At a certain level of complexity and with certain requirements, it might make more sense to integrate these tools instead of using custom scripts. But the simplicity of this solution might make it easier for beginners to reach at least some level of automation without diving into the deep waters of the full-blown configuration tools.

All of the code is available at GitHub, with examples.


The scripts

In the Vagrantfile, the following lines should look familiar:

client.vm.provision :shell,
  path: "some_script.sh",
  :args => [ "arg1", "arg2" ]

They basically pass a script including parameters to Vagrant and run the script on the host.

And this can be abused.

The structure

For this example the local Vagrant installation is combined with a VirtualBox. The basic principles are easy to understand and can be used in other setups.

boot.sh
The core of the setup is the file boot.sh. It handles all parameters and includes all the necessary files. (You’ll find this file and all of the other files included in the in the Git repository mentioned in the beginning and at the end of the article). The script parses parameters and controls the order in which optional updates, host files and other installations take place. It is also responsible for including the id_distro.sh.
id.distro.sh
Then there’s Santa’s little helper: id.distro.sh. It provides some basic id-ing of the distro and allows other scripts to use the right distro-specific commands. If you need to support another distro, add specifics in this file.
host_update.sh
The host_update.sh, does what you’d guess from the name - it updates the installed packages on the system.
bs.<fqdn>.sh:
host specific installation files can run any kind of custom command on the host-level. They need to be named following the pattern bs.<fqdn>.sh.
install_tags.sh
The install_tags.sh file handles the tags structure. These are basically directories with init-files. These init-files install a component on a host, they are not System V init-files. I usually use this like you would use Puppet Modules or Chef Cookbooks and either install and configure a single component or multiple (E.g. syslog, nfs-server, dhcp, etc.). By just including the tags as parameters, we include these automatically in the bootstrap process.

The name of the directory must be identical to the tag to use, e.g. the tag webserver will trigger the file ./webserver/init.sh. In the example code you’ll find a setup for a (very basic) web-server installation. Also in the example: the directory tools and the required init.sh, which installs some generic basic tools.

./hosts/bs.u1404.example.com  # Hostfile for host u1404.example.com
./tools/boot.sh               # The Main process
./tools/host_update.sh        # Update script
./tools/id_distro.sh          # Santa's helper
./tools/init.sh               # Tools-init script (install-tag)
./webserver/init.sh           # webserver-init script (install-tag)
boot.sh pulling it all together
The initial script called from Vagrantfileis the boot.sh script. It starts by parsing parameters and gathering general information and then sets some environment variables.
  • If the hostname parameter has been set as well, the specific host-file is included and included commands are executed.

  • Then the rest of the installation tags are run, installing specific tools or more general applications.


An example

Depending on the parameters given in the Vagrantfile, the hosts will be setup differently using the method described above.

Node 1

The following Vagrant configuration will

  • Upgrade all packages on the host
  • do nothing else (because the example setup does not provide a bs.plain.example.com.sh bootstrap file)
host.vm.provision :shell,
  path: "bootstrap/tools/boot.sh",
  :args => [
    "-h plain.example.com",
    "-u"

Node 2

The following Vagrant configuration will

  • Upgrade all packages on the host.
  • Install a web-server.
  • Install custom tools
  • Run the commands in bs.u1404.example.com.sh.
host.vm.provision :shell,
  path: "bootstrap/tools/boot.sh",
  :args => [
    "-h u1404.example.com",
    "-u",
    "-i webserver",
    "-i tools"

Future improvements

As always, there’s still some space for improvements:

  • Support more distributions, and make the scripts as distro agnostic as possible.

  • The code structure could probably require some restructuring.

The code is available at GitHub, and I would love it if you play around with it and send me pull-requests if you improve or extend ‘vagrant-lazy’.

Containerized Development Environment

Do you spend days or weeks setting up your development environment just the way you like it when you get a new computer? Is your home directory a mess of dotfiles and metadata that you’re reluctant to clean up just in case they do something useful? Do you avoid trying new versions of software because of the effort to roll back software and settings if the new version doesn’t work?

Take control over your local development environment with containerization and Dev-Env-as-Code!

... [continue reading]

Ansible-runner

Published on February 27, 2024

Portable Java shell scripts with Java 21

Published on February 21, 2024