Detecting if a virtualbox machine already exists in Vagrant
Posted by: Mark Bools on 2019-02-13 You want to change a VM’s settings depending upon whether the VM is being built or simply being rebooted (for my specific situation, see below). For example, during the initial provisioning run of the VM you might want to use the host DNS but on subsequent reboots you want to rely on a guest DNS. Simply using the following lines ensures that You cannot use a provisioner to vary VM settings (provisioners run on the machine). The solution offered works by probing the VM file system. A bit of investigation revealed that a machine that exists has files in the directory under Line 1 provides the Line 5 sets up to look for the Line 6 checks if the file exists. The first time this Line 7 is replaced by whatever you want to do when the machine is simply being rebooted. Line 9 is replaced with whatever you want to do when the machine is about to be created. This problem presented itself while I was putting together a dev/test environment for the In my setup I created a nameserver on one of the VMs and I needed to ensure no interference. To do this I wanted to ensure all the For the curious, here is the block I added to the On the initial boot of the VM the standard One other tweak required on the VM was to ensure the Arguably we could change the way Problem
vagrant
runs when the guest machine does not exist, you want configuration A
.vagrant
runs when the guest machine exists (and, we will, assume has been provisioned), you want configuration B
.Solution
Probing
virtualbox
filesvagrant
modifies the virtualbox
to boot with different VM settings (or whatever other logic you need to vary).1
2
3
4
5
6
7
8
9
10
11
12
require 'pathname'
config.vm.define :mysrv do |mysrv|
mysrv.vm.provider "virtualbox" do |vb|
machine_id_file=Pathname.new(".vagrant/machines/mysrv/virtualbox/id")
if machine_id_file.exist?()
# INSERT YOUR REBOOT LOGIC HERE
else
# INSERT YOUR PROVISION LOGIC HERE
end
end
end
Discussion
.vagrant/machine/mysrv/virtualbox
(obviously, replacing mysrv
with the actual machine id).Pathname
class.virtualbox
id file for the machine we’re interested in.Vagrantfile
is processed the machine will not exist (and so nor will this file), once the machine exists the id
file will be present, so the additional modifyvm
lines (7-9) will be executed. If you subsequently destroy
the machine the id
file is removed along with the machine.Motivation
salt
management system on my home system. I needed to disable the virtualbox
DNS handling as set up by vagrant
. The default makes sense for the general use case. Most of the time having the machine NAT onto the host network and pass DNS queries via the host both makes sense.virtualbox
DNS facilities were turned off. But, I wanted to maintain this facility during the first provisioning boot (it simplifies installing the salt-minion
). Hence this solution.Vagrantfile
.1
2
3
4
5
6
7
8
9
require 'pathname'
# The following block is added inside the "virtualbox" provider block
machine_files=Pathname.new(".vagrant/machines/prsrv002/virtualbox/id" )
if machine_files.exist?()
vb.customize ["modifyvm", :id, "--natdnspassdomain1", "off"]
vb.customize ["modifyvm", :id, "--natdnsproxy1", "off"]
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "off"]
end
vagrant
configuration would be in place. My salt
system then modifies the machine’s configuration. This works until that machine is rebooted. Under normal circumstances a reboot would result in vagrant
/virtualbox
updating the VM to use the host DNS. To avoid this the code block above takes over and uses the vb.customize
to disable all virtualbox
natdns*
settings.dhclient
did not try to change the resolv.conf
settings that salt
would manage. To this end I added this to the Vagrantfile
1
2
3
4
5
6
7
8
9
10
11
# prime_lan_interface manually configures a static interface so salt can be used
# without vagrant constantly wanting to control the interface subsequently
prime_lan_interface = "cat<<EOF >>/etc/network/interfaces
iface eth1 inet static
address 192.168.1.254
netmask 255.255.255.0
EOF
ifup eth1"
# Then invoke this in as a provisioner on any machine needing the dhclient resolv.conf updates disabling
prsrv002.vm.provision "shell", inline: prime_lan_interface
Opinion
virtualbox
networks the virtual machine (for example, bridging rather than NAT) but I’m a firm believer in making the smallest changes necessary to achieve a result and it is possible that a more radical change than that shown could have unanticipated effects on the way vagrant
interacts with our machine.