No need to present Vagrant if you read this post. Hostmanager is a plugin which manages /etc/hosts on the host and the guests, to have common fqdns and simplify connections to your box. You can for instance set up host manager to make sure that you web development virtual is always accessible at web.local, or make sure that all machines in your virtual cluster can talk to each other with names like dev1.example.com, dev2.example.com and so on, no matter what DHCP decided what the IP address should be.
This is all and well, but there are a few issues. For instance, with virtualbox and dhcp, hostmanager only finds out 127.0.0.1 as IP for your virtuals, which is not handy to say the least.
If you use aws, you would like the guests to use the private IP, while having the host using the public IP, which is not possible by default.
Luckily, you can write your own IP resolver. The one I give here, which can as well be found on github, solves the following issues:
- Only for Linux guests (probably other unices as well to be honest, but I cannot guarantee that hostname -I works on all flavours)
- dhcp and virtualbox
- public/private IP with aws
$cached_addresses = {} # There is a bug when using virtualbox/dhcp which makes hostmanager not find # the proper IP, only the loop one: https://github.com/smdahlen/vagrant-hostmanager/issues/86 # The following custom resolver (for linux guests) is a good workaround. # Furthermore it handles aws private/public IP. # A limitation (feature?) is that hostmanager only looks at the current provider. # This means that if you `up` an aws vm, then a virtualbox vm, all aws ips # will disappear from your host /etc/hosts. # To prevent this, apply this patch to your hostmanager plugin (1.6.1), probably # at $HOME/.vagramt.d/gems/gems or (hopefully) wait for newer versions. # https://github.com/smdahlen/vagrant-hostmanager/pull/169 $ip_resolver = proc do |vm, resolving_vm| # For aws, we should use private IP on the guests, public IP on the host if vm.provider_name == :aws if resolving_vm.nil? used_name = vm.name.to_s + '--host' else used_name = vm.name.to_s + '--guest' end else used_name= vm.name.to_s end if $cached_addresses[used_name].nil? if hostname = (vm.ssh_info && vm.ssh_info[:host]) # getting aws guest ip *for the host*, we want the public IP in that case. if vm.provider_name == :aws and resolving_vm.nil? vm.communicate.execute('curl http://169.254.169.254/latest/meta-data/public-ipv4') do |type, pubip| $cached_addresses[used_name] = pubip end else vm.communicate.execute('uname -o') do |type, uname| unless uname.downcase.include?('linux') warn("Guest for #{vm.name} (#{vm.provider_name}) is not Linux, hostmanager might not find an IP.") end end vm.communicate.execute('hostname --all-ip-addresses') do |type, hostname_i| # much easier (but less fun) to work in ruby than sed'ing or perl'ing from shell allips = hostname_i.strip().split(' ') if vm.provider_name == :virtualbox # 10.0.2.15 is the default virtualbox IP in NAT mode. allips = allips.select { |x| x != '10.0.2.15'} end if allips.size() == 0 warn("Trying to find out ip for #{vm.name} (#{vm.provider_name}), found none useable: #{allips}.") else if allips.size() > 1 warn("Trying to find out ip for #{vm.name} (#{vm.provider_name}), found too many: #{allips} and I cannot choose cleverly. Will select the first one.") end $cached_addresses[used_name] = allips[0] end end end end end $cached_addresses[used_name] end
Just put this code in your vagrantfile, outside the Vagrant.configure block, and you can use it by allocating it that way:
config.hostmanager.ip_resolver = $ip_resolver
On a side note, and as explained in the comment, there is a limitation (feature?) in that hostmanager only looks at the current provider. This means that if you up an aws vm, then a virtualbox vm, all aws ips will disappear from your host /etc/hosts.
To prevent this, apply this patch to your hostmanager plugin (1.6.1), probably
at $HOME/.vagramt.d/gems/gems or (hopefully) wait for newer versions.
The patch itself is ridiculously tiny:
diff --git a/lib/vagrant-hostmanager/hosts_file/updater.rb b/lib/vagrant-hostmanager/hosts_file/updater.rb index 9514508..ef469bf 100644 --- a/lib/vagrant-hostmanager/hosts_file/updater.rb +++ b/lib/vagrant-hostmanager/hosts_file/updater.rb @@ -82,8 +82,8 @@ module VagrantPlugins def update_content(file_content, resolving_machine, include_id) id = include_id ? " id: #{read_or_create_id}" : "" - header = "## vagrant-hostmanager-start#{id}\n" - footer = "## vagrant-hostmanager-end\n" + header = "## vagrant-hostmanager-start-#{@provider}#{id}\n" + footer = "## vagrant-hostmanager-end-#{@provider}\n" body = get_machines .map { |machine| get_hosts_file_entry(machine, resolving_machine) } .join
Hi,
Thanks for this. I finally have my box running correctly on my network and the hosts file well managed.