lib/vagrant-hosts/addresses.rb in vagrant-hosts-2.6.2 vs lib/vagrant-hosts/addresses.rb in vagrant-hosts-2.7.0
- old
+ new
@@ -1,19 +1,35 @@
+require 'resolv'
+require 'ipaddr'
+
module VagrantHosts::Addresses
+ # Cache for networking data
+ #
+ # @return [Hash{String => Hash{String => String}}]
+ # @private
+ #
+ # @since 2.7.0
+ CACHE ||= {}
+
private
def all_hosts(config)
all_hosts = []
all_hosts += local_hosts(@machine, config)
if config.autoconfigure
all_hosts += vagrant_hosts(@env)
end
- all_hosts += config.hosts
- all_hosts
+ unless config.imports.empty?
+ all_hosts += collect_imports(@machine, config)
+ end
+
+ all_hosts += resolve_host_entries(config.hosts, @machine)
+
+ all_hosts.uniq
end
# Builds an array containing hostname and aliases for a given machine.
def hostnames_for_machine(machine)
# Cast any Symbols to Strings
@@ -51,10 +67,168 @@
end
hosts
end
+ # Collect all hosts entries for a machine
+ #
+ # @param machine [Vagrant::Machine] A vagrant VM to perform collection upon.
+ # @param config [VagrantHosts::Config] A configuration object for the hosts
+ # provisioner.
+ #
+ # @return [Array<Array<IPAddr, Array<String>>>] A list of address, alias
+ # tuples.
+ #
+ # @since 2.7.0
+ def collect_imports(machine, config)
+ env = machine.env
+ imports = config.imports
+
+ # TODO: Use Set?
+ hosts = []
+
+ all_machines(env).each do |m|
+ next if m.name == machine.name
+
+ host_provisioners(m).each do |p|
+ imports.each do |k|
+ next unless p.config.exports.has_key?(k)
+ hosts.concat resolve_host_entries(p.config.exports[k], m)
+ end
+ end
+ end
+
+ hosts.uniq
+ end
+
+ # Generate a list of IP addresses and aliases for a vagrant machine
+ #
+ # This functionresolves a list of addresses and aliases, possibly including
+ # special keys, into a list of addresses and aliases.
+ #
+ # See {#resolve_addresses} and {#resolve_aliases} for special key handling.
+ #
+ # @param entries[Array<String, Array<String>>] A list of entries.
+ #
+ # @raise [IPAddr::InvalidAddressError] Raised when an invalid address is
+ # supplied.
+ # @raise [Resolv::ResolvError] When a hostname cannot be resolved to an IP.
+ #
+ # @return [Array<IPAddr, Array<String>>]
+ #
+ # @since 2.7.0
+ def resolve_host_entries(entries, machine)
+ entries.flat_map do |(address, aliases)|
+ names = resolve_aliases(aliases, machine)
+ resolve_addresses(address, machine).map {|ip| [resolve_ip(ip), names]}
+ end
+ end
+
+ # Generate a list of IP addresses for a vagrant machine
+ #
+ # This function resolves an address or special key into a list of
+ # IP addresses.
+ #
+ # Special keys currently supported:
+ #
+ # - `@vagrant_private_networks`: The IP addresses of each privte network
+ # attached to the machine.
+ #
+ # - `@vagrant_ssh`: The IP address used by Vagrant to communicate with the
+ # machine (also includes WinRM and other communicators).
+ #
+ # @param aliases [String] An IP address or special key.
+ # @param machine [Vagrant::Machine] The Vagrant machine to use when resolving
+ # addresses.
+ #
+ # @return [Array<String>] A list of addresses.
+ #
+ # @since 2.7.0
+ def resolve_addresses(address, machine)
+ # Some network addresses, such as ssh_info, can be expensive to
+ # look up from cloud environments such as AWS, vSphere and OpenStack.
+ # So, we cache these special keys.
+ if CACHE.key?(machine.name) && CACHE[machine.name].key?(address)
+ ips = CACHE[machine.name][address]
+ else
+ ips = case address
+ when '@vagrant_private_networks'
+ machine.config.vm.networks.map do |(net_type, opts)|
+ next unless net_type == :private_network
+ opts[:ip]
+ end.compact
+ when '@vagrant_ssh'
+ if (info = machine.ssh_info)
+ info[:host]
+ else
+ []
+ end
+ else
+ address
+ end
+
+ if address.start_with?('@')
+ CACHE[machine.name] ||= {}
+ CACHE[machine.name][address] = ips
+ end
+ end
+
+ Array(ips)
+ end
+
+ # Generate an list of IP addresses from a string
+ #
+ # This function resolves a string into an IP address.
+ # IP addresses.
+ #
+ # @param address [String] A string that might be an IP address or a hostname.
+ #
+ # @raise [IPAddr::InvalidAddressError] Raised when an invalid address is
+ # supplied.
+ # @raise [Resolv::ResolvError] When a hostname cannot be resolved to an IP.
+ #
+ # @return [IPAddr] An IP address.
+ #
+ # @since 2.7.0
+ def resolve_ip(address)
+ ip = begin
+ IPAddr.new(address)
+ rescue IPAddr::InvalidAddressError
+ # Wasn't an IP address. Resolve it. The AWS provider does this.
+ IPAddr.new(Resolv.getaddress(address))
+ end
+
+ ip
+ end
+
+ # Generate a list of hostnames for a vagrant machine
+ #
+ # This function resolves a list of hostnames or special keys into a list of
+ # hostnmaes.
+ #
+ # Special keys currently supported:
+ #
+ # - `@vagrant_hostnames`: See {#hostnames_for_machine}.
+ #
+ # @param aliases [Array<String>] A list of hostnames or special keys.
+ # @param machine [Vagrant::Machine] The Vagrant machine to use when resolving
+ # aliases.
+ #
+ # @return [Array<String>] A list of hostnames.
+ #
+ # @since 2.7.0
+ def resolve_aliases(aliases, machine)
+ aliases.flat_map do |a|
+ case a
+ when '@vagrant_hostnames'
+ hostnames_for_machine(machine)
+ else
+ a
+ end
+ end
+ end
+
# @return [Array<Vagrant::Machine>]
def all_machines(env)
env.active_machines.map do |vm_id|
begin
env.machine(*vm_id)
@@ -62,6 +236,17 @@
nil
end
end.compact
end
+ # NOTE: This method exists for compatibility with Vagrant 1.6 and earlier.
+ # Remove it once support for these versions is dropped.
+ def host_provisioners(machine)
+ machine.config.vm.provisioners.select do |p|
+ if Vagrant::VERSION < '1.7'
+ p.name.intern == :hosts
+ else
+ p.type.intern == :hosts
+ end
+ end
+ end
end