I am using Vagrant (v1.7.2) to provision Linux (Fedora 22) hosts, and the vagrant-hostmanager plugin (v1.6.1)
to write /etc/hosts so that hosts can access each other.
My Vagrantfile:
Vagrant.configure(2) do |config|
config.vm.box = "workshop"
config.hostmanager.enabled = true
config.hostmanager.include_offline = true
config.vm.define "server" do |server|
server.vm.network "private_network", ip: "192.168.33.10"
server.vm.hostname = "server.local"
end
config.vm.define "client" do |client|
client.vm.network "private_network", ip: "192.168.33.20"
client.vm.hostname = "client.local"
end
end
When I vagrant up, the server VM has the following /etc/hosts:
127.0.0.1 server.ipademo.local server
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
## vagrant-hostmanager-start
192.168.33.10 server.ipademo.local
192.168.33.20 client.ipademo.local
## vagrant-hostmanager-end
(For VM client, substitute s/server/client/ on the first line only.)
Because Vagrant >= 1.5.0 runs the vagrant-hostmanager plugin before provisioning, I also tried running hostmanager during provisions by changing the Vagrantfile to:
config.hostmanager.enabled = false
config.hostmanager.include_offline = true
config.vm.provision :hostmanager
This had the same outcome.
The 127.0.0.1 <fqdn> <shortname> line conflicts with the information added by vagrant-hostmanager. I need to suppress the association of the hostname to the loopback address, so that on every VM the hostname resolves to the private network address, as added by vagrant-hostmanager.
How can I accomplish this?
The cause of the problem is Vagrant's change host name capability for Fedora guests. In particular, in plugins/guests/fedora/cap/change_host_name.rb:
def update_etc_hosts
ip_address = '([0-9]{1,3}\.){3}[0-9]{1,3}'
search = "^(#{ip_address})\\s+#{Regexp.escape(current_hostname)}(\\s.*)?$"
replace = "\\1 #{fqdn} #{short_hostname}"
expression = ['s', search, replace, 'g'].join('@')
sudo("sed -ri '#{expression}' /etc/hosts")
end
The update_etc_hosts method replaces the original hostname (for Fedora, this is localhost.localdomain, bound to the loopback address 127.0.0.1) with the new hostname. It then updates /etc/hostname with the short hostname, although system calls still return the full hostname because it appears in /etc/hosts.
I provided additional provisioners (which run after the above described hackery takes place) to:
Query the long hostname (FQDN) and write it back to /etc/hostname. This is needed so hostname --fqdn actually returns the full hostname after we repair /etc/hosts in the next step.
Restore the loopback line in /etc/hosts so that the machine's hostname resolves to the private network address as set by vagrant-hostmanager.
The order is critical. Here's the Vagrantfile code:
# Vagrant's "change host name" sets the short host name.
# Before we undo the /etc/hosts silliness (see below) let's
# reset /etc/hostname to the *full* host name
#
config.vm.provision "shell",
inline: "hostname --fqdn > /etc/hostname && hostname -F /etc/hostname"
# Vagrant's "change host name" capability for Fedora
# maps hostname to loopback, conflicting with hostmanager.
# We must repair /etc/hosts
#
config.vm.provision "shell",
inline: "sed -ri 's/127\.0\.0\.1\s.*/127.0.0.1 localhost localhost.localdomain/' /etc/hosts"
Most linux distributions have the same issue caused by the change_host_name vagrant capability (redhat, debian, arch, etc) when the hostname is set via Vagrant.
The following line from change_host_name prepends the vm hostname and vm name as aliases to 127.0.0.1 when the hostname is set, which conflicts with vagrant-hostmanager's aliasing.
sed -i'' '1i 127.0.0.1\\t#{name}\\t#{basename}' /etc/hosts
Vagrant authors have said that this is intentional and that they aren't planning to fix it, because it works as-is, as long as you don't modify /etc/hosts (which vagrant-hostmanager does).
Interestingly, many tools (dig, host, nslookup) use the LAST specified alias, which works fine with the defualt Vagrant behavior. Unfortunately, other tools, namely ones using gethostbyname or /etc/nsswitch.conf, have different behavior.
Ping, for example, seems to use the first alias in /etc/hosts, while Curl (when compiled to use NSS) uses multiple aliases as fallback from top down.
Because of this, having an alias match multiple IPs is generally discouraged.
The following Vagrantfile workaround should be sufficient:
config.hostmanager.enabled = true
name = "name"
hostname = "hostname"
config.vm.define name do |machine|
machine.vm.hostname = hostname
machine.vm.provision :shell, inline: "sed -i'' '/^127.0.0.1\\t#{hostname}\\t#{name}$/d' /etc/hosts"
...
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With