Is it possible to run a script on a virtual machine after Vagrant finishes provisioning all of them? Is it possible to run a script on a virtual machine after Vagrant finishes provisioning all of them? ruby ruby

Is it possible to run a script on a virtual machine after Vagrant finishes provisioning all of them?


The question is one year old, anyway I found it because I had the same problem, so here it is the workarround I used to solve the problem, somebody might find it usefull.

We need "vagrant triggers" for this to work. The thing with vagrant triggers is that they fire for every machine you are creating, but we want to determine the moment ALL machines are UP. We can do that by checking on each UP event if that event corresponds to the last machine being created:

Vagrant.configure("2") do |config|  (1..$machine_count).each do |i|   config.vm.define vm_name = "w%d" % i do |worker|   worker.vm.hostname = vm_name   workerIP = IP   worker.vm.network :private_network, ip: workerIP   worker.trigger.after :up do     if(i == $machine_count) then       info "last machine is up"       run_remote  "bash /vagrant/YOUR_SCRIPT.sh"     end      end  end endend

This works for providers that not support parallel execution on Vagrant (VBox, VMWare).


There is no hook in Vagrant for "run after all VMs are provisioned", so you would need to implement it yourself. A couple options I can think of:

1: Run the SSH setup script after all VMs are running.

For example if the script was named ssh_setup.sh and present in the shared folder:

$ for i in {1..4}; do vagrant ssh node$i -c 'sudo /vagrant/ssh_setup.sh'; done

2: Use the same SSH keys for all hosts and set up during provisioning

If all nodes share the same passphrase-less SSH key, you could copy into ~.ssh the needed files like authorized_keys, id_rsa, etc.


Adding an updated answer.

The vagrant-triggers plugin was merged to Vagrant 2.1.0 in may 2018.

We can simply use the only_on option option from the trigger class.

Let's say we have the following configuration:

servers=[  {:hostname => "net1",:ip => "192.168.11.11"},  {:hostname => "net2",:ip => "192.168.22.11"},  {:hostname => "net3",:ip => "192.168.33.11"}]

We can now easily execute the trigger after the last machine is up:

# Take the hostname of the last machine in the arraylast_vm = servers[(servers.length) -1][:hostname]Vagrant.configure(2) do |config|    servers.each do |machine|        config.vm.define machine[:hostname] do |node|            # ----- Common configuration ----- #            node.vm.box = "debian/jessie64"            node.vm.hostname = machine[:hostname]            node.vm.network "private_network", ip: machine[:ip]            # ----- Adding trigger - only after last VM is UP ------ #            node.trigger.after :up do |trigger|                trigger.only_on = last_vm  # <---- Just use it here!                trigger.info = "Running only after last machine is up!"            end        end    endend

And we can check the output and see the the trigger really fires only after "net3" is UP:

==> net3: Setting hostname...==> net3: Configuring and enabling network interfaces...==> net3: Installing rsync to the VM...==> net3: Rsyncing folder: /home/rotem/workspaces/playground/vagrant/learning-network-modes/testing/ => /vagrant==> net3: Running action triggers after up ...==> net3: Running trigger...==> net3: Running only after last machine is up!