hashicorp / vagrant

Vagrant is a tool for building and distributing development environments.
https://www.vagrantup.com
Other
26.05k stars 4.42k forks source link

Feature Request: Generic Guest Agent / Override Nameservers via Vagrantfile #10701

Open ladar opened 5 years ago

ladar commented 5 years ago

I've had a handful people struggle to configure and use the robox images. Lack of support for configuring Alpine has certainly come up. But more recently, a long discussion over what to use for default DNS server values.

In my view, the ideal solution is for vagrant to handle overriding settings like the DNS resolvers, enable/disable IPv6 support, etc, via a format similar to what's provided by config.vm.network .

To that end, configuring options like resolvers, etc, for every OS, and in some cases, every configuration possible within a given OS, is impossible. So I'd like to propose support for a generic guest agent. Namely, boxes could embed distro specific scripts within a base box that vagrant could then use to configure a given option, without having to know how that configuration is done.

To elaborate, if the generic config script was called shelter, vagrant could set a hostname by issuing the command shelter hostname awesomeness.localdomain ... or to overide/setup nameservers, it could use something like shelter dns 4.2.2.1 4.2.2.2 etc. Base boxes could indicate support for the shelter, and the path to the script via the embedded Vagrantfile.

See this issue for a longer discussion.

chrisroberts commented 5 years ago

I can see the value in being able to configure the nameservers via the Vagrantfile but relying on a script within the guest to do the actual provision doesn't seem to be the correct solution here. There are multiple reasons for this, but the main one being: if the script fails for some reason, users will assume Vagrant has failed. This makes debugging much more difficult, not only for users, but for maintainers as well.

I think the better approach here would be to instead treat nameserver configuration on the guest like any other guest capability. This will require adding capabilities for supported guests within Vagrant, and with that it will be easy to warn users when nameserver configuration may not be available for their guest of choice.

Triggers can definitely be used as a stopgap currently to allow nameserver configuration, but I do agree that Vagrant having the ability to handle it would be nice.

ladar commented 5 years ago

@chrisroberts I concur that native guest plugins are ideal, but vagrant will inevitably encounter operating systems it doesn't know how to interface with. What I'm suggesting is that in this case, vagrant can "fall back" to using set of "predefined" commands or interface for the various things that can be set via the Vagrantfile like hostname, network interface options, etc.

Then as a base box builder all I need to do is ensure the box can handle those predefined operations properly. Presumably it could be implemented via a shell script, but depending on the interface a variety of options are possible.

I understand your concerns regarding debugging. Perhaps as a method for limiting the number of issues, vagrant should require the Vagrantfile to explicitly stipulate the use of the generic guest agent interface. In this fashion, I could again, when building base boxes, embed such a directive in the bundled Vagrantfile for boxes which have implemented/require this interface.

ladar commented 5 years ago

It's easy to overlook the positive side, but this feature request, if implemented, would fix issues like https://github.com/hashicorp/vagrant/issues/10584 ... and ... https://github.com/lavabit/robox/issues/11 ... and .. https://github.com/lavabit/robox/issues/35 ... along with numerous others.

chrisroberts commented 5 years ago

I can definitely appreciate the positive value of the proposal. However, I can also see where it can introduce unexpected behavior or issues. If something like this was flagged to be used when a guest was set to be :generic (or really, it would probably need to be something like :generic_posix, :generic_windows, etc) you would end up in an either/or situation. Either you are only using some generic script interface on the guest, or you are using the proper guest capabilities. So, for something like #10584 having this ability may allow "fixing" setting the hostname, but you would then need to also provide all the other alpine guest capability functionality since you can't change your guest identification mid way through.

For the last two, Vagrant currently doesn't have any sense of setting up DNS so just adding that guest capability implementation would resolve those things. And as a stopgap until the feature is available, triggers should be able to provide the desired functionality, just not quite as cleanly.

I'm still :+1: on the DNS configuration.

ladar commented 5 years ago

you would then need to also provide all the other alpine guest capability functionality since you can't change your guest identification mid way through.

I concur. If using the generic interface, it would need to be used for every capability. Which means any predefined interface/standard would need to provide a standardized mechanism that could be used to indicate a lack of support for the specific functionality. And/or, perhaps support for a given function could be indicated via the Vagrantfile as well, ala config.vm.guest.capability.hostname = false or, config.vm.guest.capability.nameservers = false to indicate the guest doesn't support the given operation.

This would allow vagrant to handle the lack of support for a requested operation "gracefully" and presumably print a more meaningful error message.

As for fixing some things, while breaking others, I'd say that would be up to the implementer, but that the generic interface would and should be used as a means of last resort. For distros which a) lack a guest plugin and are b) sufficiently exotic that waiting on vagrant to start bundling the guest plugin doesn't make sense. Operating systems like DragonflyBSD, ReactOS, or SmartOS.

At the very least, the ability to indicate a lack of support for some function, like setting the hostname, via the Vagrantfile, could allow vagrant to print a more useful error message (which, hopefully, would reduce the number of bug reports associated with the issue). Just a thought.

As for:

when a guest was set to be :generic (or really, it would probably need to be something like :generic_posix, :generic_windows, etc)

That makes perfect sense. Although I wonder if the Windows option is necessary since it would never (or at least rarely) make sense to use the generic option for Windows, in lieu of the operating system specific guest agent.

Another option would be the ability to specify the path to the required interface. For example if /usr/local/bin/vagrant-guest was the default path, a Windows variant would simply need to specific C:\Windows\vagrant-guest.exe (or some other more appropriate path).

jerrac commented 4 years ago

I just ran into the hard coded dns issue (https://github.com/lavabit/robox/issues/11) today. I have an internal apt mirror that the generic/xenial and generic/bionic boxes were unable to find until I manually updated their dns settings.

I actually spent a good amount of time looking for a way to configure dns via the Vagrantfile. It seemed like something that should be supported.

So, I would like to see some form of dns management added to the Vagrantfile. @ladar 's suggestion seems like a good way to go.

I also found https://github.com/BerlinVagrant/vagrant-dns. I haven't tried it yet, but from the readme, it looks like it runs a dns server specific to the Vagrant vms. Would that method work as something built into vagrant? So boxes would just always hard code the dns to the built in dns server?

ladar commented 4 years ago

@jerrac sounds like there are two issues here. The vagrant-dns plugin, like this guide @abbbi created, deal with the reverse dns issue. Specifically, they make sure a dynamically set hostname will resolve back to a dynamically assigned network address.

The other, and probably more pressing issue, is a generic method for dictating the nameservers used by a guest using a common syntax inside the Vagrantfile. In theory such a scheme could support static (after which you manually dictate the IPs), or dhcp which configures the guest to use the nameservers provided via DHCP, or dnsmasq which forces the guest to use a dnsmasq proxy. Sounds simple, but like most things, there are lots of details.

Such a plugin would need to abstract away how the resolvers are configured for the various guests/operating systems. In the old days it was easy. Overwrite the /etc/resolv.conf and your good. But that doesn't have the desired effect on many distros, and will likely get overwritten on reboot. What's needed is a vagrant plugin, which like other vagrant config plugins (hostname/network), can detect the system type (and/or resolver type), and make the appropriate changes. I say resolver type, because some distros, unfortunately, support multiple resolvers. Specifically resolvconf vs systemd-resolved.

There are also various methods/best practices for ensuring the values persist. On RHEL/CentOS/Fedora systems you'd configure the values via /etc/sysconfig/network-scripts/ifcfg-eth0 (unless NetworkManager is in play), while Debian/Ubuntu systems using resolvconf rely on the /etc/network/interfaces file. For newer variants, using Netplan, you'd have to modify the /etc/netplan/01-netcfg.yaml file. Alpine, Windows, MacOS and BSD have different methods as well.

I've thought about creating Vagrantfile examples which show how to override the nameserver defaults for the various distros, and then post them on the robox wiki page, but haven't found the time. If you feel so inclined I'd welcome a pull request.

You will find some examples buried inside closed robox issues,, if that helps.