The recent HashiCorp Vagrant 2.2.6 that was released came with a couple of new and interesting features. Dependency provisioners offer a new way to control when your provisioners run for a given guest. Additionally, Vagrant and Vagrant Cloud now offer support for validating the checksum for a published box. In this post, we’ll outline these two new features of Vagrant.

Dependency Provisioners

Provisioning has always been a core feature of Vagrant. There are many different kinds of provisioners today that use different tools to help set up and configure a Vagrant guest. However, until the introduction of Dependency Provisioners, Vagrant was only able to run provisioners in the "linear" order that they are defined within a Vagrantfile. Vagrant does not evaluate Vagrantfiles strictly top to bottom which can result in some surprising behavior. Take this Vagrantfile for example:

“`ruby
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/bionic64"

config.vm.provision "A", type: "shell", inline:<<-SHELL
echo ‘A’
SHELL

config.vm.define "guest" do |guest|
guest.vm.provision "B", type: "shell", inline:<<-SHELL
echo ‘B’
SHELL
end

config.vm.provision "C", type: "shell", inline:<<-SHELL
echo ‘C’
SHELL
end
“`

If provisioners truly ran in the order they are defined in a Vagrantfile, you would expect the output of running this Vagrantfile to print: A -> B -> C. Due to how Vagrant parses Vagrantfiles, however, the globally defined provisioners "A" and "C" actually run before "B". While this is just a basic example, dependency provisioners allow users to have finer grained control over exactly when they want a provisioner to run during the provision step. Here’s how to use a dependency provisioner:

“`ruby

A dependency provisioner that runs before "Configure"

config.vm.provision "Hello", before: "Configure", type: "shell", inline:<<-SHELL
echo 'The first provisioner!'
SHELL

A dependency provisioner that runs after the configure

config.vm.provision "Finished", after: "Configure", type: "shell", inline:<<-SHELL
echo 'Vagrant finished updating your system!’
SHELL

config.vm.provision "Configure", type: "shell", inline:<<-SHELL
apt-get update
apt-get install vim tmux tree -y
apt-get upgrade -y
SHELL
“`

If a provisioner has been configured using the before or after options, it is considered a Dependency Provisioner. This means it has been configured to run before or after a Root Provisioner, which does not have the before or after options configured. Root Provisioners can be thought of as a traditional Vagrant provisioner prior to the 2.2.6 release, and behave the way provisioners have prior to this release.

By giving the before or after options a string value "Name" that refers to a Root Provisioner, a dependency provisioner can be defined to run before or after that named provisioner. Not only will these keys allow users to modify the run order for their provisioners, they will also allow users to specify if a provisioner should run more than once. Instead of giving a "Name" string, users will also be able to provide an array of strings which contain the names of multiple provisioners. This allows the provisioner to be defined once, but run before or after each of the defined named provisioners. Dependency provisioners also have two valid shortcuts for the before and after keys: :each and :all:

“`ruby

This will run before any defined provisioner for a given Vagrant guest

config.vm.provision "Hello", before: :all, type: "shell", inline:<<-SHELL
echo 'The first provisioner!'
SHELL

This will run after every defined provisioner for a given Vagrant guest

config.vm.provision "Next", after: :each, type: "shell", inline:<<-SHELL
echo ‘The provisioner finished!'
SHELL
“`

Now that we’ve introduced Dependency Provisioners, let’s fix our original example and have the provisioners run in A -> B -> C order:

“`ruby
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/bionic64"

config.vm.provision "A", type: "shell", inline:<<-SHELL
echo ‘A’
SHELL

config.vm.define "guest" do |guest|
guest.vm.provision "B", after, "A", type: "shell", inline:<<-SHELL
echo ‘B’
SHELL
end

config.vm.provision "C", type: "shell", inline:<<-SHELL
echo ‘C’
SHELL
end
“`

Because this feature is experimental, you will need to enable it using the VAGRANT_EXPERIMENTAL environment variable. For example, on Linux or macOS you would run:


VAGRANT_EXPERIMENTAL="dependency_provisioners" vagrant up guest

If you are on Windows using Powershell, you would enable this feature by exporting the same environment variable:


$env:VAGRANT_EXPERIMENTAL = "dependency_provisioners"
vagrant up guest

Running this will now make our Vagrantfile provisioners run in A -> B -> C order. It should be noted that without the experimental flag, provisioner "B" would run like a normal provisioner from our first example.

For more information on how to use Dependency Provisioners, please check out the documentation on Vagrant Up.

Limitations

Dependency provisioners introduce two new top-level keys for the provisioner class: before and after. Because of how the class was designed, it means that when older Vagrant clients try to parse a Vagrantfile with dependency triggers defined, it will fail to parse the dependency provisioners properly and result in a stack trace to the user.

Additionally, as of Vagrant 2.2.6, dependency provisioners cannot rely on other dependency provisioners and is considered a configuration state error in Vagrant. If you must
order dependency provisioners, you can still order them by the order they are defined inside your Vagrantfile.

Vagrant Box Checksum Validation

With this release, we have added support for Vagrant box checksums to Vagrant Cloud. When the checksum value is set, Vagrant will automatically validate that the downloaded box matches the checksum before unpacking. Vagrant versions prior to 2.2.6 will only validate MD5 and SHA1 checksums. Support for SHA256, SHA384, and SHA512 were added in the 2.2.6 release.

Checksum information can be added to boxes directly on the Vagrant Cloud website. Alternatively, they can be added using the Vagrant Cloud API, or by using the vagrant cloud commands when creating or updating boxes.

Conclusion

For more information about Vagrant, go to the website at vagrantup.com and read the documentation.

from Hashicorp Blog: https://www.hashicorp.com/blog/whats-new-hashicorp-vagrant-2-2-6