Reputation: 5644
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?
Upvotes: 3
Views: 3525
Reputation: 3112
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
Upvotes: 1
Reputation: 5644
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"
Upvotes: 2