This commit refactors the freebsd networking to:
1. Use predictable network naming
2. Properly handle DHCP vs static networks on up and reload [GH-5852]
3. Perform all networking configuration in a single command to prevent
partial configuration.
This updates the guest capabilities to run in as few communicator
commands as possible. Additionally, it fixes a number of issues around
hostname and idempotency.
This patch was tested against:
- puphpet/debian75-x64
- debian/jessie64
- debian/wheezy64
with custom networking, custom hostname, and rsync shared folders.
This commit does a few things:
1. Make the hostname update idempotent with `grep -w`
2. Add the given hostname to `/etc/hosts` as recommended by the docs
3. Add missing tests
This commit updates the procedure for configuring arch networks to occur
in a single command. Previously, each network was configured
independently. If, for some reason, one of the networks destroyed the
SSH connection, the box would be irrecoverable. This commit does not
alleviate that behavior, but attempts to mitigate it by running all
network-related configuration commands in a single communicator (SSH)
session.
The new procedure looks like this:
1. Upload a temp file to /tmp/vagrant-network-id... for each interface
on the guest.
2. Compile a commands array (of bash) to execute after all network
configurations have been uploaded.
3. Concatenate all the commands together in a single communicator
session.
This was tested against `terrywant/archlinux` using the following Vagrantfile:
```ruby
Vagrant.configure(2) do |config|
config.vm.box = "terrywang/archlinux"
config.vm.hostname = "banana-ramama.example.com"
config.vm.network "private_network", type: "dhcp"
config.vm.network "private_network", ip: "33.33.33.10"
config.vm.provision "file", source: "Vagrantfile", destination: "/tmp/vf"
config.vm.provision "shell", inline: "echo hi"
end
```
This commit updates the procedure for changing the hostname on arch
guests to occur in a single command. Previously, setting the hostname
and adding the value of the hostname to the /etc/hosts file was done in
two different uploads. This reduces the cycle to a single upload, making
provisioning a bit faster.
Additionally, this changes the behavior of the /etc/hosts file to:
1. Not remove localhost as an alias of 127.0.0.1
2. Prepend our custom hostname before localhost
The resulting /etc/hosts file will look something like:
127.0.0.1 my-host.example.com my-host
127.0.0.1 localhost.mydomain localhost
Tested against `terrywang/archlinux` using the following Vagrantfile:
```ruby
Vagrant.configure(2) do |config|
config.vm.box = "terrywang/archlinux"
config.vm.hostname = "banana-ramama.example.com"
config.vm.network "private_network", type: "dhcp"
config.vm.network "private_network", ip: "33.33.33.10"
config.vm.provision "file", source: "Vagrantfile", destination: "/tmp/vf"
config.vm.provision "shell", inline: "echo hi"
end
```
This fixes a fairly large tempfile leak. Vagrant uses a template
renderer to write network configuration files locally to disk. Then,
that temporarily file is uploaded to the remote host and moved into
place. Since Vagrant is such a short-lived process, GC never came along
and cleaned up those tempfiles, resulting in many temporary files being
created through regular Vagrant usage.
The Util::Tempfile class uses a block to ensure the temporary file is
deleted when the block finishes. This API required small tweaks to the
usage, but provides more safety to ensure the files are deleted.
Ubuntu versions prior to 16.04 always returned a successful exit status,
even if one tried to down an interface that does not exist. This
behavior changed in Ubuntu 16.04 to return an error. This commit
preserves the old behavior.
Fixes GH-7155
Refactor and repair regular expression attempting to match present interfaces.
The refactored regular expression will match on enp* ens* eth* variants.
Previously, configuring and enabling network interfaces failed with:
"The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!
/usr/sbin/biosdevname --policy=all_ethN -i bash: /usr/sbin/biosdevname:
No such file or directory
Stdout from the command:
bash: /usr/sbin/biosdevname: No such file or directory"
The previous attempt to fix this (ccc4162) doesn't work since it doesn't
properly parse the 'bash: /usr/sbin/biosdevname: No such file or
directory' error message.
This patch works around that problem and adds a comment explaining the
meaning of the return codes.
Currently `configure_networks` guest cap configures NICs following the device order and fails
when the device order is mixed. We should detect the appropriate NIC by its MAC address.
Windows offers no out-of-the-box rsync utility. By far, the most
commonly used external utilities for Windows rsync are built with the
GNU Cygwin libraries. The cost for this convenience is that rsync on
Windows has to be provided paths that begin “/cygdrive/c” rather than
“c:/“ like other Windows-API utilities. Compounding the situation,
rsync doesn’t create paths/to/sub/targets and so the vagrant plugin
code, when performing an rsync, is responsible for creating
intermediate directories in guest paths if there are any. Furthermore,
the mkdir utility in Windows is not another Cygwin utility like rsync
but the routine mkdir of Windows command.com. Therefore, while rsync
needs the /cygwin paths, mkdir uses the Windows paths. Later, the
chef_solo.rp provisioner running within the guest will expect to find
Windows-style paths in its solo.rb configuration file. Due to all this,
vagrant has to keep track of both the original, possibly dirty Windows
guest path and the cygwin-scrubbed guest path.
Configuring by :interface doesn't work very well because Vagrant has
no idea about what interfaces are present in the VM, for example if
the image has 'docker' installed but not biosdevname, then
interface_names[0] = "docker0" which is usually not what you want
mapped to the first network from the Vagrantfile.
So if the plugins (like vagrant-libvirt) or the Vagrantfile has
given us a network with a MAC address, use that to find the interface
name for the network. Otherwise use slot numbers as before.