This introduces the new network configuration syntax for Vagrant 1.1
and forward.
== The Problem
With multiple providers, the concept of networking as it stands in Vagrant
1.0.x becomes really muddy. We have `config.vm.forward_port` and
`config.vm.network :hostonly` and `config.vm.network :bridged`. But what
if someone writes an AWS provider? What is a bridged network in AWS? It
just doesn't make sense.
Networking working out of the box with Vagrant is a core part of what
makes Vagrant "magic" to new users. It is a core part of what makes Vagrant
simple to use. One option to punt networking to provider-specific
configuration was considered, but I found the whole idea of networking
too core to Vagrant to simply punt.
Because of this, a whole new method of networking is introduced.
== The Solution
The solution is to have a high-level notion of networking for Vagrant
configuration. This should cover the most _common_ cases of networking, and
every provider should do their best to implement these high-level
abstractions, to ensure the "just works" nature of Vagrant.
In addition to this high-level networking, low-level networking options
should be exposed on the provider configuration. This allows users to do
advanced provider-specific networking configuration if they want, but aren't
required to.
== High-Level Abstractions
=== Available Types
The high-level abstractions built into Vagrant will be the following:
* Forwarded ports - A mapping of host port to guest port that one can hit
using `localhost`.
* Private network - A private network, the machine should ideally be
protected from public access.
* Public network - A public network, one that is easily accessible by
others.
I'm not sure if these are the proper abstractions. They can change up
until 2.0, but these are what we have so far.
Theoretically, here is how mappings would work. Note that this is just
an example, and the mappings in practice of such providers may or
may not map to this as follows.
**VirtualBox**
* Forwarded ports - NAT network, forwared ports.
* Private network - Hostonly network, static IP assigned.
* Public network - Bridged network, IP assigned via DHCP from router.
**VMWare**
* Forwarded ports - NAT network, forwarded ports.
* Private network - Hostonly network, static IP assigned.
* Public network - Bridged network, IP assigned via DHCP from router.
**AWS**
* Forwarded ports - Unimplemented.
* Private network - Public DNS in EC2, private IP in VPC.
* Public network - Elastic IP in EC2 and VPC.
=== Syntax
Networks are configured at the top-level of a Vagrantfile:
```ruby
Vagrant.configure("2") do |config|
# ...
config.vm.network :forwarded_port, 80, 8080
config.vm.network :private_network, "192.168.1.12"
config.vm.network :public_network
end
```
Providers should do their best to honor these configurations.
=== Advanced Options
While providers should do their best to satisfy the requirements for the
high-level abstractions, it is expected that provider-specific configuration
may be possible per network, even for the high-level configurations. For
this, provider-prefixed configuration options should be done:
```ruby
config.vm.network :forwarded_port, 80, 8000,
:vmware__device => "vmnet8"
config.vm.network :public_network,
:aws__elastic_ip => "1.2.3.4",
:vmware__device => "en0"
```
If at all possible, providers should **not** require advanced options for
these to function.
== Low-level Configuration
While the high-level configuration should satisfy the common case and make
Vagrant work out of the box for most providers, one of the large benefits of
many providers is the ability to do certain networking tricks. For example,
KVM, Hyper-V, vSphere, etc. can create and be a part of true VLANs, which
may be required for certain upstream networking rules/ACLs. For things like
this, the network configuration should go directly into the provider
configuration in some way.
Examples:
```ruby
config.vm.provider :virtualbox do |vb|
vb.network_adapter 2, :hostonly
vb.network_adapter 3, :nat
end
config.vm.provider :aws do |aws|
aws.routing_table = "route-123456"
end
```
It is up to the provider implementation to define the configuration
syntax as well as the implementation details of such an option. Other
providers are unable to see provider configurations other than their own
so it is truly private to the provider.
This branch brings in a whole lot of awesome. The name does not do it
justice. The list of things that comes into play here:
* "virtualbox" is no longer hardcoded anywhere in core. It is the default
provider, yes, but it is 100% possible now to slip in another provider
and have it work.
* `vagrant up --provider` is a thing. This allows you to specify an
alternate provider. Note that the other commands don't support
`--provider` yet so its not THAT useful, but its getting really close.
* True V2 configuration is in place. That means that `Vagrant.configure`
calls now are loading a completely new configuration version, and old
1.0.x Vagrantfiles are V1 configuration. V1 configuration is upgraded
automatically internally, so backwards compatibility is maintained.
Magic, people, magic.
* `config.vm.provider` is the major new configuration option. This is
how provider-specific configuration will be done. For example, Vagrant
has always provided a way to make a pass of `VBoxManage` calls to
customize your VM via `config.vm.customize` in V1. This now exists
as a VirtualBox configuration option. See the example here:
https://gist.github.com/98f5a0df6a05286dfb73
* Unit tests no longer depend on VirtualBox being installed, because for
unit tests we slip in a "no-op" provider, which is a fully valid
Vagrant provider plug-in that does... NOTHING! Brilliant!
* Lots of core middleware executor improvements that make writing and
using middleware stacks a lot more enjoyable. Enjoy a set of "standard
library middlewares" provided by Vagrant in Vagrant::Action::Builtin.
The multi-provider is really shaping up here.
This works by registering a `config` with `:provider => true` with the
same name as your provider. Vagrant will then automatically configure
the provider when `config.vm.provider` is used.
This will eventually replace the Environment#vms method. Because of the
introduction of providers, the environment doesn't know what the backing
of the machines will be (and they're _machines_ now, not _vms_).
Instead, users of Environment will now call `#machine` on the
environment to retrieve a machine with the given backing provider as it
needs it.
The sudo() block and/or the Puppet provisioner often returns newline
characters as separate strings. This makes the chomp() ineffective and
results in extraneous spacing between the output lines.
Separate out the call to chomp() so that we only do it once. Then only
output info if that line is not an empty string.
Previously, failures in applying the puppet manifests would be
ignored, because puppet apply/agent don't have any useful exit codes
by default. (Errors are printed, but vagrant continues.)
Use the option --detailed-exitcodes of puppet apply/agent to check for
success.
This branch brings in the "machine abstraction" code. This is a major
milestone in the development of Vagrant as it abstracts all of the
VirtualBox-specific code out into a plugin. There is zero VirtualBox
specific code in the core ("lib/") directory at this point. Read on for
important points.
== Gotchas
White it is technically possible now to write plugins for other
providers, there is still major work to be done to make this feasible.
The plugin interface itself is pretty much done, but there are some
issues:
* ":virtualbox" is the hardcoded provider to be used at the moment.
* There is no way to configure a provider. For example,
`config.vm.customize` would never work for anything other than
VirtualBox, so there needs to be a way to have provider-specific
configuration. This will come soon.
* Shared folders and networking need to be rearchitected to be friendly
for multiple providers, since it is unrealistic that a provider such as
EC2 could provide the same level of networking, for example.
* There is no way easy way (like `vagrant package --base`) to create
boxes for providers other than VirtualBox. This will be addressed in a
whole new feature of Vagrant probably in a future release after
provider stuff has shipped.
== Writing a Provider
To write a provider, you create a Vagrant plugin that defines a
"provider". See the "plugins/providers/virtualbox/plugin.rb" for more
details. Providers themselves have an exremely simple API. The burden
for writing providers mostly rests on the fact that you must define
complex middleware sequences.
Lots more work to come in the future, but this is a BIG MILESTONE!
`vagrant package --base` is deprecated for a future feature so I didn't
want to waste any brain cycles on how to do this the "right" way since a
new system will be introduced to do this sort of thing in teh future.
The built-in middleware sequences will now be hardcoded onto
Vagrant::Action. Other plugins can hook into these sequences to provide
verification and so on. So the VirtualBox plugin will hook into that
action sequence and add verification.
This required some modifications to the linux guest implementation. And
the other guests will have to be modified as well. This is because
`channel` is now `communicate`.
This works by now calling the `:ssh` action on the provider. This action
is allowed to do whatever it pleases, but should at some point probably
call the `SSHExec` built-in middleware.
The `SSHExec` built-in middleware was added. This uses the information
returned by `Machine#ssh_info` and uses the `Vagrant::Util::SSH` helper
to exec into the remote machine. The provider should do any work upfront
in verifying that the machine is ready to be SSHed into.